10000 Implement 3d axis positions · matplotlib/matplotlib@7be6747 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7be6747

Browse files
Implement 3d axis positions
1 parent 7762bff commit 7be6747

File tree

1 file changed

+64
-38
lines changed

1 file changed

+64
-38
lines changed

lib/mpl_toolkits/mplot3d/axis3d.py

Lines changed: 64 additions & 38 deletions
< 10000 td data-grid-cell-id="diff-ea1dd4bc7c3b7c0078e69e41e916d25354864e4f2fe31fd71210477f6f9f9660-264-265-1" data-selected="false" role="gridcell" style="background-color:var(--diffBlob-additionNum-bgColor, var(--diffBlob-addition-bgColor-num));text-align:center" tabindex="-1" valign="top" class="focusable-grid-cell diff-line-number position-relative left-side">265
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ def __init__(self, *args, **kwargs):
7676

7777
name = self.axis_name
7878

79+
self.position = 'auto'
80+
7981
# This is a temporary member variable.
8082
# Do not depend on this existing in future releases!
8183
self._axinfo = self._AXINFO[name].copy()
@@ -225,8 +227,7 @@ def _get_coord_info(self, renderer):
225227
# Get the mean value for each bound:
226228
centers = 0.5 * (maxs + mins)
227229

228-
# Add a small offset between min/max point and the edge of the
229-
# plot:
230+
# Add a small offset between min/max point and the edge of the plot:
230231
deltas = (maxs - mins) / 12
231232
mins -= 0.25 * deltas
232233
maxs += 0.25 * deltas
@@ -256,19 +257,26 @@ def _get_coord_info(self, renderer):
256257

257258
return mins, maxs, centers, deltas, bounds_proj, highs
258259

259-
def _get_axis_line_edge_points(self, minmax, maxmin):
260+
def _get_axis_line_edge_points(self, minmax, maxmin, position=None):
260261
"""Get the edge points for the black bolded axis line."""
261262
# When changing vertical axis some of the axes has to be
262263
# moved to the other plane so it looks the same as if the z-axis
263264
# was the vertical axis.
264-
mb = [minmax, maxmin]
+
mb = [minmax, maxmin] # line from origin to near invisible corner
265266
mb_rev = mb[::-1]
266267
mm = [[mb, mb_rev, mb_rev], [mb_rev, mb_rev, mb], [mb, mb, mb]]
267268
mm = mm[self.axes._vertical_axis][self._axinfo["i"]]
268269

269270
juggled = self._axinfo["juggled"]
270-
edge_point_0 = mm[0].copy()
271-
edge_point_0[juggled[0]] = mm[1][juggled[0]]
271+
edge_point_0 = mm[0].copy() # origin point
272+
273+
if ( (position == 'lower'
274+
and mm[1][juggled[-1]] < mm[0][juggled[-1]])
275+
or (position == 'upper'
276+
and mm[1][juggled[-1]] > mm[0][juggled[-1]])):
277+
edge_point_0[juggled[-1]] = mm[1][juggled[-1]]
278+
else:
279+
edge_point_0[juggled[0]] = mm[1][juggled[0]]
272280

273281
edge_point_1 = edge_point_0.copy()
274282
edge_point_1[juggled[1]] = mm[1][juggled[1]]
@@ -370,7 +378,8 @@ def _draw_ticks(self, renderer, edgep1, deltas_per_point):
370378
tick.draw(renderer)
371379

372380

373-
def _draw_offset_text(self, renderer, edgep1, edgep2, labeldeltas, pep, dx, dy):
381+
def _draw_offset_text(self, renderer, edgep1, edgep2, labeldeltas, pep,
382+
dx, dy):
374383
mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer)
375384

376385
# Get general axis information:
@@ -387,7 +396,8 @@ def _draw_offset_text(self, renderer, edgep1, edgep2, labeldeltas, pep, dx, dy):
387396
outeredgep = edgep2
388397
outerindex = 1
389398

390-
pos = _move_from_center(outeredgep, centers, labeldeltas, self._axmask())
399+
pos = _move_from_center(outeredgep, centers, labeldeltas,
400+
self._axmask())
391401
olx, oly, olz = proj3d.proj_transform(*pos, self.axes.M)
392402
self.offsetText.set_text(self.major.formatter.get_offset())
393403
self.offsetText.set_position((olx, oly))
@@ -467,19 +477,6 @@ def draw(self, renderer):
467477
# Get general axis information:
468478
mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer)
469479

470-
minmax = np.where(highs, maxs, mins)
471-
maxmin = np.where(~highs, maxs, mins)
472-
473-
# Create edge points for the black bolded axis line:
474-
edgep1, edgep2 = self._get_axis_line_edge_points(minmax, maxmin)
475-
476-
# Draw the lines
477-
# Project the edge points along the current position
478-
pep = proj3d._proj_trans_points([edgep1, edgep2], self.axes.M)
479-
pep = np.asarray(pep)
480-
self.line.set_data(pep[0], pep[1])
481-
self.line.draw(renderer)
482-
483480
# Calculate offset distances
484481
# A rough estimate; points are ambiguous since 3D plots rotate
485482
reltoinches = self.figure.dpi_scale_trans.inverted()
@@ -489,24 +486,53 @@ def draw(self, renderer):
489486
default_offset = 21.
490487
labeldeltas = (
491488
(self.labelpad + default_offset) * deltas_per_point * deltas)
492-
# The transAxes transform is used because the Text object
493-
# rotates the text relative to the display coordinate system.
494-
# Therefore, if we want the labels to remain parallel to the
495-
# axis regardless of the aspect ratio, we need to convert the
496-
# edge points of the plane to display coordinates and calculate
497-
# an angle from that.
498-
# TODO: Maybe Text objects should handle this themselves?
499-
dx, dy = (self.axes.transAxes.transform([pep[0:2, 1]]) -
500-
self.axes.transAxes.transform([pep[0:2, 0]]))[0]
501-
502-
# Draw labels
503-
self._draw_labels(renderer, edgep1, edgep2, labeldeltas, dx, dy)
504489

505-
# Draw Offset text
506-
self._draw_offset_text(renderer, edgep1, edgep2, labeldeltas, pep, dx, dy)
507-
508-
# Draw ticks
509-
self._draw_ticks(renderer, edgep1, deltas_per_point)
490+
# Determine edge points for the axis lines
491+
edgep1s = []
492+
edgep2s = []
493+
minmax = np.where(highs, maxs, mins) # "origin" point
494+
maxmin = np.where(~highs, maxs, mins) # "opposite" corner near camera
495+
if self.position == 'auto':
496+
edgep1, edgep2 = self._get_axis_line_edge_points(minmax, maxmin)
497+
edgep1s = [edgep1]
498+
edgep2s = [edgep2]
499+
else:
500+
edgep1_l, edgep2_l = self._get_axis_line_edge_points(minmax, maxmin, position='lower')
501+
edgep1_u, edgep2_u = self._get_axis_line_edge_points(minmax, maxmin, position='upper')
502+
if self.position in ('lower', 'both'):
503+
edgep1s.append(edgep1_l)
504+
edgep2s.append(edgep2_l)
505+
if self.position in ('upper', 'both'):
506+
edgep1s.append(edgep1_u)
507+
edgep2s.append(edgep2_u)
508+
509+
for edgep1, edgep2 in zip(edgep1s, edgep2s):
510+
# Draw the lines
511+
# Project the edge points along the current position
512+
pep = proj3d._proj_trans_points([edgep1, edgep2], self.axes.M)
513+
pep = np.asarray(pep)
514+
self.line.set_data(pep[0], pep[1])
515+
self.line.draw(renderer)
516+
517+
# The transAxes transform is used because the Text object
518+
# rotates the text relative to the display coordinate system.
519+
# Therefore, if we want the labels to remain parallel to the
520+
# axis regardless of the aspect ratio, we need to convert the
521+
# edge points of the plane to display coordinates and calculate
522+
# an angle from that.
523+
# TODO: Maybe Text objects should handle this themselves?
524+
dx, dy = (self.axes.transAxes.transform([pep[0:2, 1]]) -
525+
self.axes.transAxes.transform([pep[0:2, 0]]))[0]
526+
527+
# Draw labels
528+
self._draw_labels(renderer, edgep1, edgep2, labeldeltas, dx, dy)
529+
530+
# Draw Offset text
531+
self._draw_offset_text(renderer, edgep1, edgep2, labeldeltas, pep,
532+
dx, dy)
533+
534+
# Draw ticks
535+
self._draw_ticks(renderer, edgep1, deltas_per_point)
510536

511537
renderer.close_group('axis3d')
512538
self.stale = False

0 commit comments

Comments
 (0)
0