Skip to content

Commit abf083b

Browse files
Tick rendering speedups
1 parent c11175d commit abf083b

File tree

6 files changed

+44
-23
lines changed

6 files changed

+44
-23
lines changed

lib/matplotlib/axis.py

+14-8
Original file line numberDiff line numberDiff line change
@@ -1269,7 +1269,7 @@ def _set_artist_props(self, a):
12691269
def _update_ticks(self):
12701270
"""
12711271
Update ticks (position and labels) using the current data interval of
1272-
the axes. Return the list of ticks that will be drawn.
1272+
the axes.
12731273
"""
12741274
major_locs = self.get_majorticklocs()
12751275
major_labels = self.major.formatter.format_ticks(major_locs)
@@ -1285,7 +1285,7 @@ def _update_ticks(self):
12851285
tick.update_position(loc)
12861286
tick.label1.set_text(label)
12871287
tick.label2.set_text(label)
1288-
ticks = [*major_ticks, *minor_ticks]
1288+
self._ticks = [*major_ticks, *minor_ticks]
12891289

12901290
view_low, view_high = self.get_view_interval()
12911291
if view_low > view_high:
@@ -1302,18 +1302,24 @@ def _update_ticks(self):
13021302
view_high = view_high - delta * margin
13031303
view_low = view_low + delta * margin
13041304

1305-
interval_t = self.get_transform().transform([view_low, view_high])
1305+
self._interval_t = self.get_transform().transform([view_low, view_high])
13061306

1307+
def _get_ticks_to_draw(self, update=True):
1308+
'''
1309+
Return the list of ticks that will be drawn.
1310+
'''
1311+
if update:
1312+
self._update_ticks()
13071313
ticks_to_draw = []
1308-
for tick in ticks:
1314+
for tick in self._ticks:
13091315
try:
13101316
loc_t = self.get_transform().transform(tick.get_loc())
13111317
except AssertionError:
13121318
# transforms.transform doesn't allow masked values but
13131319
# some scales might make them, so we need this try/except.
13141320
pass
13151321
else:
1316-
if mtransforms._interval_contains_close(interval_t, loc_t):
1322+
if mtransforms._interval_contains_close(self._interval_t, loc_t):
13171323
ticks_to_draw.append(tick)
13181324

13191325
return ticks_to_draw
@@ -1341,7 +1347,7 @@ def get_tightbbox(self, renderer=None, *, for_layout_only=False):
13411347
return
13421348
if renderer is None:
13431349
renderer = self.get_figure(root=True)._get_renderer()
1344-
ticks_to_draw = self._update_ticks()
1350+
ticks_to_draw = self._get_ticks_to_draw(update=True)
13451351

13461352
self._update_label_position(renderer)
13471353

@@ -1394,7 +1400,7 @@ def draw(self, renderer):
13941400
return
13951401
renderer.open_group(__name__, gid=self.get_gid())
13961402

1397-
ticks_to_draw = self._update_ticks()
1403+
ticks_to_draw = self._get_ticks_to_draw(update=True)
13981404
tlb1, tlb2 = self._get_ticklabel_bboxes(ticks_to_draw, renderer)
13991405

14001406
for tick in ticks_to_draw:
@@ -2230,7 +2236,7 @@ def _get_tick_boxes_siblings(self, renderer):
22302236
# If we want to align labels from other Axes:
22312237
for ax in grouper.get_siblings(self.axes):
22322238
axis = ax._axis_map[name]
2233-
ticks_to_draw = axis._update_ticks()
2239+
ticks_to_draw = axis._get_ticks_to_draw(update=True)
22342240
tlb, tlb2 = axis._get_ticklabel_bboxes(ticks_to_draw, renderer)
22352241
bboxes.extend(tlb)
22362242
bboxes2.extend(tlb2)

lib/matplotlib/backends/backend_agg.py

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from contextlib import nullcontext
2525
from math import radians, cos, sin
26+
from functools import lru_cache
2627

2728
import numpy as np
2829

@@ -245,6 +246,7 @@ def get_canvas_width_height(self):
245246
# docstring inherited
246247
return self.width, self.height
247248

249+
@lru_cache(maxsize=64)
248250
def _prepare_font(self, font_prop):
249251
"""
250252
Get the `.FT2Font` for *font_prop*, clear its buffer, and set its size.

lib/matplotlib/spines.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def get_window_extent(self, renderer=None):
155155
if self.axis is None or not self.axis.get_visible():
156156
return bb
157157
bboxes = [bb]
158-
drawn_ticks = self.axis._update_ticks()
158+
drawn_ticks = self.axis._get_ticks_to_draw(update=True)
159159

160160
major_tick = next(iter({*drawn_ticks} & {*self.axis.majorTicks}), None)
161161
minor_tick = next(iter({*drawn_ticks} & {*self.axis.minorTicks}), None)

lib/matplotlib/tests/test_axes.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3128,7 +3128,7 @@ def test_log_scales():
31283128
ax.invert_yaxis()
31293129
ax.set_xscale('log', base=9.0)
31303130
xticks, yticks = (
3131-
[(t.get_loc(), t.label1.get_text()) for t in axis._update_ticks()]
3131+
[(t.get_loc(), t.label1.get_text()) for t in axis._get_ticks_to_draw(update=True)]
31323132
for axis in [ax.xaxis, ax.yaxis]
31333133
)
31343134
assert xticks == [

lib/mpl_toolkits/mplot3d/axes3d.py

+3
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,9 @@ def draw(self, renderer):
456456
artist.do_3d_projection()
457457

458458
if self._axis3don:
459+
# Update ticks
460+
for axis in self._axis_map.values():
461+
axis._update_ticks()
459462
# Draw panes first
460463
for axis in self._axis_map.values():
461464
axis.draw_pane(renderer)

lib/mpl_toolkits/mplot3d/axis3d.py

+23-13
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,9 @@ def _axmask(self):
435435

436436
def _draw_ticks(self, renderer, edgep1, centers, deltas, highs,
437437
deltas_per_point, pos):
438-
ticks = self._update_ticks()
438+
ticks = self._get_ticks_to_draw(update=False) # We updated in Axes3D.draw()
439439
info = self._axinfo
440440
index = info["i"]
441-
juggled = info["juggled"]
442441

443442
mins, maxs, tc, highs = self._get_coord_info()
444443
centers, deltas = self._calc_centers_deltas(maxs, mins)
@@ -461,17 +460,28 @@ def _draw_ticks(self, renderer, edgep1, centers, deltas, highs,
461460
# Get tick line positions
462461
pos = edgep1.copy()
463462
pos[index] = tick.get_loc()
464-
pos[tickdir] = out_tickdir
465-
x1, y1, z1 = proj3d.proj_transform(*pos, self.axes.M)
466-
pos[tickdir] = in_tickdir
467-
x2, y2, z2 = proj3d.proj_transform(*pos, self.axes.M)
468-
469-
# Get position of label
470-
labeldeltas = (tick.get_pad() + default_label_offset) * points
471463

472-
pos[tickdir] = edgep1_tickdir
473-
pos = _move_from_center(pos, centers, labeldeltas, self._axmask())
474-
lx, ly, lz = proj3d.proj_transform(*pos, self.axes.M)
464+
# Add out and in tickdir positions
465+
positions = []
466+
for td in (out_tickdir, in_tickdir):
467+
p = pos.copy()
468+
p[tickdir] = td
469+
positions.append(p)
470+
471+
# Add label position
472+
p = pos.copy()
473+
p[tickdir] = edgep1_tickdir
474+
positions.append(_move_from_center(
475+
p, centers,
476+
(tick.get_pad() + default_label_offset) * points,
477+
self._axmask()
478+
))
479+
480+
xs, ys, zs = proj3d._proj_trans_points(np.array(positions), self.axes.M)
481+
482+
x1, y1, z1 = xs[0], ys[0], zs[0]
483+
x2, y2, z2 = xs[1], ys[1], zs[1]
484+
lx, ly, lz = xs[2], ys[2], zs[2]
475485

476486
_tick_update_position(tick, (x1, x2), (y1, y2), (lx, ly))
477487
tick.tick1line.set_linewidth(tick_lw[tick._major])
@@ -636,7 +646,7 @@ def draw_grid(self, renderer):
636646

637647
renderer.open_group("grid3d", gid=self.get_gid())
638648

639-
ticks = self._update_ticks()
649+
ticks = self._get_ticks_to_draw(update=False) # We updated in Axes3D.draw()
640650
if len(ticks):
641651
# Get general axis information:
642652
info = self._axinfo

0 commit comments

Comments
 (0)