From c002fb038a67fe2c719c036814f8e15442a586ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Sun, 9 Nov 2025 15:27:00 +0100 Subject: [PATCH 1/3] Slight rewrite of docstrings, use more natural language in errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- orix/quaternion/misorientation.py | 30 ++++---- orix/quaternion/orientation.py | 31 ++++---- orix/quaternion/quaternion.py | 32 +++++--- .../tests/test_quaternion/test_orientation.py | 76 +++++++++---------- 4 files changed, 92 insertions(+), 77 deletions(-) diff --git a/orix/quaternion/misorientation.py b/orix/quaternion/misorientation.py index 3ac26a84..7222a347 100644 --- a/orix/quaternion/misorientation.py +++ b/orix/quaternion/misorientation.py @@ -277,8 +277,8 @@ def from_scipy_rotation( def from_path_ends( cls, points: Misorientation, closed: bool = False, steps: int = 100 ) -> Misorientation: - """Return misorientations tracing the shortest path between - two or more consecutive points. + """Return misorientations tracing the shortest path between two + or more consecutive points. Parameters ---------- @@ -286,31 +286,35 @@ def from_path_ends( Two or more misorientations that define points along the path. closed - Option to add a final trip from the last point back to - the first, thus closing the loop. The default is False. + Add a final trip from the last point back to the first, thus + closing the loop. Default is False. steps - Number of misorientations to return between each point - along the path defined by `points`. The default is 100. + Number of misorientations to return between each point along + the path given by *points*. Default is 100. Returns ------- path - regularly spaced misorientations following the shortest - path. + Regularly spaced misorientations along the path. + + + See Also + -------- + :class:`~orix.quaternion.Quaternion.from_path_ends`, + :class:`~orix.quaternion.Orientation.from_path_ends` Notes ----- This function traces the shortest path between points without - any regard to symmetry. Concept of "shortest path" is not + considering symmetry. The concept of "shortest path" is not well-defined for misorientations, which can define multiple symmetrically equivalent points with non-equivalent paths. """ - # Confirm `points` are misorientations. - if type(points) is not cls: + points_type = type(points) + if points_type is not cls: raise TypeError( - f"Points must be a Misorientation, not of type {type(points)}" + f"Points must be misorientations, not of type {points_type}" ) - # Create a path through Quaternion space, then reapply the symmetry. out = Rotation.from_path_ends(points=points, closed=closed, steps=steps) return cls(out.data, symmetry=points.symmetry) diff --git a/orix/quaternion/orientation.py b/orix/quaternion/orientation.py index a09a4a7a..d8537cb8 100644 --- a/orix/quaternion/orientation.py +++ b/orix/quaternion/orientation.py @@ -356,37 +356,40 @@ def from_scipy_rotation( def from_path_ends( cls, points: Orientation, closed: bool = False, steps: int = 100 ) -> Misorientation: - """Return orientations tracing the shortest path between two - or more consecutive points. + """Return orientations tracing the shortest path between two or + more consecutive points. Parameters ---------- points - Two or more orientations that define points along the - path. + Two or more orientations that define points along the path. closed - Option to add a final trip from the last point back to - the first, thus closing the loop. The default is False. + Add a final trip from the last point back to the first, thus + closing the loop. Default is False. steps - Number of orientations to return between each point - along the path defined by `points`. The default is 100. + Number of orientations to return between each point along + the path given by *points*. Default is 100. Returns ------- path - regularly spaced orientations following the shortest path. + Regularly spaced orientations along the path. + + See Also + -------- + :class:`~orix.quaternion.Quaternion.from_path_ends`, + :class:`~orix.quaternion.Misorientation.from_path_ends` Notes ----- This function traces the shortest path between points without - any regard to symmetry. Concept of "shortest path" is not + considering symmetry. The concept of "shortest path" is not well-defined for orientations, which can define multiple symmetrically equivalent points with non-equivalent paths. """ - if type(points) is not cls: - raise TypeError( - f"Points must be an Orientation instance, not of type {type(points)}" - ) + points_type = type(points) + if points_type is not cls: # Disallow misorientations + raise TypeError(f"Points must be orientations, not of type {points_type}") out = Rotation.from_path_ends(points=points, closed=closed, steps=steps) return cls(out.data, symmetry=points.symmetry) diff --git a/orix/quaternion/quaternion.py b/orix/quaternion/quaternion.py index de3a1d87..848f8a01 100644 --- a/orix/quaternion/quaternion.py +++ b/orix/quaternion/quaternion.py @@ -703,16 +703,21 @@ def from_path_ends( points Two or more quaternions that define points along the path. closed - Option to add a final trip from the last point back to - the first, thus closing the loop. The default is False. + Add a final trip from the last point back to the first, thus + closing the loop. Default is False. steps Number of quaternions to return between each point along - the path defined by `points`. The default is 100. + the path given by *points*. Default is 100. Returns ------- path - regularly spaced quaternions following the shortest path. + Regularly spaced quaternions along the path. + + See Also + -------- + :class:`~orix.quaternion.Orientation.from_path_ends`, + :class:`~orix.quaternion.Misorientation.from_path_ends` """ points = points.flatten() n = points.size @@ -721,16 +726,19 @@ def from_path_ends( path_list = [] for i in range(n): - # get start and end for this leg of the trip - q1 = points[i] - q2 = points[(i + 1) % (points.size)] - # find the ax/ang describing the trip between points - ax, ang = _conversions.qu2ax((~q1 * q2).data) - # get 'steps=n' steps along the trip and add them to the journey - trip = Quaternion.from_axes_angles(ax, np.linspace(0, ang, steps)) - path_list.append((q1 * (trip.flatten())).data) + # Get start and end for this part of the jorney + qu1 = points[i] + qu2 = points[(i + 1) % (points.size)] + # Get the axis-angle pair describing this part + ax, ang = _conversions.qu2ax((~qu1 * qu2).data) + # Get steps along the trip and add them to the journey + angles = np.linspace(0, ang, steps) + qu_trip = Quaternion.from_axes_angles(ax, angles) + path_list.append((qu1 * qu_trip.flatten()).data) + path_data = np.concatenate(path_list, axis=0) path = cls(path_data) + return path @classmethod diff --git a/orix/tests/test_quaternion/test_orientation.py b/orix/tests/test_quaternion/test_orientation.py index 15bf93a6..89b0d566 100644 --- a/orix/tests/test_quaternion/test_orientation.py +++ b/orix/tests/test_quaternion/test_orientation.py @@ -317,52 +317,52 @@ def test_from_path_ends(): In particular, ensure the class of the returned object matches the class used for creating it, NOT the class of the object passed in. """ - q = Quaternion.random(10) - r = Rotation.random(10) - o = Orientation.random(10, Oh) - m = Misorientation.random(10, [D3, Oh]) + qu = Quaternion.random(10) + rot = Rotation.random(10) + ori = Orientation.random(10, Oh) + mori = Misorientation.random(10, [D3, Oh]) # Quaternion sanity checks - a = Quaternion.from_path_ends(q) - assert isinstance(a, Quaternion) - b = Quaternion.from_path_ends(r) - assert isinstance(b, Quaternion) - c = Quaternion.from_path_ends(o) - assert isinstance(c, Quaternion) - d = Quaternion.from_path_ends(m) - assert isinstance(d, Quaternion) + qu_path1 = Quaternion.from_path_ends(qu) + assert isinstance(qu_path1, Quaternion) + qu_path2 = Quaternion.from_path_ends(rot) + assert isinstance(qu_path2, Quaternion) + qu_path3 = Quaternion.from_path_ends(ori) + assert isinstance(qu_path3, Quaternion) + qu_path4 = Quaternion.from_path_ends(mori) + assert isinstance(qu_path4, Quaternion) # Rotation sanity checks - a = Rotation.from_path_ends(q) - assert isinstance(a, Rotation) - b = Rotation.from_path_ends(r) - assert isinstance(b, Rotation) - c = Rotation.from_path_ends(o) - assert isinstance(c, Rotation) - d = Rotation.from_path_ends(m) - assert isinstance(d, Rotation) + rot_path1 = Rotation.from_path_ends(qu) + assert isinstance(rot_path1, Rotation) + rot_path2 = Rotation.from_path_ends(rot) + assert isinstance(rot_path2, Rotation) + rot_path3 = Rotation.from_path_ends(ori) + assert isinstance(rot_path3, Rotation) + rot_path4 = Rotation.from_path_ends(mori) + assert isinstance(rot_path4, Rotation) # Misorientation sanity checks - with pytest.raises(TypeError, match="Points must be a Misorientation"): - a = Misorientation.from_path_ends(q) - with pytest.raises(TypeError, match="Points must be a Misorientation"): - b = Misorientation.from_path_ends(r) - with pytest.raises(TypeError, match="Points must be a Misorientation"): - c = Misorientation.from_path_ends(o) - d = Misorientation.from_path_ends(m) - assert isinstance(d, Misorientation) - assert d.symmetry == m.symmetry + with pytest.raises(TypeError, match="Points must be misorientations, "): + Misorientation.from_path_ends(qu) + with pytest.raises(TypeError, match="Points must be misorientations, "): + Misorientation.from_path_ends(rot) + with pytest.raises(TypeError, match="Points must be misorientations, "): + Misorientation.from_path_ends(ori) + mori_path = Misorientation.from_path_ends(mori) + assert isinstance(mori_path, Misorientation) + assert mori_path.symmetry == mori.symmetry # Orientation sanity checks - with pytest.raises(TypeError, match="Points must be an Orientation"): - a = Orientation.from_path_ends(q) - with pytest.raises(TypeError, match="Points must be an Orientation"): - b = Orientation.from_path_ends(r) - c = Orientation.from_path_ends(o) - assert c.symmetry == o.symmetry - assert isinstance(c, Orientation) - with pytest.raises(TypeError, match="Points must be an Orientation"): - d = Orientation.from_path_ends(m) + with pytest.raises(TypeError, match="Points must be orientations, "): + Orientation.from_path_ends(qu) + with pytest.raises(TypeError, match="Points must be orientations, "): + Orientation.from_path_ends(rot) + ori_path = Orientation.from_path_ends(ori) + assert ori_path.symmetry == ori.symmetry + assert isinstance(ori_path, Orientation) + with pytest.raises(TypeError, match="Points must be orientations, "): + qu_path4 = Orientation.from_path_ends(mori) class TestMisorientation: From ab66ae140cb2562dd7bc3466162c133c499a56de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Sun, 9 Nov 2025 16:32:21 +0100 Subject: [PATCH 2/3] Slight formulation of changelog entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- CHANGELOG.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e0ceb0a9..397123e9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,8 +34,8 @@ Added An example of a custom projection is the :class:`~orix.plot.StereographicPlot`. This function replaces the previous behavior of relying on a side-effect of importing the :mod:`orix.plot` module, which also registered the projections. -- :func:`~orix.quaternion.Rotation.from_path_ends` returns evenly spaced points - mapping the shortest path betwen two or more rotations. +- Method ``from_path_ends()`` to return quaternions, rotations, orientations, or + misorientations along the shortest path between two or more points. Changed ------- From 5eb7bbb7af4e885c92a90813dafa19eb5efb48fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akon=20Wiik=20A=CC=8Anes?= Date: Sun, 9 Nov 2025 16:39:02 +0100 Subject: [PATCH 3/3] Rework path visualization example slightly, remove use of private method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Håkon Wiik Ånes --- .../visualizing_crystallographic_paths.py | 152 ----------------- .../visualizing_rotation_vector_paths.py | 154 ++++++++++++++++++ orix/quaternion/misorientation.py | 1 - 3 files changed, 154 insertions(+), 153 deletions(-) delete mode 100644 examples/plotting/visualizing_crystallographic_paths.py create mode 100644 examples/plotting/visualizing_rotation_vector_paths.py diff --git a/examples/plotting/visualizing_crystallographic_paths.py b/examples/plotting/visualizing_crystallographic_paths.py deleted file mode 100644 index 1e8e383e..00000000 --- a/examples/plotting/visualizing_crystallographic_paths.py +++ /dev/null @@ -1,152 +0,0 @@ -r""" -========================================= -Visualizing crystallographic paths -========================================= - -This example shows how define and plot paths through either -rotation or vector space.This is akin to describing crystallographic -fiber textures in metallurgy, or the shortest arcs connecting points on -the surface of a unit sphere. - -In both cases, "shortest" is defined as the route that minimizes the -movement required to transform from point to point, which is typically -not a stright line when plotted into a euclidean projection -(axis-angle, stereographic, etc.). - -This functionality is available in :class:`~orix.vector.Vector3d`, -:class:`~orix.quaternions.Rotation`, -:class:`~orix.quaternions.Orientation`, -and :class:`~orix.quaternions.Misorientation`.""" - -from matplotlib import cm -import matplotlib.pyplot as plt -import numpy as np - -from orix.plot import register_projections -from orix.plot.direction_color_keys import DirectionColorKeyTSL -from orix.quaternion import Orientation, OrientationRegion, Quaternion -from orix.quaternion.symmetry import C1, Oh -from orix.sampling import sample_S2 -from orix.vector import Vector3d - -plt.close("all") -register_projections() # Register our custom Matplotlib projections -np.random.seed(2319) # Create reproducible random data - - -fig = plt.figure(figsize=(6, 6)) -n_steps = 30 - -# ============ # -# Example 1: Plotting multiple paths into a user defined axis - -# This subplot shows several paths through the cubic (m3m) fundamental zone -# created by rotating 20 randomly chosen points 30 degrees around the z axis. -# these paths are drawn in rodrigues space, which is an equal-angle projection -# of rotation space. As such, notice how all lines tracing out axial rotations -# are straight, but lines starting closer to the center of the fundamental zone -# appear shorter. - -# the sampe paths are then also plotted on an Inverse Pole Figure (IPF) plot. - -rod_ax = fig.add_subplot(2, 2, 1, projection="rodrigues", proj_type="ortho") -ipf_ax = fig.add_subplot(2, 2, 2, projection="ipf", symmetry=Oh) - -# 10 random orientations with the cubic m3m ('Oh' in the schoenflies notation) -# crystal symmetry. -oris = Orientation( - data=np.array( - [ - [0.69, 0.24, 0.68, 0.01], - [0.26, 0.59, 0.32, 0.7], - [0.07, 0.17, 0.93, 0.31], - [0.6, 0.03, 0.61, 0.52], - [0.51, 0.38, 0.34, 0.69], - [0.31, 0.86, 0.22, 0.35], - [0.68, 0.67, 0.06, 0.31], - [0.01, 0.12, 0.05, 0.99], - [0.39, 0.45, 0.34, 0.72], - [0.65, 0.59, 0.46, 0.15], - ] - ), - symmetry=Oh, -) -# reduce them to their crystallographically identical representations -oris = oris.reduce() -# define a 20 degree rotation around the z axis -shift = Orientation.from_axes_angles([0, 0, 1], 30, degrees=True) -# for each orientation, calculate and plot the path they would take during a -# 45 degree shift. -segment_colors = cm.inferno(np.linspace(0, 1, n_steps)) -for ori in oris: - points = Orientation.stack([ori, (shift * ori)]).reduce() - points.symmetry = Oh - path = Orientation.from_path_ends(points, steps=n_steps) - rod_ax.scatter(path, c=segment_colors) - ipf_ax.scatter(path, c=segment_colors) - -# add the wireframe and clean up the plot. -fz = OrientationRegion.from_symmetry(path.symmetry) -rod_ax.plot_wireframe(fz) -rod_ax._correct_aspect_ratio(fz) -rod_ax.axis("off") -rod_ax.set_title(r"Rodrigues, multiple paths") -ipf_ax.set_title(r"IPF, multiple paths ") - - -# ============ # -# Example 2: Plotting a path using `Rotation.scatter' -# This subplot traces the path of an object rotated 90 degrees around the -# X axis, then 90 degrees around the Y axis. - -rots = Orientation.from_axes_angles( - [[1, 0, 0], [1, 0, 0], [0, 1, 0]], [0, 90, 90], degrees=True, symmetry=C1 -) -rots[2] = rots[1] * rots[2] -path = Orientation.from_path_ends(rots, steps=n_steps) -# create a list of RGBA color values for a gradient red line and blue line -path_colors = np.vstack( - [ - cm.Reds(np.linspace(0.5, 1, n_steps)), - cm.Blues(np.linspace(0.5, 1, n_steps)), - ] -) - -# Here, we instead use the in-built plotting tool from -# Orientation.scatter to auto-generate the subplot. This is especially handy when -# plotting only a single Orientation object. -path.scatter(figure=fig, position=[2, 2, 3], marker=">", c=path_colors) -fig.axes[2].set_title(r"Axis-Angle, two $90^\circ$ rotations") - - -# ============ # -# Example 3: paths in stereographic plots - -# This is similar to the second example, but now vectors are being rotated -# 30 degrees around the [1,1,1] axis on a stereographic plot. - -vec_ax = plt.subplot(2, 2, 4, projection="stereographic", hemisphere="upper") -ipf_colormap = DirectionColorKeyTSL(C1) - -# define a mesh of vectors with approximately 20 degree spacing, and -# within 80 degrees of the Z axis -vecs = sample_S2(20) -vecs = vecs[vecs.polar < (80 * np.pi / 180)] - -# define a 15 degree rotation around [1,1,1] -rots = Quaternion.from_axes_angles([1, 1, 1], [0, 15], degrees=True) - -for vec in vecs: - path_ends = rots * vec - # color each path using a gradient pased on the IPF coloring. - c = ipf_colormap.direction2color(vec) - if np.abs(path_ends.cross(path_ends[::-1])[0].norm) > 1e-12: - path = Vector3d.from_path_ends(path_ends, steps=100) - segment_c = c * np.linspace(0.25, 1, path.size)[:, np.newaxis] - vec_ax.scatter(path, c=segment_c) - else: - vec_ax.scatter(path_ends[0], c=c) - -vec_ax.set_title(r"Stereographic") -vec_ax.set_labels("X", "Y") -plt.tight_layout() diff --git a/examples/plotting/visualizing_rotation_vector_paths.py b/examples/plotting/visualizing_rotation_vector_paths.py new file mode 100644 index 00000000..76942d09 --- /dev/null +++ b/examples/plotting/visualizing_rotation_vector_paths.py @@ -0,0 +1,154 @@ +# +# Copyright 2018-2025 the orix developers +# +# This file is part of orix. +# +# orix is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# orix is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with orix. If not, see . +# + +""" +=============================================== +Visualizing paths between rotations and vectors +=============================================== + +This example shows how define and plot paths through either rotation or vector space. +This is akin to describing crystallographic fiber textures in metallurgy, or the +shortest arcs connecting points on the surface of a unit sphere. + +In both cases, "shortest" is defined as the route that minimizes the movement required +to transform from point to point, which is typically not a stright line when plotted +into a euclidean projection (axis-angle, stereographic, etc.). +""" + +import matplotlib as mpl +import matplotlib.pyplot as plt +import numpy as np + +from orix.plot import register_projections +from orix.plot.direction_color_keys import DirectionColorKeyTSL +from orix.quaternion import Orientation, Rotation +from orix.quaternion.symmetry import C1, Oh +from orix.sampling import sample_S2 +from orix.vector import Vector3d + +register_projections() # Register our custom Matplotlib projections +np.random.seed(2319) # Reproducible random data + +# Number of steps along each path +n_steps = 30 + +######################################################################################## +# Example 1: Continuous path +# ========================== +# +# This plot traces the path of an object rotated 90 degrees around the x-axis, then 90 +# degrees around the y-axis. + +oris1 = Orientation.from_axes_angles( + [[1, 0, 0], [1, 0, 0], [0, 1, 0]], [0, 90, 90], degrees=True +) +oris1[2] = oris1[1] * oris1[2] +path = Orientation.from_path_ends(oris1, steps=n_steps) + +# Create a list of RGBA color values for a gradient red line and blue line +colors1 = np.vstack( + [ + mpl.colormaps["Reds"](np.linspace(0.5, 1, n_steps)), + mpl.colormaps["Blues"](np.linspace(0.5, 1, n_steps)), + ] +) + +# Here, we use the built-in plotting method from Orientation.scatter to auto-generate +# the plot. +# This is especially handy when plotting only a single set of orientations. +path.scatter(marker=">", c=colors1) +_ = plt.gca().set_title("Axis-angle space, two 90\N{DEGREE SIGN} rotations") + +######################################################################################## +# Example 2: Multiple paths +# ========================= +# +# This plot shows several paths through the cubic (*m3m*) fundamental zone created by +# rotating 20 randomly chosen points 30 degrees around the z-axis. +# These paths are drawn in Rodrigues space, which is an equal-angle projection of +# rotation space. +# As such, notice how all lines tracing out axial rotations are straight, but lines +# starting closer to the center of the fundamental zone appear shorter. +# +# The same paths are then also plotted in the inverse pole figure (IPF) for the sample +# direction (0, 0, 1), IPF-Z. + +# Random orientations with the cubic *m3m* crystal symmetry, located inside the +# fundamental zone of the proper point group (*432*) +oris2 = Orientation.random(10, symmetry=Oh).reduce() + +# Rotation around the z-axis +ori_shift = Orientation.from_axes_angles([0, 0, 1], -30, degrees=True) + +# Plot path for the first orientation (to get a figure to add to) +rot_end = ori_shift * oris2[0] +points = Orientation.stack([oris2[0], rot_end]) +path = Orientation.from_path_ends(points, steps=n_steps) +path.symmetry = Oh + +colors2 = mpl.colormaps["inferno"](np.linspace(0, 1, n_steps)) +fig = path.scatter("rodrigues", position=121, return_figure=True, c=colors2) +path.scatter("ipf", position=122, figure=fig, c=colors2) + +# Plot the rest +rod_ax, ipf_ax = fig.axes +rod_ax.set_title("Orientation paths in Rodrigues space") +ipf_ax.set_title("Vector paths in IPF-Z", pad=15) + +for ori_start in oris2[1:]: + rot_end = ori_shift * ori_start + points = Orientation.stack([ori_start, rot_end]) + path = Orientation.from_path_ends(points, steps=n_steps) + path.symmetry = Oh + rod_ax.scatter(path, c=colors2) + ipf_ax.scatter(path, c=colors2) + +######################################################################################## +# Example 3: Multiple vector paths +# ================================ +# +# Rotate vectors around the (1, 1, 1) axis on a stereographic plot. + +vec_ax = plt.subplot(projection="stereographic") +vec_ax.set_title(r"Stereographic") +vec_ax.set_labels("X", "Y") + +ipf_colormap = DirectionColorKeyTSL(C1) + +# Define a mesh of vectors with approximately 20 degree spacing, and within 80 degrees +# of the z-axis +vecs = sample_S2(20) +vecs = vecs[vecs.polar < np.deg2rad(80)] + +# Define a 15 degree rotation around (1, 1, 1) +rot111 = Rotation.from_axes_angles([1, 1, 1], [0, 15], degrees=True) + +for vec in vecs: + path_ends = rot111 * vec + + # Handle case where path start end end are the same vector + if np.isclose(path_ends[0].dot(path_ends[1]), 1): + vec_ax.scatter(path_ends[0], c=ipf_colormap.direction2color(path_ends[0])) + continue + + # Color each path using a gradient pased on the IPF coloring + colors3 = ipf_colormap.direction2color(vec) + path = Vector3d.from_path_ends(path_ends, steps=100) + colors3_segment = colors3 * np.linspace(0.25, 1, path.size)[:, np.newaxis] + vec_ax.scatter(path, c=colors3_segment) diff --git a/orix/quaternion/misorientation.py b/orix/quaternion/misorientation.py index 7222a347..f05158b5 100644 --- a/orix/quaternion/misorientation.py +++ b/orix/quaternion/misorientation.py @@ -297,7 +297,6 @@ def from_path_ends( path Regularly spaced misorientations along the path. - See Also -------- :class:`~orix.quaternion.Quaternion.from_path_ends`,