diff --git a/lib/mpl_toolkits/axisartist/axis_artist.py b/lib/mpl_toolkits/axisartist/axis_artist.py index 9b7faafd40fc..5b297ce38a3b 100644 --- a/lib/mpl_toolkits/axisartist/axis_artist.py +++ b/lib/mpl_toolkits/axisartist/axis_artist.py @@ -77,7 +77,7 @@ The following attributes can be customized (use the ``set_xxx`` methods): -* `Ticks`: ticksize, tick_out +* `Ticks`: ticksize, tickdir * `TickLabels`: pad * `AxisLabel`: pad """ @@ -123,12 +123,12 @@ class Ticks(AttributeCopier, Line2D): Ticks are derived from Line2D, and note that ticks themselves are markers. Thus, you should use set_mec, set_mew, etc. - To change the tick size (length), you need to use - set_ticksize. To change the direction of the ticks (ticks are - in opposite direction of ticklabels by default), use - set_tick_out(False). + To change the tick size (length), use set_ticksize. To change the + direction of the ticks, use set_tickdir ("out" corresponds to the side of + the label, "in" to the opposite side). """ + # tick_out is mostly deprecated in favor of tickdir. def __init__(self, ticksize, tick_out=False, *, axis=None, **kwargs): self._ticksize = ticksize self.locs_angles_labels = [] @@ -158,13 +158,24 @@ def get_markeredgecolor(self): def get_markeredgewidth(self): return self.get_attribute_from_ref_artist("markeredgewidth") + def set_tickdir(self, tickdir): + _api.check_in_list(self._tick_paths, tickdir=tickdir) + self._tickdir = tickdir + + def get_tickdir(self): + return self._tickdir + def set_tick_out(self, b): """Set whether ticks are drawn inside or outside the axes.""" - self._tick_out = b + self.set_tickdir({True: "out", False: "in"}[bool(b)]) def get_tick_out(self): """Return whether ticks are drawn inside or outside the axes.""" - return self._tick_out + if self._tickdir == "out": + return True + elif self._tickdir == "in": + return False + raise ValueError(f"tickdir is {self._tickdir}") def set_ticksize(self, ticksize): """Set length of the ticks in points.""" @@ -177,7 +188,11 @@ def get_ticksize(self): def set_locs_angles(self, locs_angles): self.locs_angles = locs_angles - _tickvert_path = Path([[0., 0.], [1., 0.]]) + _tick_paths = { + "out": Path([[0, 0], [-1, 0]]), + "in": Path([[0, 0], [1, 0]]), + "inout": Path([[-1/2, 0], [1/2, 0]]), + } def draw(self, renderer): if not self.get_visible(): @@ -191,15 +206,14 @@ def draw(self, renderer): path_trans = self.get_transform() marker_transform = (Affine2D() .scale(renderer.points_to_pixels(self._ticksize))) - if self.get_tick_out(): - marker_transform.rotate_deg(180) + tick_path = self._tick_paths[self._tickdir] for loc, angle in self.locs_angles: locs = path_trans.transform_non_affine(np.array([loc])) if self.axes and not self.axes.viewLim.contains(*locs[0]): continue renderer.draw_markers( - gc, self._tickvert_path, + gc, tick_path, marker_transform + Affine2D().rotate_deg(angle), Path(locs), path_trans.get_affine()) @@ -844,11 +858,13 @@ def _init_ticks(self, **kwargs): self.major_ticks = Ticks( kwargs.get( "major_tick_size", rcParams[f"{axis_name}tick.major.size"]), - axis=self.axis, transform=trans) + axis=self.axis, transform=trans, + tickdir=rcParams[f"{axis_name}tick.direction"]) self.minor_ticks = Ticks( kwargs.get( "minor_tick_size", rcParams[f"{axis_name}tick.minor.size"]), - axis=self.axis, transform=trans) + axis=self.axis, transform=trans, + tickdir=rcParams[f"{axis_name}tick.direction"]) size = rcParams[f"{axis_name}tick.labelsize"] self.major_ticklabels = TickLabels( @@ -897,14 +913,13 @@ def _update_ticks(self, renderer): # majorticks even for minor ticks. not clear what is best. dpi_cor = renderer.points_to_pixels(1.) - if self.major_ticks.get_visible() and self.major_ticks.get_tick_out(): - self.major_ticklabels._set_external_pad( - self.major_ticks._ticksize * dpi_cor) - self.minor_ticklabels._set_external_pad( - self.major_ticks._ticksize * dpi_cor) - else: - self.major_ticklabels._set_external_pad(0) - self.minor_ticklabels._set_external_pad(0) + multiplier = ( + self.major_ticks.get_visible() + * {"out": 1, "inout": .5, "in": 0}[self.major_ticks._tickdir]) + self.major_ticklabels._set_external_pad( + multiplier * self.major_ticks._ticksize * dpi_cor) + self.minor_ticklabels._set_external_pad( + multiplier * self.major_ticks._ticksize * dpi_cor) majortick_iter, minortick_iter = \ self._axis_artist_helper.get_tick_iterators(self.axes) @@ -979,7 +994,7 @@ def _update_label(self, renderer): return if self._ticklabel_add_angle != self._axislabel_add_angle: - if ((self.major_ticks.get_visible() + if ((self.major_ticks.get_visible() # ??? and not self.major_ticks.get_tick_out()) or (self.minor_ticks.get_visible() and not self.major_ticks.get_tick_out())): diff --git a/lib/mpl_toolkits/tests/test_axisartist_axis_artist.py b/lib/mpl_toolkits/tests/test_axisartist_axis_artist.py index 1bebbfd9b81d..651a9cca879a 100644 --- a/lib/mpl_toolkits/tests/test_axisartist_axis_artist.py +++ b/lib/mpl_toolkits/tests/test_axisartist_axis_artist.py @@ -78,8 +78,9 @@ def test_ticklabels(): @image_comparison(['axis_artist.png'], style='default') def test_axis_artist(): - # Remove this line when this test image is regenerated. + # Remove these lines when this test image is regenerated. plt.rcParams['text.kerning_factor'] = 6 + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) fig, ax = plt.subplots() diff --git a/lib/mpl_toolkits/tests/test_axisartist_axislines.py b/lib/mpl_toolkits/tests/test_axisartist_axislines.py index 0502a0f23879..ca6c23b4e5aa 100644 --- a/lib/mpl_toolkits/tests/test_axisartist_axislines.py +++ b/lib/mpl_toolkits/tests/test_axisartist_axislines.py @@ -13,8 +13,9 @@ @image_comparison(['SubplotZero.png'], style='default') def test_SubplotZero(): - # Remove this line when this test image is regenerated. + # Remove these lines when this test image is regenerated. plt.rcParams['text.kerning_factor'] = 6 + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) fig = plt.figure() @@ -34,8 +35,9 @@ def test_SubplotZero(): @image_comparison(['Subplot.png'], style='default') def test_Subplot(): - # Remove this line when this test image is regenerated. + # Remove these lines when this test image is regenerated. plt.rcParams['text.kerning_factor'] = 6 + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) fig = plt.figure() @@ -65,8 +67,9 @@ def test_Axes(): @image_comparison(['ParasiteAxesAuxTrans_meshplot.png'], remove_text=True, style='default', tol=0.075) def test_ParasiteAxesAuxTrans(parasite_cls): - # Remove this line when this test image is regenerated. + # Remove these lines when this test image is regenerated. plt.rcParams['pcolormesh.snap'] = False + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) data = np.ones((6, 6)) data[2, 2] = 2 diff --git a/lib/mpl_toolkits/tests/test_axisartist_floating_axes.py b/lib/mpl_toolkits/tests/test_axisartist_floating_axes.py index e69b63f99c2b..0b7af6ed04a2 100644 --- a/lib/mpl_toolkits/tests/test_axisartist_floating_axes.py +++ b/lib/mpl_toolkits/tests/test_axisartist_floating_axes.py @@ -20,6 +20,9 @@ def test_subplot(): @image_comparison(['curvelinear3.png'], style='default', tol=0.01) def test_curvelinear3(): + # Remove this lines when this test image is regenerated. + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) + fig = plt.figure(figsize=(5, 5)) tr = (mtransforms.Affine2D().scale(np.pi / 180, 1) + @@ -74,8 +77,9 @@ def test_curvelinear3(): @image_comparison(['curvelinear4.png'], style='default', tol=0.015) def test_curvelinear4(): - # Remove this line when this test image is regenerated. + # Remove these lines when this test image is regenerated. plt.rcParams['text.kerning_factor'] = 6 + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) fig = plt.figure(figsize=(5, 5)) diff --git a/lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py b/lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py index 57397a596223..a191c72c860e 100644 --- a/lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py +++ b/lib/mpl_toolkits/tests/test_axisartist_grid_helper_curvelinear.py @@ -19,6 +19,9 @@ @image_comparison(['custom_transform.png'], style='default', tol=0.03 if platform.machine() == 'x86_64' else 0.034) def test_custom_transform(): + # Remove this line when this test image is regenerated. + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) + class MyTransform(Transform): input_dims = output_dims = 2 @@ -82,8 +85,9 @@ def inverted(self): @image_comparison(['polar_box.png'], style='default', tol={'aarch64': 0.04}.get(platform.machine(), 0.03)) def test_polar_box(): - # Remove this line when this test image is regenerated. + # Remove these lines when this test image is regenerated. plt.rcParams['text.kerning_factor'] = 6 + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) fig = plt.figure(figsize=(5, 5)) @@ -145,8 +149,9 @@ def test_polar_box(): @image_comparison(['axis_direction.png'], style='default', tol=0.03) def test_axis_direction(): - # Remove this line when this test image is regenerated. + # Remove these lines when this test image is regenerated. plt.rcParams['text.kerning_factor'] = 6 + plt.rcParams.update({"xtick.direction": "in", "ytick.direction": "in"}) fig = plt.figure(figsize=(5, 5))