Skip to content

Commit 94d09cd

Browse files
authored
Merge pull request matplotlib#30369 from anntzer/aiot
Support standard tickdir control (in/out/inout) in axisartist.
2 parents 59eafb8 + 61b6cdc commit 94d09cd

8 files changed

Lines changed: 151 additions & 75 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
:mod:`.axisartist` now uses more standard tick direction controls
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
Previously, the position of :mod:`.axisartist` ticks (inside or outside
4+
the axes) were set using ``set_tick_out(bool)``. They are now set
5+
using ``set_tick_direction("in")`` (or "out", or "inout"), and respect
6+
:rc:`xtick.direction` and :rc:`ytick.direction`. In particular, they default
7+
to pointing outwards, consistently with the rest of the library.
8+
9+
The *tick_out* parameter of `.Ticks` has been deprecated (use *tick_direction*
10+
instead). The ``Ticks.get_tick_out`` method is deprecated (use
11+
`.Ticks.get_tick_direction` instead).
12+
13+
The unused ``locs_angles_labels`` attribute of `.Ticks` and `.LabelBase` has
14+
also been deprecated.

galleries/examples/axisartist/simple_axis_pad.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,33 @@ def ann(ax1, d):
6363
va="top", ha="center")
6464

6565

66-
ax1 = setup_axes(fig, rect=141)
66+
ax1 = setup_axes(fig, rect=231)
6767
axis = add_floating_axis1(ax1)
68-
ann(ax1, r"default")
68+
ann(ax1, "default")
6969

70-
ax1 = setup_axes(fig, rect=142)
70+
ax1 = setup_axes(fig, rect=232)
7171
axis = add_floating_axis1(ax1)
7272
axis.major_ticklabels.set_pad(10)
73-
ann(ax1, r"ticklabels.set_pad(10)")
73+
ann(ax1, "ticklabels.set_pad(10)")
7474

75-
ax1 = setup_axes(fig, rect=143)
75+
ax1 = setup_axes(fig, rect=233)
7676
axis = add_floating_axis1(ax1)
7777
axis.label.set_pad(20)
78-
ann(ax1, r"label.set_pad(20)")
78+
ann(ax1, "label.set_pad(20)")
7979

80-
ax1 = setup_axes(fig, rect=144)
80+
ax1 = setup_axes(fig, rect=234)
8181
axis = add_floating_axis1(ax1)
82-
axis.major_ticks.set_tick_out(True)
83-
ann(ax1, "ticks.set_tick_out(True)")
82+
axis.major_ticks.set_tick_direction("in")
83+
ann(ax1, 'ticks.set_tick_direction("in")')
84+
85+
ax1 = setup_axes(fig, rect=235)
86+
axis = add_floating_axis1(ax1)
87+
axis.major_ticks.set_tick_direction("out")
88+
ann(ax1, 'ticks.set_tick_direction("out")')
89+
90+
ax1 = setup_axes(fig, rect=236)
91+
axis = add_floating_axis1(ax1)
92+
axis.major_ticks.set_tick_direction("inout")
93+
ann(ax1, 'ticks.set_tick_direction("inout")')
8494

8595
plt.show()

galleries/users_explain/toolkits/axisartist.rst

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -287,16 +287,16 @@ HowTo
287287

288288
ax.axis[:].major_ticklabels.set_color("r")
289289

290-
4. To change the tick size (length), you need to use
291-
axis.major_ticks.set_ticksize method. To change the direction of
292-
the ticks (ticks are in opposite direction of ticklabels by
293-
default), use axis.major_ticks.set_tick_out method.
290+
4. To change the tick size (length), use ``axis.major_ticks.set_ticksize``.
291+
292+
To change the direction of the ticks, use
293+
``axis.major_ticks.set_tick_direction``.
294294

295295
To change the pad between ticks and ticklabels, use
296-
axis.major_ticklabels.set_pad method.
296+
``axis.major_ticklabels.set_pad``.
297297

298-
To change the pad between ticklabels and axis label,
299-
axis.label.set_pad method.
298+
To change the pad between ticklabels and axis label, use
299+
``axis.label.set_pad``.
300300

301301
Rotation and alignment of TickLabels
302302
====================================
@@ -398,15 +398,14 @@ axis_direction of ticks, ticklabels, and axis-label does not affect
398398
them.
399399

400400
If you want to make ticks outward and ticklabels inside the axes,
401-
use invert_ticklabel_direction method. ::
401+
use `.AxisArtist.invert_ticklabel_direction`::
402402

403403
ax.axis[:].invert_ticklabel_direction()
404404

405-
A related method is "set_tick_out". It makes ticks outward (as a
406-
matter of fact, it makes ticks toward the opposite direction of the
407-
default direction). ::
405+
A related method is `.Ticks.set_tick_direction`. It can make ticks point "in",
406+
"out", or "inout" (crossing the axis halfway)::
408407

409-
ax.axis[:].major_ticks.set_tick_out(True)
408+
ax.axis[:].major_ticks.set_tick_direction("inout")
410409

411410
.. figure:: /gallery/axisartist/images/sphx_glr_simple_axis_direction03_001.png
412411
:target: /gallery/axisartist/simple_axis_direction03.html
@@ -416,27 +415,28 @@ So, in summary,
416415

417416
* AxisArtist's methods
418417

419-
- set_axis_direction: "left", "right", "bottom", or "top"
420-
- set_ticklabel_direction: "+" or "-"
421-
- set_axislabel_direction: "+" or "-"
422-
- invert_ticklabel_direction
418+
- `~.AxisArtist.set_axis_direction`: "left", "right", "bottom", or "top"
419+
- `~.AxisArtist.set_ticklabel_direction`: "+" or "-"
420+
- `~.AxisArtist.set_axislabel_direction`: "+" or "-"
421+
- `~.AxisArtist.invert_ticklabel_direction`
423422

424423
* Ticks' methods (major_ticks and minor_ticks)
425424

426-
- set_tick_out: True or False
427-
- set_ticksize: size in points
425+
- `~.Ticks.set_tick_direction`: "in", "out", or "inout"
426+
- `~.Ticks.set_ticksize`: size in points
428427

429428
* TickLabels' methods (major_ticklabels and minor_ticklabels)
430429

431-
- set_axis_direction: "left", "right", "bottom", or "top"
432-
- set_rotation: angle with respect to the reference direction
433-
- set_ha and set_va: see below
430+
- `~.TickLabels.set_axis_direction`: "left", "right", "bottom", or "top"
431+
- `~.Text.set_rotation`: angle with respect to the reference direction
432+
- `~.Text.set_horizontalalignment` and `~.Text.set_verticalalignment`: see below
434433

435-
* AxisLabels' methods (label)
434+
* AxisLabel' methods (label)
436435

437-
- set_axis_direction: "left", "right", "bottom", or "top"
438-
- set_rotation: angle with respect to the reference direction
439-
- set_ha and set_va
436+
- `~.AxisLabel.set_axis_direction`: "left", "right", "bottom", or "top"
437+
- `~.Text.set_rotation`: angle with respect to the reference direction
438+
- `~.Text.set_horizontalalignment` and
439+
`~.Text.set_verticalalignment`
440440

441441
Adjusting ticklabels alignment
442442
------------------------------

lib/mpl_toolkits/axisartist/axis_artist.py

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@
5555
axislabel ha right center right center
5656
=================== ====== ======== ====== ========
5757
58-
Ticks are by default direct opposite side of the ticklabels. To make ticks to
59-
the same side of the ticklabels, ::
58+
Tick orientation is controlled by :rc:`xtick.direction` and
59+
:rc:`ytick.direction`; they can be manually adjusted using ::
6060
61-
ax.axis["bottom"].major_ticks.set_tick_out(True)
61+
ax.axis["bottom"].major_ticks.set_tick_direction("in") # or "out", "inout"
6262
6363
The following attributes can be customized (use the ``set_xxx`` methods):
6464
65-
* `Ticks`: ticksize, tick_out
65+
* `Ticks`: ticksize, tick_direction
6666
* `TickLabels`: pad
6767
* `AxisLabel`: pad
6868
"""
@@ -109,16 +109,16 @@ class Ticks(AttributeCopier, Line2D):
109109
Ticks are derived from `.Line2D`, and note that ticks themselves
110110
are markers. Thus, you should use set_mec, set_mew, etc.
111111
112-
To change the tick size (length), you need to use
113-
`set_ticksize`. To change the direction of the ticks (ticks are
114-
in opposite direction of ticklabels by default), use
115-
``set_tick_out(False)``
112+
To change the tick size (length), use `set_ticksize`.
113+
To change the direction of the ticks, use ``set_tick_direction("in")`` (or
114+
"out", or "inout").
116115
"""
117116

117+
locs_angles_labels = _api.deprecated("3.11")(property(lambda self: []))
118+
119+
@_api.delete_parameter("3.11", "tick_out", alternative="tick_direction")
118120
def __init__(self, ticksize, tick_out=False, *, axis=None, **kwargs):
119121
self._ticksize = ticksize
120-
self.locs_angles_labels = []
121-
122122
self.set_tick_out(tick_out)
123123

124124
self._axis = axis
@@ -152,13 +152,33 @@ def get_markeredgecolor(self):
152152
def get_markeredgewidth(self):
153153
return self.get_attribute_from_ref_artist("markeredgewidth")
154154

155+
def set_tick_direction(self, direction):
156+
_api.check_in_list(["in", "out", "inout"], direction=direction)
157+
self._tick_dir = direction
158+
159+
def get_tick_direction(self):
160+
return self._tick_dir
161+
155162
def set_tick_out(self, b):
156-
"""Set whether ticks are drawn inside or outside the axes."""
157-
self._tick_out = b
163+
"""
164+
Set whether ticks are drawn inside or outside the axes.
158165
166+
.. admonition:: Discouraged
167+
Consider using the more general method `.set_tick_direction` instead.
168+
"""
169+
self._tick_dir = "out" if b else "in"
170+
171+
@_api.deprecated("3.11", alternative="get_tick_direction")
159172
def get_tick_out(self):
160173
"""Return whether ticks are drawn inside or outside the axes."""
161-
return self._tick_out
174+
if self._tick_dir == "in":
175+
return False
176+
elif self._tick_dir == "out":
177+
return True
178+
else:
179+
raise ValueError(
180+
f"Tick direction ({self._tick_dir!r}) not supported by get_tick_out, "
181+
f"use get_tick_direction instead")
162182

163183
def set_ticksize(self, ticksize):
164184
"""Set length of the ticks in points."""
@@ -171,7 +191,11 @@ def get_ticksize(self):
171191
def set_locs_angles(self, locs_angles):
172192
self.locs_angles = locs_angles
173193

174-
_tickvert_path = Path([[0., 0.], [1., 0.]])
194+
_tick_paths = {
195+
"in": Path([[0, 0], [+1, 0]]),
196+
"inout": Path([[-1/2, 0.], [+1/2, 0]]),
197+
"out": Path([[-1, 0], [0, 0]]),
198+
}
175199

176200
def draw(self, renderer):
177201
if not self.get_visible():
@@ -183,18 +207,17 @@ def draw(self, renderer):
183207
gc.set_linewidth(self.get_markeredgewidth())
184208
gc.set_alpha(self._alpha)
185209

210+
tickvert_path = self._tick_paths[self._tick_dir]
186211
path_trans = self.get_transform()
187212
marker_transform = (Affine2D()
188213
.scale(renderer.points_to_pixels(self._ticksize)))
189-
if self.get_tick_out():
190-
marker_transform.rotate_deg(180)
191214

192215
for loc, angle in self.locs_angles:
193216
locs = path_trans.transform_non_affine(np.array([loc]))
194217
if self.axes and not self.axes.viewLim.contains(*locs[0]):
195218
continue
196219
renderer.draw_markers(
197-
gc, self._tickvert_path,
220+
gc, tickvert_path,
198221
marker_transform + Affine2D().rotate_deg(angle),
199222
Path(locs), path_trans.get_affine())
200223

@@ -208,8 +231,9 @@ class LabelBase(mtext.Text):
208231
text_ref_angle, and offset_radius attributes.
209232
"""
210233

234+
locs_angles_labels = _api.deprecated("3.11")(property(lambda self: []))
235+
211236
def __init__(self, *args, **kwargs):
212-
self.locs_angles_labels = []
213237
self._ref_angle = 0
214238
self._offset_radius = 0.
215239

@@ -867,14 +891,16 @@ def _init_ticks(self, **kwargs):
867891
+ self.offset_transform)
868892

869893
self.major_ticks = Ticks(
870-
kwargs.get(
894+
ticksize=kwargs.get(
871895
"major_tick_size",
872896
mpl.rcParams[f"{axis_name}tick.major.size"]),
897+
tick_direction=mpl.rcParams[f"{axis_name}tick.direction"],
873898
axis=self.axis, transform=trans)
874899
self.minor_ticks = Ticks(
875-
kwargs.get(
900+
ticksize=kwargs.get(
876901
"minor_tick_size",
877902
mpl.rcParams[f"{axis_name}tick.minor.size"]),
903+
tick_direction=mpl.rcParams[f"{axis_name}tick.direction"],
878904
axis=self.axis, transform=trans)
879905

880906
size = mpl.rcParams[f"{axis_name}tick.labelsize"]
@@ -926,14 +952,13 @@ def _update_ticks(self, renderer=None):
926952
if renderer is None:
927953
renderer = self.get_figure(root=True)._get_renderer()
928954

929-
dpi_cor = renderer.points_to_pixels(1.)
930-
if self.major_ticks.get_visible() and self.major_ticks.get_tick_out():
931-
ticklabel_pad = self.major_ticks._ticksize * dpi_cor
932-
self.major_ticklabels._external_pad = ticklabel_pad
933-
self.minor_ticklabels._external_pad = ticklabel_pad
934-
else:
935-
self.major_ticklabels._external_pad = 0
936-
self.minor_ticklabels._external_pad = 0
955+
self.major_ticklabels._external_pad = \
956+
self.minor_ticklabels._external_pad = (
957+
renderer.points_to_pixels(self.major_ticks._ticksize)
958+
* {"in": 0, "inout": 1/2, "out": 1}[
959+
self.major_ticks.get_tick_direction()]
960+
* self.major_ticks.get_visible() # 0 if invisible.
961+
)
937962

938963
majortick_iter, minortick_iter = \
939964
self._axis_artist_helper.get_tick_iterators(self.axes)
@@ -1008,13 +1033,18 @@ def _update_label(self, renderer):
10081033
return
10091034

10101035
if self._ticklabel_add_angle != self._axislabel_add_angle:
1011-
if ((self.major_ticks.get_visible()
1012-
and not self.major_ticks.get_tick_out())
1013-
or (self.minor_ticks.get_visible()
1014-
and not self.major_ticks.get_tick_out())):
1015-
axislabel_pad = self.major_ticks._ticksize
1016-
else:
1017-
axislabel_pad = 0
1036+
axislabel_pad = max(
1037+
# major pad:
1038+
self.major_ticks._ticksize
1039+
* {"in": 1, "inout": 1/2, "out": 0}[
1040+
self.major_ticks.get_tick_direction()]
1041+
* self.major_ticks.get_visible(), # 0 if invisible.
1042+
# minor pad:
1043+
self.minor_ticks._ticksize
1044+
* {"in": 1, "inout": 1/2, "out": 0}[
1045+
self.minor_ticks.get_tick_direction()]
1046+
* self.minor_ticks.get_visible(), # 0 if invisible.
1047+
)
10181048
else:
10191049
axislabel_pad = max(self.major_ticklabels._axislabel_pad,
10201050
self.minor_ticklabels._axislabel_pad)

lib/mpl_toolkits/axisartist/tests/test_axis_artist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def test_ticks():
1919
ticks_in.set_locs_angles(locs_angles)
2020
ax.add_artist(ticks_in)
2121

22-
ticks_out = Ticks(ticksize=10, tick_out=True, color='C3', axis=ax.xaxis)
22+
ticks_out = Ticks(ticksize=10, tick_direction="out", color='C3', axis=ax.xaxis)
2323
ticks_out.set_locs_angles(locs_angles)
2424
ax.add_artist(ticks_out)
2525

@@ -92,11 +92,11 @@ def test_axis_artist():
9292
for loc in ('left', 'right', 'bottom'):
9393
helper = AxisArtistHelperRectlinear.Fixed(ax, loc=loc)
9494
axisline = AxisArtist(ax, helper, offset=None, axis_direction=loc)
95+
axisline.major_ticks.set_tick_direction("in")
9596
ax.add_artist(axisline)
9697

9798
# Settings for bottom AxisArtist.
9899
axisline.set_label("TTT")
99-
axisline.major_ticks.set_tick_out(False)
100100
axisline.label.set_pad(5)
101101

102102
ax.set_ylabel("Test")

0 commit comments

Comments
 (0)