Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5a134ed

Browse files
committed
Support standard tickdir control (in/out/inout) in axisartist.
... and also respect rcParams, which makes axisartist ticks default to pointing outwards, similarly to standard ticks. Rework the tick direction machinery to also support "inout" (similarly to standard ticks). One may wonder whether external ticks should really be drawn in the local direction of the gridlines, though, or whether drawing them orthogonal to the axis spine would look better. This PR keeps the old behavior of `set_ticks_out(True)`, but we could later add something like ``set_tick_direction("out_ortho")`` (name up to bikeshedding). While at it, also deprecate the entirely unused `Ticks.locs_angles_labels` and `LabelBase.locs_angles_labels`.
1 parent b2e8b93 commit 5a134ed

File tree

8 files changed

+149
-76
lines changed

8 files changed

+149
-76
lines changed
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
@@ -81,23 +81,33 @@ def ann(ax1, d):
8181
va="top", ha="center")
8282

8383

84-
ax1 = setup_axes(fig, rect=141)
84+
ax1 = setup_axes(fig, rect=231)
8585
axis = add_floating_axis1(ax1)
86-
ann(ax1, r"default")
86+
ann(ax1, "default")
8787

88-
ax1 = setup_axes(fig, rect=142)
88+
ax1 = setup_axes(fig, rect=232)
8989
axis = add_floating_axis1(ax1)
9090
axis.major_ticklabels.set_pad(10)
91-
ann(ax1, r"ticklabels.set_pad(10)")
91+
ann(ax1, "ticklabels.set_pad(10)")
9292

93-
ax1 = setup_axes(fig, rect=143)
93+
ax1 = setup_axes(fig, rect=233)
9494
axis = add_floating_axis1(ax1)
9595
axis.label.set_pad(20)
96-
ann(ax1, r"label.set_pad(20)")
96+
ann(ax1, "label.set_pad(20)")
9797

98-
ax1 = setup_axes(fig, rect=144)
98+
ax1 = setup_axes(fig, rect=234)
9999
axis = add_floating_axis1(ax1)
100-
axis.major_ticks.set_tick_out(True)
101-
ann(ax1, "ticks.set_tick_out(True)")
100+
axis.major_ticks.set_tick_direction("in")
101+
ann(ax1, 'ticks.set_tick_direction("in")')
102+
103+
ax1 = setup_axes(fig, rect=235)
104+
axis = add_floating_axis1(ax1)
105+
axis.major_ticks.set_tick_direction("out")
106+
ann(ax1, 'ticks.set_tick_direction("out")')
107+
108+
ax1 = setup_axes(fig, rect=236)
109+
axis = add_floating_axis1(ax1)
110+
axis.major_ticks.set_tick_direction("inout")
111+
ann(ax1, 'ticks.set_tick_direction("inout")')
102112

103113
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: 63 additions & 36 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,8 +191,6 @@ 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.]])
175-
176194
def draw(self, renderer):
177195
if not self.get_visible():
178196
return
@@ -182,18 +200,20 @@ def draw(self, renderer):
182200
gc.set_linewidth(self.get_markeredgewidth())
183201
gc.set_alpha(self._alpha)
184202

203+
tickvert_path = (
204+
Path([[0, 0], [1, 0]]) if self._tick_dir == "in" else
205+
Path([[-1, 0], [0, 0]]) if self._tick_dir == "out" else
206+
Path([[-.5, 0.], [.5, 0]])) # if self._tick_dir == "inout"
185207
path_trans = self.get_transform()
186208
marker_transform = (Affine2D()
187209
.scale(renderer.points_to_pixels(self._ticksize)))
188-
if self.get_tick_out():
189-
marker_transform.rotate_deg(180)
190210

191211
for loc, angle in self.locs_angles:
192212
locs = path_trans.transform_non_affine(np.array([loc]))
193213
if self.axes and not self.axes.viewLim.contains(*locs[0]):
194214
continue
195215
renderer.draw_markers(
196-
gc, self._tickvert_path,
216+
gc, tickvert_path,
197217
marker_transform + Affine2D().rotate_deg(angle),
198218
Path(locs), path_trans.get_affine())
199219

@@ -207,8 +227,9 @@ class LabelBase(mtext.Text):
207227
text_ref_angle, and offset_radius attributes.
208228
"""
209229

230+
locs_angles_labels = _api.deprecated("3.11")(property(lambda self: []))
231+
210232
def __init__(self, *args, **kwargs):
211-
self.locs_angles_labels = []
212233
self._ref_angle = 0
213234
self._offset_radius = 0.
214235

@@ -866,14 +887,16 @@ def _init_ticks(self, **kwargs):
866887
+ self.offset_transform)
867888

868889
self.major_ticks = Ticks(
869-
kwargs.get(
890+
ticksize=kwargs.get(
870891
"major_tick_size",
871892
mpl.rcParams[f"{axis_name}tick.major.size"]),
893+
tick_direction=mpl.rcParams[f"{axis_name}tick.direction"],
872894
axis=self.axis, transform=trans)
873895
self.minor_ticks = Ticks(
874-
kwargs.get(
896+
ticksize=kwargs.get(
875897
"minor_tick_size",
876898
mpl.rcParams[f"{axis_name}tick.minor.size"]),
899+
tick_direction=mpl.rcParams[f"{axis_name}tick.direction"],
877900
axis=self.axis, transform=trans)
878901

879902
size = mpl.rcParams[f"{axis_name}tick.labelsize"]
@@ -925,14 +948,13 @@ def _update_ticks(self, renderer=None):
925948
if renderer is None:
926949
renderer = self.get_figure(root=True)._get_renderer()
927950

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

937959
majortick_iter, minortick_iter = \
938960
self._axis_artist_helper.get_tick_iterators(self.axes)
@@ -1007,13 +1029,18 @@ def _update_label(self, renderer):
10071029
return
10081030

10091031
if self._ticklabel_add_angle != self._axislabel_add_angle:
1010-
if ((self.major_ticks.get_visible()
1011-
and not self.major_ticks.get_tick_out())
1012-
or (self.minor_ticks.get_visible()
1013-
and not self.major_ticks.get_tick_out())):
1014-
axislabel_pad = self.major_ticks._ticksize
1015-
else:
1016-
axislabel_pad = 0
1032+
axislabel_pad = max(
1033+
# major pad:
1034+
self.major_ticks._ticksize
1035+
* {"in": 1, "inout": .5, "out": 0}[
1036+
self.major_ticks.get_tick_direction()]
1037+
* self.major_ticks.get_visible(), # 0 if invisible.
1038+
# minor pad:
1039+
self.minor_ticks._ticksize
1040+
* {"in": 1, "inout": .5, "out": 0}[
1041+
self.minor_ticks.get_tick_direction()]
1042+
* self.minor_ticks.get_visible(), # 0 if invisible.
1043+
)
10171044
else:
10181045
axislabel_pad = max(self.major_ticklabels._axislabel_pad,
10191046
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

@@ -89,11 +89,11 @@ def test_axis_artist():
8989
for loc in ('left', 'right', 'bottom'):
9090
helper = AxisArtistHelperRectlinear.Fixed(ax, loc=loc)
9191
axisline = AxisArtist(ax, helper, offset=None, axis_direction=loc)
92+
axisline.major_ticks.set_tick_direction("in")
9293
ax.add_artist(axisline)
9394

9495
# Settings for bottom AxisArtist.
9596
axisline.set_label("TTT")
96-
axisline.major_ticks.set_tick_out(False)
9797
axisline.label.set_pad(5)
9898

9999
ax.set_ylabel("Test")

0 commit comments

Comments
 (0)