| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1968,6 +1968,9 @@ def __init__(self, xy, width, height, angle=0.0, | |||
| 1968 | 1968 | ||
| 1969 | 1969 | self.theta1 = theta1 | |
| 1970 | 1970 | self.theta2 = theta2 | |
| 1971 | + self._theta1, self._theta2, self._width, self._height = \ | ||
| 1972 | + self._theta_stretch() | ||
| 1973 | + self._path = Path.arc(self._theta1, self._theta2) | ||
| 1971 | 1974 | ||
| 1972 | 1975 | @artist.allow_rasterization | |
| 1973 | 1976 | def draw(self, renderer): | |
@@ -2023,36 +2026,7 @@ def draw(self, renderer): | |||
| 2023 | 2026 | ||
| 2024 | 2027 | self._recompute_transform() | |
| 2025 | 2028 | ||
| 2026 | - width = self.convert_xunits(self.width) | ||
| 2027 | - height = self.convert_yunits(self.height) | ||
| 2028 | - | ||
| 2029 | - # If the width and height of ellipse are not equal, take into account | ||
| 2030 | - # stretching when calculating angles to draw between | ||
| 2031 | - def theta_stretch(theta, scale): | ||
| 2032 | - theta = np.deg2rad(theta) | ||
| 2033 | - x = np.cos(theta) | ||
| 2034 | - y = np.sin(theta) | ||
| 2035 | - stheta = np.rad2deg(np.arctan2(scale * y, x)) | ||
| 2036 | - # arctan2 has the range [-pi, pi], we expect [0, 2*pi] | ||
| 2037 | - return (stheta + 360) % 360 | ||
| 2038 | - | ||
| 2039 | - theta1 = self.theta1 | ||
| 2040 | - theta2 = self.theta2 | ||
| 2041 | - | ||
| 2042 | - if ( | ||
| 2043 | - # if we need to stretch the angles because we are distorted | ||
| 2044 | - width != height | ||
| 2045 | - # and we are not doing a full circle. | ||
| 2046 | - # | ||
| 2047 | - # 0 and 360 do not exactly round-trip through the angle | ||
| 2048 | - # stretching (due to both float precision limitations and | ||
| 2049 | - # the difference between the range of arctan2 [-pi, pi] and | ||
| 2050 | - # this method [0, 360]) so avoid doing it if we don't have to. | ||
| 2051 | - and not (theta1 != theta2 and theta1 % 360 == theta2 % 360) | ||
| 2052 | - ): | ||
| 2053 | - theta1 = theta_stretch(self.theta1, width / height) | ||
| 2054 | - theta2 = theta_stretch(self.theta2, width / height) | ||
| 2055 | - | ||
| 2029 | + self._update_path() | ||
| 2056 | 2030 | # Get width and height in pixels we need to use | |
| 2057 | 2031 | # `self.get_data_transform` rather than `self.get_transform` | |
| 2058 | 2032 | # because we want the transform from dataspace to the | |
@@ -2061,12 +2035,12 @@ def theta_stretch(theta, scale): | |||
| 2061 | 2035 | # `self.get_transform()` goes from an idealized unit-radius | |
| 2062 | 2036 | # space to screen space). | |
| 2063 | 2037 | data_to_screen_trans = self.get_data_transform() | |
| 2064 | - pwidth, pheight = (data_to_screen_trans.transform((width, height)) - | ||
| 2065 | - data_to_screen_trans.transform((0, 0))) | ||
| 2038 | + pwidth, pheight = ( | ||
| 2039 | + data_to_screen_trans.transform((self._width, self._height)) - | ||
| 2040 | + data_to_screen_trans.transform((0, 0))) | ||
| 2066 | 2041 | inv_error = (1.0 / 1.89818e-6) * 0.5 | |
| 2067 | 2042 | ||
| 2068 | 2043 | if pwidth < inv_error and pheight < inv_error: | |
| 2069 | - self._path = Path.arc(theta1, theta2) | ||
| 2070 | 2044 | return Patch.draw(self, renderer) | |
| 2071 | 2045 | ||
| 2072 | 2046 | def line_circle_intersect(x0, y0, x1, y1): | |
@@ -2118,10 +2092,11 @@ def segment_circle_intersect(x0, y0, x1, y1): | |||
| 2118 | 2092 | # arctan2 return [-pi, pi), the rest of our angles are in | |
| 2119 | 2093 | # [0, 360], adjust as needed. | |
| 2120 | 2094 | theta = (np.rad2deg(np.arctan2(y, x)) + 360) % 360 | |
| 2121 | - thetas.update(theta[(theta1 < theta) & (theta < theta2)]) | ||
| 2122 | - thetas = sorted(thetas) + [theta2] | ||
| 2123 | - last_theta = theta1 | ||
| 2124 | - theta1_rad = np.deg2rad(theta1) | ||
| 2095 | + thetas.update( | ||
| 2096 | + theta[(self._theta1 < theta) & (theta < self._theta2)]) | ||
| 2097 | + thetas = sorted(thetas) + [self._theta2] | ||
| 2098 | + last_theta = self._theta1 | ||
| 2099 | + theta1_rad = np.deg2rad(self._theta1) | ||
| 2125 | 2100 | inside = box_path.contains_point( | |
| 2126 | 2101 | (np.cos(theta1_rad), np.sin(theta1_rad)) | |
| 2127 | 2102 | ) | |
@@ -2140,6 +2115,44 @@ def segment_circle_intersect(x0, y0, x1, y1): | |||
| 2140 | 2115 | # restore original path | |
| 2141 | 2116 | self._path = path_original | |
| 2142 | 2117 | ||
| 2118 | + def _update_path(self): | ||
| 2119 | + # Compute new values and update and set new _path if changed | ||
| 2120 | + stretched = self._theta_stretch() | ||
| 2121 | + if any(a != b for a, b in zip(stretched, (self._theta1, self._theta2, | ||
| 2122 | + self._width, self._height))): | ||
| 2123 | + self._theta1, self._theta2, self._width, self._height = stretched | ||
| 2124 | + self._path = Path.arc(self._theta1, self._theta2) | ||
| 2125 | + | ||
| 2126 | + def _theta_stretch(self): | ||
| 2127 | + # If the width and height of ellipse are not equal, take into account | ||
| 2128 | + # stretching when calculating angles to draw between | ||
| 2129 | + def theta_stretch(theta, scale): | ||
| 2130 | + theta = np.deg2rad(theta) | ||
| 2131 | + x = np.cos(theta) | ||
| 2132 | + y = np.sin(theta) | ||
| 2133 | + stheta = np.rad2deg(np.arctan2(scale * y, x)) | ||
| 2134 | + # arctan2 has the range [-pi, pi], we expect [0, 2*pi] | ||
| 2135 | + return (stheta + 360) % 360 | ||
| 2136 | + | ||
| 2137 | + width = self.convert_xunits(self.width) | ||
| 2138 | + height = self.convert_yunits(self.height) | ||
| 2139 | + if ( | ||
| 2140 | + # if we need to stretch the angles because we are distorted | ||
| 2141 | + width != height | ||
| 2142 | + # and we are not doing a full circle. | ||
| 2143 | + # | ||
| 2144 | + # 0 and 360 do not exactly round-trip through the angle | ||
| 2145 | + # stretching (due to both float precision limitations and | ||
| 2146 | + # the difference between the range of arctan2 [-pi, pi] and | ||
| 2147 | + # this method [0, 360]) so avoid doing it if we don't have to. | ||
| 2148 | + and not (self.theta1 != self.theta2 and | ||
| 2149 | + self.theta1 % 360 == self.theta2 % 360) | ||
| 2150 | + ): | ||
| 2151 | + theta1 = theta_stretch(self.theta1, width / height) | ||
| 2152 | + theta2 = theta_stretch(self.theta2, width / height) | ||
| 2153 | + return theta1, theta2, width, height | ||
| 2154 | + return self.theta1, self.theta2, width, height | ||
| 2155 | + | ||
| 2143 | 2156 | ||
| 2144 | 2157 | def bbox_artist(artist, renderer, props=None, fill=True): | |
| 2145 | 2158 | """ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | 8 | import matplotlib as mpl | |
| 9 | 9 | from matplotlib.patches import (Annulus, Ellipse, Patch, Polygon, Rectangle, | |
| 10 | - FancyArrowPatch, FancyArrow, BoxStyle) | ||
| 10 | + FancyArrowPatch, FancyArrow, BoxStyle, Arc) | ||
| 11 | 11 | from matplotlib.testing.decorators import image_comparison, check_figures_equal | |
| 12 | 12 | from matplotlib.transforms import Bbox | |
| 13 | 13 | import matplotlib.pyplot as plt | |
@@ -642,7 +642,7 @@ def test_large_arc(): | |||
| 642 | 642 | y = -2115 | |
| 643 | 643 | diameter = 4261 | |
| 644 | 644 | for ax in [ax1, ax2]: | |
| 645 | - a = mpatches.Arc((x, y), diameter, diameter, lw=2, color='k') | ||
| 645 | + a = Arc((x, y), diameter, diameter, lw=2, color='k') | ||
| 646 | 646 | ax.add_patch(a) | |
| 647 | 647 | ax.set_axis_off() | |
| 648 | 648 | ax.set_aspect('equal') | |
@@ -669,7 +669,7 @@ def test_rotated_arcs(): | |||
| 669 | 669 | for prescale, centers in zip((1 - .0001, (1 - .0001) / np.sqrt(2)), | |
| 670 | 670 | (on_axis_centers, diag_centers)): | |
| 671 | 671 | for j, (x_sign, y_sign) in enumerate(centers, start=k): | |
| 672 | - a = mpatches.Arc( | ||
| 672 | + a = Arc( | ||
| 673 | 673 | (x_sign * scale * prescale, | |
| 674 | 674 | y_sign * scale * prescale), | |
| 675 | 675 | scale * sx, | |
@@ -808,3 +808,32 @@ def test_default_capstyle(): | |||
| 808 | 808 | def test_default_joinstyle(): | |
| 809 | 809 | patch = Patch() | |
| 810 | 810 | assert patch.get_joinstyle() == 'miter' | |
| 811 | + | ||
| 812 | + | ||
| 813 | + @image_comparison(["autoscale_arc"], extensions=['png', 'svg'], | ||
| 814 | + style="mpl20") | ||
| 815 | + def test_autoscale_arc(): | ||
| 816 | + fig, axs = plt.subplots(1, 3, squeeze=False, figsize=(4, 1)) | ||
| 817 | + arc_lists = ( | ||
| 818 | + [Arc((0, 0), 1, 1, theta1=0, theta2=90)], | ||
| 819 | + [Arc((0.5, 0.5), 1.5, 0.5, theta1=10, theta2=20)], | ||
| 820 | + [Arc((0.5, 0.5), 1.5, 0.5, theta1=10, theta2=20), | ||
| 821 | + Arc((0.5, 0.5), 2.5, 0.5, theta1=110, theta2=120), | ||
| 822 | + Arc((0.5, 0.5), 3.5, 0.5, theta1=210, theta2=220), | ||
| 823 | + Arc((0.5, 0.5), 4.5, 0.5, theta1=310, theta2=320)]) | ||
| 824 | + | ||
| 825 | + for ax, arcs in zip(axs[0], arc_lists): | ||
| 826 | + for arc in arcs: | ||
| 827 | + ax.add_patch(arc) | ||
| 828 | + ax.autoscale() | ||
| 829 | + ax.set_axis_off() | ||
| 830 | + | ||
| 831 | + | ||
| 832 | + @check_figures_equal(extensions=["png", 'svg', 'pdf', 'eps']) | ||
| 833 | + def test_arc_in_collection(fig_test, fig_ref): | ||
| 834 | + arc1 = Arc([.5, .5], .5, 1, theta1=0, theta2=60, angle=20) | ||
| 835 | + arc2 = Arc([.5, .5], .5, 1, theta1=0, theta2=60, angle=20) | ||
| 836 | + col = mcollections.PatchCollection(patches=[arc2], facecolors='none', | ||
| 837 | + edgecolors='k') | ||
| 838 | + fig_ref.subplots().add_patch(arc1) | ||
| 839 | + fig_test.subplots().add_collection(col) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,7 +7,7 @@ | |||
| 7 | 7 | import matplotlib as mpl | |
| 8 | 8 | from matplotlib.backend_bases import MouseButton | |
| 9 | 9 | from matplotlib import cm | |
| 10 | - from matplotlib import colors as mcolors | ||
| 10 | + from matplotlib import colors as mcolors, patches as mpatch | ||
| 11 | 11 | from matplotlib.testing.decorators import image_comparison, check_figures_equal | |
| 12 | 12 | from matplotlib.testing.widgets import mock_event | |
| 13 | 13 | from matplotlib.collections import LineCollection, PolyCollection | |
@@ -1742,3 +1742,14 @@ def test_view_init_vertical_axis( | |||
| 1742 | 1742 | tickdir_expected = tickdirs_expected[i] | |
| 1743 | 1743 | tickdir_actual = axis._get_tickdir() | |
| 1744 | 1744 | np.testing.assert_array_equal(tickdir_expected, tickdir_actual) | |
| 1745 | + | ||
| 1746 | + | ||
| 1747 | + @image_comparison(baseline_images=['arc_pathpatch.png'], | ||
| 1748 | + remove_text=True, | ||
| 1749 | + style='default') | ||
| 1750 | + def test_arc_pathpatch(): | ||
| 1751 | + ax = plt.subplot(1, 1, 1, projection="3d") | ||
| 1752 | + a = mpatch.Arc((0.5, 0.5), width=0.5, height=0.9, | ||
| 1753 | + angle=20, theta1=10, theta2=130) | ||
| 1754 | + ax.add_patch(a) | ||
| 1755 | + art3d.pathpatch_2d_to_3d(a, z=0, zdir='z') | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments