@@ -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 ]
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 ]]
@@ -372,7 +380,8 @@ def _draw_ticks(self, renderer, edgep1, deltas_per_point):
372
380
tick .draw (renderer )
373
381
374
382
375
- def _draw_offset_text (self , renderer , edgep1 , edgep2 , labeldeltas , pep , dx , dy ):
383
+ def _draw_offset_text (self , renderer , edgep1 , edgep2 , labeldeltas , pep ,
384
+ dx , dy ):
376
385
mins , maxs , centers , deltas , tc , highs = self ._get_coord_info (renderer )
377
386
378
387
# Get general axis information:
@@ -389,7 +398,8 @@ def _draw_offset_text(self, renderer, edgep1, edgep2, labeldeltas, pep, dx, dy):
389
398
outeredgep = edgep2
390
399
outerindex = 1
391
400
392
- pos = _move_from_center (outeredgep , centers , labeldeltas , self ._axmask ())
401
+ pos = _move_from_center (outeredgep , centers , labeldeltas ,
402
+ self ._axmask ())
393
403
olx , oly , olz = proj3d .proj_transform (* pos , self .axes .M )
394
404
self .offsetText .set_text (self .major .formatter .get_offset ())
395
405
self .offsetText .set_position ((olx , oly ))
@@ -470,19 +480,6 @@ def draw(self, renderer):
470
480
# Get general axis information:
471
481
mins , maxs , centers , deltas , tc , highs = self ._get_coord_info (renderer )
472
482
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
483
# Calculate offset distances
487
484
# A rough estimate; points are ambiguous since 3D plots rotate
488
485
reltoinches = self .figure .dpi_scale_trans .inverted ()
@@ -492,24 +489,53 @@ def draw(self, renderer):
492
489
default_offset = 21.
493
490
labeldeltas = (
494
491
(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
492
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 )
493
+ # Determine edge points for the axis lines
494
+ edgep1s = []
495
+ edgep2s = []
496
+ minmax = np .where (highs , maxs , mins ) # "origin" point
497
+ maxmin = np .where (~ highs , maxs , mins ) # "opposite" corner near camera
498
+ if self .position == 'auto' :
499
+ edgep1 , edgep2 = self ._get_axis_line_edge_points (minmax , maxmin )
500
+ edgep1s = [edgep1 ]
501
+ edgep2s = [edgep2 ]
502
+ else :
503
+ edgep1_l , edgep2_l = self ._get_axis_line_edge_points (minmax , maxmin , position = 'lower' )
504
+ edgep1_u , edgep2_u = self ._get_axis_line_edge_points (minmax , maxmin , position = 'upper' )
505
+ if self .position in ('lower' , 'both' ):
506
+ edgep1s .append (edgep1_l )
507
+ edgep2s .append (edgep2_l )
508
+ if self .position in ('upper' , 'both' ):
509
+ edgep1s .append (edgep1_u )
510
+ edgep2s .append (edgep2_u )
511
+
512
+ for edgep1 , edgep2 in zip (edgep1s , edgep2s ):
513
+ # Draw the lines
514
+ # Project the edge points along the current position
515
+ pep = proj3d ._proj_trans_points ([edgep1 , edgep2 ], self .axes .M )
516
+ pep = np .asarray (pep )
517
+ self .line .set_data (pep [0 ], pep [1 ])
518
+ self .line .draw (renderer )
519
+
520
+ # The transAxes transform is used because the Text object
521
+ # rotates the text relative to the display coordinate system.
522
+ # Therefore, if we want the labels to remain parallel to the
523
+ # axis regardless of the aspect ratio, we need to convert the
524
+ # edge points of the plane to display coordinates and calculate
525
+ # an angle from that.
526
+ # TODO: Maybe Text objects should handle this themselves?
527
+ dx , dy = (self .axes .transAxes .transform ([pep [0 :2 , 1 ]]) -
528
+ self .axes .transAxes .transform ([pep [0 :2 , 0 ]]))[0 ]
529
+
530
+ # Draw labels
531
+ self ._draw_labels (renderer , edgep1 , edgep2 , labeldeltas , dx , dy )
532
+
533
+ # Draw Offset text
534
+ self ._draw_offset_text (renderer , edgep1 , edgep2 , labeldeltas , pep ,
535
+ dx , dy )
536
+
537
+ # Draw ticks
538
+ self ._draw_ticks (renderer , edgep1 , deltas_per_point )
513
539
514
540
renderer .close_group ('axis3d' )
515
541
self .stale = False
0 commit comments