Skip to content

Commit 9965954

Browse files
Break axis3d drawing into subfunctions
1 parent 791347b commit 9965954

File tree

1 file changed

+109
-80
lines changed

1 file changed

+109
-80
lines changed

lib/mpl_toolkits/mplot3d/axis3d.py

Lines changed: 109 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -322,69 +322,63 @@ def draw_pane(self, renderer):
322322
self.pane.draw(renderer)
323323
renderer.close_group('pane3d')
324324

325-
@artist.allow_rasterization
326-
def draw(self, renderer):
327-
self.label._transform = self.axes.transData
328-
self.offsetText._transform = self.axes.transData
329-
renderer.open_group("axis3d", gid=self.get_gid())
330325

331-
ticks = self._update_ticks()
332-
333-
# Get general axis information:
326+
def _axmask(self):
334327
info = self._axinfo
335328
index = info["i"]
336-
juggled = info["juggled"]
329+
axmask = [True, True, True]
330+
axmask[index] = False
331+
return axmask
337332

333+
334+
def _draw_ticks(self, renderer, edgep1, deltas_per_point):
338335
mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer)
336+
ticks = self._update_ticks()
337+
info = self._axinfo
338+
index = info["i"]
339339

340-
minmax = np.where(highs, maxs, mins)
341-
maxmin = np.where(~highs, maxs, mins)
340+
# Draw ticks:
341+
tickdir = self._get_tickdir()
342+
tickdelta = deltas[tickdir] if highs[tickdir] else -deltas[tickdir]
342343

343-
# Create edge points for the black bolded axis line:
344-
edgep1, edgep2 = self._get_axis_line_edge_points(minmax, maxmin)
344+
tick_info = info['tick']
345+
tick_out = tick_info['outward_factor'] * tickdelta
346+
tick_in = tick_info['inward_factor'] * tickdelta
347+
tick_lw = tick_info['linewidth']
348+
edgep1_tickdir = edgep1[tickdir]
349+
out_tickdir = edgep1_tickdir + tick_out
350+
in_tickdir = edgep1_tickdir - tick_in
345351

346-
# Project the edge points along the current position and
347-
# create the line:
348-
pep = proj3d._proj_trans_points([edgep1, edgep2], self.axes.M)
349-
pep = np.asarray(pep)
350-
self.line.set_data(pep[0], pep[1])
351-
self.line.draw(renderer)
352+
default_label_offset = 8. # A rough estimate
353+
points = deltas_per_point * deltas
354+
for tick in ticks:
355+
# Get tick line positions
356+
pos = edgep1.copy()
357+
pos[index] = tick.get_loc()
358+
pos[tickdir] = out_tickdir
359+
x1, y1, z1 = proj3d.proj_transform(*pos, self.axes.M)
360+
pos[tickdir] = in_tickdir
361+
x2, y2, z2 = proj3d.proj_transform(*pos, self.axes.M)
352362

353-
# Draw labels
354-
# The transAxes transform is used because the Text object
355-
# rotates the text relative to the display coordinate system.
356-
# Therefore, if we want the labels to remain parallel to the
357-
# axis regardless of the aspect ratio, we need to convert the
358-
# edge points of the plane to display coordinates and calculate
359-
# an angle from that.
360-
# TODO: Maybe Text objects should handle this themselves?
361-
dx, dy = (self.axes.transAxes.transform([pep[0:2, 1]]) -
362-
self.axes.transAxes.transform([pep[0:2, 0]]))[0]
363+
# Get position of label
364+
labeldeltas = (tick.get_pad() + default_label_offset) * points
363365

364-
lxyz = 0.5 * (edgep1 + edgep2)
366+
pos[tickdir] = edgep1_tickdir
367+
pos = _move_from_center(pos, centers, labeldeltas, self._axmask())
368+
lx, ly, lz = proj3d.proj_transform(*pos, self.axes.M)
365369

366-
# A rough estimate; points are ambiguous since 3D plots rotate
367-
reltoinches = self.figure.dpi_scale_trans.inverted()
368-
ax_inches = reltoinches.transform(self.axes.bbox.size)
369-
ax_points_estimate = sum(72. * ax_inches)
370-
deltas_per_point = 48 / ax_points_estimate
371-
default_offset = 21.
372-
labeldeltas = (
373-
(self.labelpad + default_offset) * deltas_per_point * deltas)
374-
axmask = [True, True, True]
375-
axmask[index] = False
376-
lxyz = _move_from_center(lxyz, centers, labeldeltas, axmask)
377-
tlx, tly, tlz = proj3d.proj_transform(*lxyz, self.axes.M)
378-
self.label.set_position((tlx, tly))
379-
if self.get_rotate_label(self.label.get_text()):
380-
angle = art3d._norm_text_angle(np.rad2deg(np.arctan2(dy, dx)))
381-
self.label.set_rotation(angle)
382-
self.label.set_va(info['label']['va'])
383-
self.label.set_ha(info['label']['ha'])
384-
self.label.set_rotation_mode(info['label']['rotation_mode'])
385-
self.label.draw(renderer)
370+
_tick_update_position(tick, (x1, x2), (y1, y2), (lx, ly))
371+
tick.tick1line.set_linewidth(tick_lw[tick._major])
372+
tick.draw(renderer)
386373

387-
# Draw Offset text
374+
375+
def _draw_offset_text(self, renderer, edgep1, edgep2, labeldeltas, pep, dx, dy):
376+
mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer)
377+
378+
# Get general axis information:
379+
info = self._axinfo
380+
index = info["i"]
381+
juggled = info["juggled"]
388382

389383
# Which of the two edge points do we want to
390384
# use for locating the offset text?
@@ -395,7 +389,7 @@ def draw(self, renderer):
395389
outeredgep = edgep2
396390
outerindex = 1
397391

398-
pos = _move_from_center(outeredgep, centers, labeldeltas, axmask)
392+
pos = _move_from_center(outeredgep, centers, labeldeltas, self._axmask())
399393
olx, oly, olz = proj3d.proj_transform(*pos, self.axes.M)
400394
self.offsetText.set_text(self.major.formatter.get_offset())
401395
self.offsetText.set_position((olx, oly))
@@ -448,39 +442,74 @@ def draw(self, renderer):
448442
self.offsetText.set_ha(align)
449443
self.offsetText.draw(renderer)
450444

451-
# Draw ticks:
452-
tickdir = self._get_tickdir()
453-
tickdelta = deltas[tickdir] if highs[tickdir] else -deltas[tickdir]
454445

455-
tick_info = info['tick']
456-
tick_out = tick_info['outward_factor'] * tickdelta
457-
tick_in = tick_info['inward_factor'] * tickdelta
458-
tick_lw = tick_info['linewidth']
459-
edgep1_tickdir = edgep1[tickdir]
460-
out_tickdir = edgep1_tickdir + tick_out
461-
in_tickdir = edgep1_tickdir - tick_in
446+
def _draw_labels(self, renderer, edgep1, edgep2, labeldeltas, dx, dy):
447+
info = self._axinfo
448+
mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer)
462449

463-
default_label_offset = 8. # A rough estimate
464-
points = deltas_per_point * deltas
465-
for tick in ticks:
466-
# Get tick line positions
467-
pos = edgep1.copy()
468-
pos[index] = tick.get_loc()
469-
pos[tickdir] = out_tickdir
470-
x1, y1, z1 = proj3d.proj_transform(*pos, self.axes.M)
471-
pos[tickdir] = in_tickdir
472-
x2, y2, z2 = proj3d.proj_transform(*pos, self.axes.M)
450+
# Draw labels
451+
lxyz = 0.5 * (edgep1 + edgep2)
452+
lxyz = _move_from_center(lxyz, centers, labeldeltas, self._axmask())
453+
tlx, tly, tlz = proj3d.proj_transform(*lxyz, self.axes.M)
454+
self.label.set_position((tlx, tly))
455+
if self.get_rotate_label(self.label.get_text()):
456+
angle = art3d._norm_text_angle(np.rad2deg(np.arctan2(dy, dx)))
457+
self.label.set_rotation(angle)
458+
self.label.set_va(info['label']['va'])
459+
self.label.set_ha(info['label']['ha'])
460+
self.label.set_rotation_mode(info['label']['rotation_mode'])
461+
self.label.draw(renderer)
473462

474-
# Get position of label
475-
labeldeltas = (tick.get_pad() + default_label_offset) * points
476463

477-
pos[tickdir] = edgep1_tickdir
478-
pos = _move_from_center(pos, centers, labeldeltas, axmask)
479-
lx, ly, lz = proj3d.proj_transform(*pos, self.axes.M)
464+
@artist.allow_rasterization
465+
def draw(self, renderer):
466+
self.label._transform = self.axes.transData
467+
self.offsetText._transform = self.axes.transData
468+
renderer.open_group("axis3d", gid=self.get_gid())
480469

481-
_tick_update_position(tick, (x1, x2), (y1, y2), (lx, ly))
482-
tick.tick1line.set_linewidth(tick_lw[tick._major])
483-
tick.draw(renderer)
470+
# Get general axis information:
471+
mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer)
472+
473+
minmax = np.where(highs, maxs, mins)
474+
maxmin = np.where(~highs, maxs, mins)
475+
476+
# Create edge points for the black bolded axis line:
477+
edgep1, edgep2 = self._get_axis_line_edge_points(minmax, maxmin)
478+
479+
# Draw the lines
480+
# Project the edge points along the current position
481+
pep = proj3d._proj_trans_points([edgep1, edgep2], self.axes.M)
482+
pep = np.asarray(pep)
483+
self.line.set_data(pep[0], pep[1])
484+
self.line.draw(renderer)
485+
486+
# Calculate offset distances
487+
# A rough estimate; points are ambiguous since 3D plots rotate
488+
reltoinches = self.figure.dpi_scale_trans.inverted()
489+
ax_inches = reltoinches.transform(self.axes.bbox.size)
490+
ax_points_estimate = sum(72. * ax_inches)
491+
deltas_per_point = 48 / ax_points_estimate
492+
default_offset = 21.
493+
labeldeltas = (
494+
(self.labelpad + default_offset) * deltas_per_point * deltas)
495+
# The transAxes transform is used because the Text object
496+
# rotates the text relative to the display coordinate system.
497+
# Therefore, if we want the labels to remain parallel to the
498+
# axis regardless of the aspect ratio, we need to convert the
499+
# edge points of the plane to display coordinates and calculate
500+
# an angle from that.
501+
# TODO: Maybe Text objects should handle this themselves?
502+
dx, dy = (self.axes.transAxes.transform([pep[0:2, 1]]) -
503+
self.axes.transAxes.transform([pep[0:2, 0]]))[0]
504+
505+
# Draw labels
506+
self._draw_labels(renderer, edgep1, edgep2, labeldeltas, dx, dy)
507+
508+
# Draw Offset text
509+
self._draw_offset_text(renderer, edgep1, edgep2, labeldeltas, pep, dx, dy)
510+
511+
# Draw ticks
512+
self._draw_ticks(renderer, edgep1, deltas_per_point)
484513

485514
renderer.close_group('axis3d')
486515
self.stale = False

0 commit comments

Comments
 (0)