Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c9cbc00

Browse filesBrowse files
committed
added twin axes patch
svn path=/trunk/matplotlib/; revision=886
1 parent 0cac5dc commit c9cbc00
Copy full SHA for c9cbc00

File tree

Expand file treeCollapse file tree

4 files changed

+159
-32
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+159
-32
lines changed

‎examples/two_scales.py

Copy file name to clipboardExpand all lines: examples/two_scales.py
+7-7Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@
1919
from pylab import *
2020

2121
ax1 = subplot(111)
22-
t = arange(0.0, 10.0, 0.01)
22+
t = arange(0.01, 10.0, 0.01)
2323
s1 = exp(t)
2424
plot(t, s1, 'b-')
25-
ax1.yaxis.tick_left()
25+
xlabel('time (s)')
26+
ylabel('exp')
2627

2728

2829
# turn off the 2nd axes rectangle with frameon kwarg
29-
ax2 = subplot(111, frameon=False)
30+
ax2 = twin()
3031
s2 = sin(2*pi*t)
3132
plot(t, s2, 'r.')
32-
ax2.yaxis.tick_right()
33-
34-
35-
xlabel('time (s)')
33+
ylabel('sin')
34+
xlim(0.01, 10)
35+
set(gca(), xscale='log')
3636

3737
show()

‎lib/matplotlib/axes.py

Copy file name to clipboardExpand all lines: lib/matplotlib/axes.py
+51-2Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,14 @@ def _grab_next_args(self, *args, **kwargs):
284284
remaining=remaining[2:]
285285
#yield self._plot_2_args(remaining[:2])
286286
#remaining=args[2:]
287-
287+
288+
BinOpType=type(zero())
289+
def makeValue(v):
290+
if type(v) == BinOpType:
291+
return v
292+
else:
293+
return Value(v)
294+
288295

289296

290297
class Axes(Artist):
@@ -304,7 +311,7 @@ def __init__(self, fig, rect,
304311
axisbg = None, # defaults to rc axes.facecolor
305312
frameon = True):
306313
Artist.__init__(self)
307-
self._position = [Value(val) for val in rect]
314+
self._position = map(makeValue, rect)
308315
self.set_figure(fig)
309316

310317
if axisbg is None: axisbg = rcParams['axes.facecolor']
@@ -3639,3 +3646,45 @@ def __init__(self, fig, *args, **kwargs):
36393646
SubplotBase.__init__(self, *args)
36403647
PolarAxes.__init__(self, fig, [self.figLeft, self.figBottom, self.figW, self.figH], **kwargs)
36413648

3649+
class TwinAxes(Axes):
3650+
"""
3651+
Create an Axes instance that shares the X axis with another:
3652+
3653+
TwinAxes(existing_axes)
3654+
"""
3655+
def __init__(self, axes):
3656+
Axes.__init__(self, axes.figure, axes._position, frameon=False)
3657+
3658+
self._xscale=axes._xscale
3659+
self.fmt_xdata=axes.fmt_xdata
3660+
3661+
vl_left=axes.viewLim.ll().x()
3662+
vl_right=axes.viewLim.ur().x()
3663+
vl_bottom=self.viewLim.ll().y()
3664+
vl_top=self.viewLim.ur().y()
3665+
self.viewLim=Bbox(Point(vl_left,vl_bottom),Point(vl_right, vl_top))
3666+
3667+
dl_left=axes.dataLim.ll().x()
3668+
dl_right=axes.dataLim.ur().x()
3669+
dl_bottom=self.dataLim.ll().y()
3670+
dl_top=self.dataLim.ur().y()
3671+
self.dataLim=Bbox(Point(dl_left,dl_bottom),Point(dl_right, dl_top))
3672+
3673+
try:
3674+
self.transData = blend_xy_sep_transform(axes.transData, self.transData)
3675+
except RuntimeError:
3676+
raise RuntimeError, "TwinAxes only works with cartesian axes"
3677+
3678+
self.xaxis=axes.xaxis
3679+
3680+
self.yaxis.tick_right()
3681+
self.yaxis.set_label_position('right')
3682+
axes.yaxis.tick_left()
3683+
3684+
def set_figure(self, fig):
3685+
if self.figure is None:
3686+
Axes.set_figure(self, fig)
3687+
return None
3688+
if fig is not self.figure:
3689+
raise RuntimeError, "TwinAxes can only be added to the same figure"
3690+

‎lib/matplotlib/axis.py

Copy file name to clipboardExpand all lines: lib/matplotlib/axis.py
+89-21Lines changed: 89 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ def draw(self, renderer, *args, **kwargs):
473473
if not self.get_visible(): return
474474
renderer.open_group(__name__)
475475
ticklabelBoxes = []
476+
ticklabelBoxes2 = []
476477

477478
majorTicks = self.get_major_ticks()
478479
majorLocs = self._majorLocator()
@@ -491,8 +492,12 @@ def draw(self, renderer, *args, **kwargs):
491492
tick.set_label1(label)
492493
tick.set_label2(label)
493494
tick.draw(renderer)
494-
extent = tick.label1.get_window_extent(renderer)
495-
ticklabelBoxes.append(extent)
495+
if tick.label1On:
496+
extent = tick.label1.get_window_extent(renderer)
497+
ticklabelBoxes.append(extent)
498+
if tick.label2On:
499+
extent = tick.label2.get_window_extent(renderer)
500+
ticklabelBoxes2.append(extent)
496501

497502
minorTicks = self.get_minor_ticks()
498503
minorLocs = self._minorLocator()
@@ -508,8 +513,12 @@ def draw(self, renderer, *args, **kwargs):
508513
tick.set_label(label)
509514

510515
tick.draw(renderer)
511-
extent = tick.label1.get_window_extent(renderer)
512-
ticklabelBoxes.append(extent)
516+
if tick.label1On:
517+
extent = tick.label1.get_window_extent(renderer)
518+
ticklabelBoxes.append(extent)
519+
if tick.label2On:
520+
extent = tick.label2.get_window_extent(renderer)
521+
ticklabelBoxes2.append(extent)
513522

514523

515524

@@ -519,7 +528,7 @@ def draw(self, renderer, *args, **kwargs):
519528
# the actual bbox
520529

521530

522-
self._update_label_postion(ticklabelBoxes)
531+
self._update_label_postion(ticklabelBoxes, ticklabelBoxes2)
523532

524533
self.label.draw(renderer) # memory leak here, vertical text
525534

@@ -750,25 +759,54 @@ def _get_label(self):
750759
identity_transform() ))
751760

752761
self._set_artist_props(label)
762+
self.label_position='bottom'
753763
return label
754764

765+
def get_label_position(self):
766+
"""
767+
Return the label position (top or bottom)
768+
"""
769+
return self.label_position
755770

756-
def _update_label_postion(self, bboxes):
771+
def set_label_position(self, position):
772+
"""
773+
Set the label position (top or bottom)
774+
775+
ACCEPTS: [ 'top' | 'bottom' ]
776+
"""
777+
assert position == 'top' or position == 'bottom'
778+
if position == 'top':
779+
self.label.set_verticalalignment('bottom')
780+
else:
781+
self.label.set_verticalalignment('top')
782+
self.label_position=position
783+
784+
def _update_label_postion(self, bboxes, bboxes2):
757785
"""
758786
Update the label position based on the sequence of bounding
759787
boxes of all the ticklabels
760788
"""
761789

762790
x,y = self.label.get_position()
763-
if not len(bboxes):
764-
bottom = self.axes.bbox.ymin()
791+
if self.label_position == 'bottom':
792+
if not len(bboxes):
793+
bottom = self.axes.bbox.ymin()
794+
else:
795+
796+
bbox = bbox_all(bboxes)
797+
bottom = bbox.ymin()
798+
799+
self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0))
800+
765801
else:
802+
if not len(bboxes2):
803+
top = self.axes.bbox.ymax()
804+
else:
766805

767-
bbox = bbox_all(bboxes)
768-
bottom = bbox.ymin()
806+
bbox = bbox_all(bboxes2)
807+
top = bbox.ymax()
769808

770-
self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0))
771-
809+
self.label.set_position( (x, top+self.LABELPAD*self.figure.dpi.get()/72.0))
772810

773811
def tick_top(self):
774812
'use ticks only on top'
@@ -822,24 +860,54 @@ def _get_label(self):
822860
self.axes.transAxes) )
823861

824862
self._set_artist_props(label)
863+
self.label_position='left'
825864
return label
826865

827-
def _update_label_postion(self, bboxes):
866+
def get_label_position(self):
867+
"""
868+
Return the label position (left or right)
869+
"""
870+
return self.label_position
871+
872+
def set_label_position(self, position):
873+
"""
874+
Set the label position (left or right)
875+
876+
ACCEPTS: [ 'left' | 'right' ]
877+
"""
878+
assert position == 'left' or position == 'right'
879+
if position == 'right':
880+
self.label.set_horizontalalignment('left')
881+
else:
882+
self.label.set_horizontalalignment('right')
883+
self.label_position=position
884+
885+
def _update_label_postion(self, bboxes, bboxes2):
828886
"""
829887
Update the label position based on the sequence of bounding
830-
boxes overlaps of all the ticklabels that overlap the current
831-
ticklabel. overlaps are the bounding boxes of the ticklabels
888+
boxes of all the ticklabels
832889
"""
833890

834891
x,y = self.label.get_position()
835-
if not len(bboxes):
836-
left = self.axes.bbox.xmin()
837-
else:
838-
bbox = bbox_all(bboxes)
839-
left = bbox.xmin()
840-
self.label.set_position((left - self.figure.dpi.get()*self.LABELPAD/72.0,y))
892+
if self.label_position == 'left':
893+
if not len(bboxes):
894+
left = self.axes.bbox.xmin()
895+
else:
841896

897+
bbox = bbox_all(bboxes)
898+
left = bbox.xmin()
899+
900+
self.label.set_position( (left-self.LABELPAD*self.figure.dpi.get()/72.0, y))
842901

902+
else:
903+
if not len(bboxes2):
904+
right = self.axes.bbox.xmax()
905+
else:
906+
907+
bbox = bbox_all(bboxes2)
908+
right = bbox.xmax()
909+
910+
self.label.set_position( (right+self.LABELPAD*self.figure.dpi.get()/72.0, y))
843911

844912
def tick_right(self):
845913
'use ticks only on right'

‎lib/matplotlib/pylab.py

Copy file name to clipboardExpand all lines: lib/matplotlib/pylab.py
+12-2Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@
187187
import _pylab_helpers
188188
import mlab #so I can override hist, psd, etc...
189189

190-
from axes import Axes, PolarAxes
190+
from axes import Axes, PolarAxes, TwinAxes
191191
from backends import new_figure_manager, error_msg, \
192192
draw_if_interactive, show
193193

@@ -1236,6 +1236,16 @@ def subplot(*args, **kwargs):
12361236
return a
12371237

12381238

1239+
def twin(axes=None):
1240+
if axes is None:
1241+
axes=gca()
1242+
1243+
tw=TwinAxes(axes)
1244+
gcf().add_axes(tw)
1245+
draw_if_interactive()
1246+
return tw
1247+
1248+
12391249
def title(s, *args, **kwargs):
12401250
"""
12411251
Set the title of the current axis to s
@@ -2466,7 +2476,7 @@ def winter():
24662476
'axes', 'delaxes', 'clim', 'close', 'clf', 'colorbar', 'draw',
24672477
'figtext', 'figimage', 'figlegend', 'figure', 'gca', 'gcf', 'gci',
24682478
'get', 'hold', 'ishold', 'isinteractive', 'imread', 'load', 'rc',
2469-
'rcdefaults', 'save', 'savefig', 'set', 'subplot', 'title',
2479+
'rcdefaults', 'save', 'savefig', 'set', 'subplot', 'twin', 'title',
24702480
'xlabel', 'ylabel', 'xlim', 'ylim', 'xticks', 'rgrids',
24712481
'thetagrids', 'yticks', 'polar', 'over', 'ioff', 'ion', 'axhline',
24722482
'axhspan', 'axvline', 'axvspan', 'bar', 'barh', 'cohere',

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.