@@ -76,6 +76,8 @@ def __init__(self, *args, **kwargs):
76
76
77
77
name = self .axis_name
78
78
79
+ self .position = 'auto'
80
+
79
81
# This is a temporary member variable.
80
82
# Do not depend on this existing in future releases!
81
83
self ._axinfo = self ._AXINFO [name ].copy ()
@@ -225,8 +227,7 @@ def _get_coord_info(self, renderer):
225
227
# Get the mean value for each bound:
226
228
centers = 0.5 * (maxs + mins )
227
229
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:
230
231
deltas = (maxs - mins ) / 12
231
232
mins -= 0.25 * deltas
232
233
maxs += 0.25 * deltas
@@ -256,19 +257,26 @@ def _get_coord_info(self, renderer):
256
257
257
258
return mins , maxs , centers , deltas , bounds_proj , highs
258
259
259
- def _get_axis_line_edge_points (self , minmax , maxmin ):
260
+ def _get_axis_line_edge_points (self , minmax , maxmin , position = None ):
260
261
"""Get the edge points for the black bolded axis line."""
261
262
# When changing vertical axis some of the axes has to be
262
263
# moved to the other plane so it looks the same as if the z-axis
263
264
# was the vertical axis.
264
- mb = [minmax , maxmin ]
<
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
+ mb = [minmax , maxmin ] # line from origin to near invisible corner
265
266
mb_rev = mb [::- 1 ]
266
267
mm = [[mb , mb_rev , mb_rev ], [mb_rev , mb_rev , mb ], [mb , mb , mb ]]
267
268
mm = mm [self .axes ._vertical_axis ][self ._axinfo ["i" ]]
268
269
269
270
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 ]]
272
280
273
281
edge_point_1 = edge_point_0 .copy ()
274
282
edge_point_1 [juggled [1 ]] = mm [1 ][juggled [1 ]]
@@ -370,7 +378,8 @@ def _draw_ticks(self, renderer, edgep1, deltas_per_point):
370
378
tick .draw (renderer )
371
379
372
380
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 ):
374
383
mins , maxs , centers , deltas , tc , highs = self ._get_coord_info (renderer )
375
384
376
385
# Get general axis information:
@@ -387,7 +396,8 @@ def _draw_offset_text(self, renderer, edgep1, edgep2, labeldeltas, pep, dx, dy):
387
396
outeredgep = edgep2
388
397
outerindex = 1
389
398
390
- pos = _move_from_center (outeredgep , centers , labeldeltas , self ._axmask ())
399
+ pos = _move_from_center (outeredgep , centers , labeldeltas ,
400
+ self ._axmask ())
391
401
olx , oly , olz = proj3d .proj_transform (* pos , self .axes .M )
392
402
self .offsetText .set_text (self .major .formatter .get_offset ())
393
403
self .offsetText .set_position ((olx , oly ))
@@ -467,19 +477,6 @@ def draw(self, renderer):
467
477
# Get general axis information:
468
478
mins , maxs , centers , deltas , tc , highs = self ._get_coord_info (renderer )
469
479
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
-
483
480
# Calculate offset distances
484
481
# A rough estimate; points are ambiguous since 3D plots rotate
485
482
reltoinches = self .figure .dpi_scale_trans .inverted ()
@@ -489,24 +486,53 @@ def draw(self, renderer):
489
486
default_offset = 21.
490
487
labeldeltas = (
491
488
(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 )
504
489
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 )
510
536
511
537
renderer .close_group ('axis3d' )
512
538
self .stale = False
0 commit comments