How Cylinders are Projected

[ ]:
from __future__ import annotations
# For the purposes of this tutorial, we will turn off logging
import logging
logger = logging.getLogger()
logger.setLevel(logging.CRITICAL)
import functools

import mpl_toolkits.mplot3d.art3d as art3d
# Getting rotation matrix
import numpy as np
from matplotlib.patches import Circle

The below is intended to help users visualize how canopyHydro transforms 3D cylinders (from QSM models) to 2D shapes.

[ ]:
# The functions in this block are used to define a 3D cylinder in space
def rotate_z_to_vector(b: np.array):
    if np.linalg.norm(b) == 0:
        return np.eye(3)
    if np.linalg.norm(b) != 1:
        raise ValueError("b must be a unit vector")
    # Algorithm from https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula#Matrix_notation
    # b must be unit vector
    # a is the z unit vector
    a = [0, 0, 1]
    v = np.cross(a, b)
    s = np.linalg.norm(v)
    c = np.dot(a, b)
    # The skew-symmetric cross product matrix of v
    vx = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]]) * -1
    # Rotation matrix as per Rodregues formula
    R = np.eye(3) + vx + np.dot(vx, vx) * ((1 - c) / (s**2))
    return R


@functools.lru_cache
def get_unoriented_cylinder(r, h, a=0, noCirPoints=200, nv=200):
    """
    Returns the parameterization of a cylinder given the radius (r), height (h), and origin (a)
    """
    theta = np.linspace(0, 2 * np.pi, noCirPoints)
    v = np.linspace(a, a + h, nv)
    theta, v = np.meshgrid(theta, v)
    x = r * np.cos(theta)
    y = r * np.sin(theta)
    z = v
    return x, y, z


def get_cylinder(r, h, a=0, noCirPoints=200, nv=200):
    """
    Returns the parameterization of a cylinder given the radius (r), height (h), and origin (a)
    """
    theta = np.linspace(0, 2 * np.pi, noCirPoints)
    v = np.linspace(a, a + h, nv)
    theta, v = np.meshgrid(theta, v)
    x = r * np.cos(theta)
    y = r * np.sin(theta)
    z = v
    #     rotation_matrix = np.array([[cos(a), -sin(a)], [sin(a), cos(a)]])
    # x   , y = zip(*[(x,y) @ rotation_matrix for x,y in zip(x,y)])

    return x, y, z
[6]:
# Here we use the above functions to draw a 3d Cylinder aligned with z axis
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")

Xc, Yc, Zc = get_cylinder(2, 4)
# end_cap = [Xc[0], Yc[0], Zc[0]]

ax.plot_surface(Xc, Yc, Zc, alpha=0.5)
plt.show()

import functools

import mpl_toolkits.mplot3d.art3d as art3d
../_images/examples_projecting_cylinders_4_0.png
[5]:
# Below we draw a 3D cylinder aligned with an arbitrary vector
#  as well as the 2D projections of the cylinder on the xy, xz, and yz planes
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.patches import Circle

v = np.array([3, 1, 7])

vu = v / np.linalg.norm(v)

Xc, Yc, Zc = get_cylinder(2, 4)

R = rotate_z_to_vector(vu)
t = np.transpose(np.array([Xc, Yc, Zc]))
x, y, z = np.transpose(t @ R, (2, 0, 1))

fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
zmin = -4

ax.plot_surface(x, y, z, alpha=0.7)

# Drawing the vector v
ax.quiver(0, 0, 0, 1.5, 0.5, 3.5, color="black")

# ax.contourf(x, y, z, zdir='z', offset=-1, cmap='Greys', alpha = .5) #'coolwarm')
ax.contourf(x, y, z, zdir="z", offset=zmin, colors="C0")

# Drawing a circle to fill in gap left by contourf
# represents the end cap of the cylinder
# hard coded for this example for simplicity
p = Circle((0.5, 0.15), 1.77)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=zmin, zdir="z")  # , color = 'Grey')


plt.contourf(x, y, z, zdir="x", offset=zmin, colors="C0", labels="YZ")
# yz_contour.collections[0].set_label('YZ')
ax.contourf(x, y, z, zdir="y", offset=6, colors="C0")


ax.view_init(elev=30, azim=-45, roll=0)
ax.set(xlim=(-4, 6), ylim=(-5, 6), zlim=(zmin, 6), xlabel="X", ylabel="Y", zlabel="Z")

print(dir(ax))
plt.show()
/tmp/ipykernel_10409/2362987715.py:39: UserWarning: The following kwargs were not used by contour: 'labels'
  plt.contourf(x, y, z, zdir="x", offset=zmin, colors="C0", labels="YZ")
['ArtistList', 'M', '_3d_extend_contour', '_AxesBase__clear', '_PROPERTIES_EXCLUDED_FROM_SET', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_add_contourf_set', '_add_text', '_adjustable', '_agg_filter', '_alias_map', '_alpha', '_anchor', '_animated', '_aspect', '_auto_scale_contourf', '_autotitlepos', '_axes', '_axes_locator', '_axis3don', '_axis_map', '_axis_names', '_axisbelow', '_box_aspect', '_button_press', '_button_release', '_calc_coord', '_calc_view_axes', '_callbacks', '_check_no_units', '_children', '_clipon', '_clippath', '_cm_set', '_colorbars', '_convert_dx', '_current_image', '_different_canvas', '_dist', '_draw_grid', '_equal_aspect_axis_indices', '_errorevery_to_mask', '_facecolor', '_fill_between_x_or_y', '_focal_length', '_forward_navigation_events', '_frameon', '_fully_clipped_to_axes', '_gci', '_gen_axes_patch', '_gen_axes_spines', '_get_aspect_ratio', '_get_camera_loc', '_get_lines', '_get_pan_points', '_get_patches_for_fill', '_get_view', '_get_w_centers_ranges', '_gid', '_gridOn', '_in_layout', '_init_axis', '_internal_update', '_label', '_label_outer_xaxis', '_label_outer_yaxis', '_left_title', '_location_coords', '_make_twin_axes', '_mouseover', '_mouseover_set', '_navigate', '_navigate_mode', '_on_move', '_originalPosition', '_pan_btn', '_parse_scatter_color_args', '_path_effects', '_pcolorargs', '_picker', '_position', '_prepare_view_from_bbox', '_process_unit_info', '_projection_init', '_pseudo_h', '_pseudo_w', '_quiver_units', '_rasterization_zorder', '_rasterized', '_remove_legend', '_remove_method', '_request_autoscale_view', '_right_title', '_roll_to_vertical', '_rotate_btn', '_rotation_coords', '_scale_axis_limits', '_sci', '_set_alpha_for_array', '_set_artist_props', '_set_bound3d', '_set_gc_clip', '_set_lim3d', '_set_lim_and_transforms', '_set_position', '_set_title_offset_trans', '_set_view', '_set_view_from_bbox', '_shared_axes', '_shareview', '_sharex', '_sharey', '_sharez', '_sketch', '_snap', '_stale', '_stale_viewlims', '_sticky_edges', '_subclass_uses_cla', '_subplotspec', '_tight', '_transform', '_transformSet', '_transformed_cube', '_twinned_axes', '_unit_change_handler', '_unstale_viewLim', '_update_image_limits', '_update_line_limits', '_update_patch_limits', '_update_props', '_update_set_signature_and_docstring', '_update_title_position', '_update_transScale', '_url', '_use_sticky_edges', '_validate_converted_limits', '_vertical_axis', '_viewLim', '_view_margin', '_visible', '_xaxis_transform', '_xmargin', '_yaxis_transform', '_ymargin', '_zmargin', '_zoom_btn', '_zoom_data_limits', 'acorr', 'add_artist', 'add_callback', 'add_child_axes', 'add_collection', 'add_collection3d', 'add_container', 'add_contour_set', 'add_contourf_set', 'add_image', 'add_line', 'add_patch', 'add_table', 'angle_spectrum', 'annotate', 'apply_aspect', 'arrow', 'artists', 'auto_scale_xyz', 'autoscale', 'autoscale_view', 'axes', 'axhline', 'axhspan', 'axis', 'axison', 'axline', 'axvline', 'axvspan', 'azim', 'bar', 'bar3d', 'bar_label', 'barbs', 'barh', 'bbox', 'boxplot', 'broken_barh', 'button_pressed', 'bxp', 'callbacks', 'can_pan', 'can_zoom', 'child_axes', 'cla', 'clabel', 'clear', 'clipbox', 'cohere', 'collections', 'computed_zorder', 'containers', 'contains', 'contains_point', 'contour', 'contour3D', 'contourf', 'contourf3D', 'convert_xunits', 'convert_yunits', 'convert_zunits', 'csd', 'dataLim', 'disable_mouse_rotation', 'drag_pan', 'draw', 'draw_artist', 'ecdf', 'elev', 'end_pan', 'errorbar', 'eventplot', 'figure', 'fill', 'fill_between', 'fill_betweenx', 'findobj', 'fmt_xdata', 'fmt_ydata', 'fmt_zdata', 'format_coord', 'format_cursor_data', 'format_xdata', 'format_ydata', 'format_zdata', 'get_adjustable', 'get_agg_filter', 'get_alpha', 'get_anchor', 'get_animated', 'get_aspect', 'get_autoscale_on', 'get_autoscalex_on', 'get_autoscaley_on', 'get_autoscalez_on', 'get_axes_locator', 'get_axis_position', 'get_axisbelow', 'get_box_aspect', 'get_children', 'get_clip_box', 'get_clip_on', 'get_clip_path', 'get_cursor_data', 'get_data_ratio', 'get_default_bbox_extra_artists', 'get_facecolor', 'get_fc', 'get_figure', 'get_forward_navigation_events', 'get_frame_on', 'get_gid', 'get_gridspec', 'get_images', 'get_in_layout', 'get_label', 'get_legend', 'get_legend_handles_labels', 'get_lines', 'get_mouseover', 'get_navigate', 'get_navigate_mode', 'get_path_effects', 'get_picker', 'get_position', 'get_proj', 'get_rasterization_zorder', 'get_rasterized', 'get_shared_x_axes', 'get_shared_y_axes', 'get_sketch_params', 'get_snap', 'get_subplotspec', 'get_tightbbox', 'get_title', 'get_transform', 'get_transformed_clip_path_and_affine', 'get_url', 'get_visible', 'get_w_lims', 'get_window_extent', 'get_xaxis', 'get_xaxis_text1_transform', 'get_xaxis_text2_transform', 'get_xaxis_transform', 'get_xbound', 'get_xgridlines', 'get_xlabel', 'get_xlim', 'get_xlim3d', 'get_xmajorticklabels', 'get_xmargin', 'get_xminorticklabels', 'get_xscale', 'get_xticklabels', 'get_xticklines', 'get_xticks', 'get_yaxis', 'get_yaxis_text1_transform', 'get_yaxis_text2_transform', 'get_yaxis_transform', 'get_ybound', 'get_ygridlines', 'get_ylabel', 'get_ylim', 'get_ylim3d', 'get_ymajorticklabels', 'get_ymargin', 'get_yminorticklabels', 'get_yscale', 'get_yticklabels', 'get_yticklines', 'get_yticks', 'get_zaxis', 'get_zbound', 'get_zgridlines', 'get_zlabel', 'get_zlim', 'get_zlim3d', 'get_zmajorticklabels', 'get_zmargin', 'get_zminorticklabels', 'get_zorder', 'get_zscale', 'get_zticklabels', 'get_zticklines', 'get_zticks', 'grid', 'has_data', 'have_units', 'hexbin', 'hist', 'hist2d', 'hlines', 'ignore_existing_data_limits', 'images', 'imshow', 'in_axes', 'indicate_inset', 'indicate_inset_zoom', 'initial_azim', 'initial_elev', 'initial_roll', 'inset_axes', 'invM', 'invert_xaxis', 'invert_yaxis', 'invert_zaxis', 'is_transform_set', 'label_outer', 'legend', 'legend_', 'lines', 'locator_params', 'loglog', 'magnitude_spectrum', 'margins', 'matshow', 'minorticks_off', 'minorticks_on', 'mouse_init', 'mouseover', 'name', 'patch', 'patches', 'pchanged', 'pcolor', 'pcolorfast', 'pcolormesh', 'phase_spectrum', 'pick', 'pickable', 'pie', 'plot', 'plot3D', 'plot_date', 'plot_surface', 'plot_trisurf', 'plot_wireframe', 'properties', 'psd', 'quiver', 'quiver3D', 'quiverkey', 'redraw_in_frame', 'relim', 'remove', 'remove_callback', 'reset_position', 'roll', 'scatter', 'scatter3D', 'secondary_xaxis', 'secondary_yaxis', 'semilogx', 'semilogy', 'set', 'set_adjustable', 'set_agg_filter', 'set_alpha', 'set_anchor', 'set_animated', 'set_aspect', 'set_autoscale_on', 'set_autoscalex_on', 'set_autoscaley_on', 'set_autoscalez_on', 'set_axes_locator', 'set_axis_off', 'set_axis_on', 'set_axisbelow', 'set_box_aspect', 'set_clip_box', 'set_clip_on', 'set_clip_path', 'set_facecolor', 'set_fc', 'set_figure', 'set_forward_navigation_events', 'set_frame_on', 'set_gid', 'set_in_layout', 'set_label', 'set_mouseover', 'set_navigate', 'set_navigate_mode', 'set_path_effects', 'set_picker', 'set_position', 'set_proj_type', 'set_prop_cycle', 'set_rasterization_zorder', 'set_rasterized', 'set_sketch_params', 'set_snap', 'set_subplotspec', 'set_title', 'set_top_view', 'set_transform', 'set_url', 'set_visible', 'set_xbound', 'set_xlabel', 'set_xlim', 'set_xlim3d', 'set_xmargin', 'set_xscale', 'set_xticklabels', 'set_xticks', 'set_ybound', 'set_ylabel', 'set_ylim', 'set_ylim3d', 'set_ymargin', 'set_yscale', 'set_yticklabels', 'set_yticks', 'set_zbound', 'set_zlabel', 'set_zlim', 'set_zlim3d', 'set_zmargin', 'set_zorder', 'set_zscale', 'set_zticklabels', 'set_zticks', 'shareview', 'sharex', 'sharey', 'sharez', 'specgram', 'spines', 'spy', 'stackplot', 'stairs', 'stale', 'stale_callback', 'start_pan', 'stem', 'stem3D', 'step', 'sticky_edges', 'streamplot', 'table', 'tables', 'text', 'text2D', 'text3D', 'texts', 'tick_params', 'ticklabel_format', 'title', 'titleOffsetTrans', 'transAxes', 'transData', 'transLimits', 'transScale', 'tricontour', 'tricontourf', 'tripcolor', 'triplot', 'twinx', 'twiny', 'update', 'update_datalim', 'update_from', 'use_sticky_edges', 'viewLim', 'view_init', 'violin', 'violinplot', 'vlines', 'voxels', 'xaxis', 'xaxis_date', 'xaxis_inverted', 'xcorr', 'xy_dataLim', 'xy_viewLim', 'yaxis', 'yaxis_date', 'yaxis_inverted', 'zaxis', 'zaxis_date', 'zaxis_inverted', 'zorder', 'zz_dataLim', 'zz_viewLim']
../_images/examples_projecting_cylinders_5_2.png