@@ -1617,16 +1617,16 @@ def number(self, num):
16171617
16181618
16191619# TODO: More systematic approach?
1620- dualxy_kwargs = (
1620+ _twin_kwargs = (
16211621 'label' , 'locator' , 'formatter' , 'ticks' , 'ticklabels' ,
16221622 'minorlocator' , 'minorticks' , 'tickminor' ,
16231623 'ticklen' , 'tickrange' , 'tickdir' , 'ticklabeldir' , 'tickrotation' ,
1624- 'bounds' , 'margin' , 'color' , 'grid' , 'gridminor' ,
1624+ 'bounds' , 'margin' , 'color' , 'linewidth' , ' grid' , 'gridminor' , 'gridcolor ' ,
16251625 'locator_kw' , 'formatter_kw' , 'minorlocator_kw' , 'label_kw' ,
16261626)
16271627
1628- dualxy_descrip = """
1629- Makes a secondary *%(x)s* axis for denoting equivalent *%(x)s*
1628+ _dual_doc = """
1629+ Return a secondary *%(x)s* axis for denoting equivalent *%(x)s*
16301630coordinates in *alternate units*.
16311631
16321632Parameters
@@ -1641,11 +1641,20 @@ def number(self, num):
16411641 Prepended with ``'%(x)s'`` and passed to `Axes.format`.
16421642"""
16431643
1644- altxy_descrip = """
1645- Alias and more intuitive name for `~XYAxes.twin%(y)s`.
1646- The matplotlib `~matplotlib.axes.Axes.twin%(y)s` function
1647- generates two *%(x)s* axes with a shared ("twin") *%(y)s* axis.
1648- Enforces the following settings.
1644+ _alt_doc = """
1645+ Return an axes in the same location as this one but whose %(x)s axis is on
1646+ the %(x2)s. This is an alias and more intuitive name for
1647+ `~CartesianAxes.twin%(y)s`, which generates two *%(x)s* axes with
1648+ a shared ("twin") *%(y)s* axes.
1649+
1650+ Parameters
1651+ ----------
1652+ %(args)s : optional
1653+ Prepended with ``'%(x)s'`` and passed to `Axes.format`.
1654+
1655+ Note
1656+ ----
1657+ This function enforces the following settngs.
16491658
16501659* Places the old *%(x)s* axis on the %(x1)s and the new *%(x)s* axis
16511660 on the %(x2)s.
@@ -1655,11 +1664,20 @@ def number(self, num):
16551664 according to the visible spine positions.
16561665* Locks the old and new *%(y)s* axis limits and scales, and makes the new
16571666 %(y)s axis labels invisible.
1667+
16581668"""
16591669
1660- twinxy_descrip = """
1661- Mimics matplotlib's `~matplotlib.axes.Axes.twin%(y)s`.
1662- Enforces the following settings.
1670+ _twin_doc = """
1671+ Mimics the builtin `~matplotlib.axes.Axes.twin%(y)s` method.
1672+
1673+ Parameters
1674+ ----------
1675+ %(args)s : optional
1676+ Prepended with ``'%(x)s'`` and passed to `Axes.format`.
1677+
1678+ Note
1679+ ----
1680+ This function enforces the following settngs.
16631681
16641682* Places the old *%(x)s* axis on the %(x1)s and the new *%(x)s* axis
16651683 on the %(x2)s.
@@ -1672,28 +1690,24 @@ def number(self, num):
16721690"""
16731691
16741692
1675- def _parse_dualxy_args (x , kwargs ):
1676- """Detect `~XYAxes.format` arguments with the leading ``x`` or ``y``
1677- removed. Translate to valid `~XYAxes.format` arguments."""
1678- kwargs_bad = {}
1679- for key in (* kwargs .keys (),):
1680- value = kwargs .pop (key )
1681- if key [0 ] == x and key [1 :] in dualxy_kwargs :
1693+ def _parse_alt (x , kwargs ):
1694+ """Interpret keyword args passed to all "twin axis" methods so they
1695+ can be passed to Axes.format."""
1696+ kw_bad , kw_out = {}, {}
1697+ for key , value in kwargs .items ():
1698+ if key in _twin_kwargs :
1699+ kw_out [x + key ] = value
1700+ elif key [0 ] == x and key [1 :] in _twin_kwargs :
16821701 _warn_proplot (
1683- f'dual{ x } () keyword arg { key !r} is deprecated. '
1684- f'Use { key [1 :]!r} instead.'
1685- )
1686- kwargs [key ] = value
1687- elif key in dualxy_kwargs :
1688- kwargs [x + key ] = value
1702+ f'Twin axis keyword arg { key !r} is deprecated. '
1703+ f'Use { key [1 :]!r} instead.' )
1704+ kw_out [key ] = value
16891705 elif key in RC_NODOTSNAMES :
1690- kwargs [key ] = value
1706+ kw_out [key ] = value
16911707 else :
1692- kwargs_bad [key ] = value
1693- if kwargs_bad :
1694- raise TypeError (
1695- f'dual{ x } () got unexpected keyword argument(s): { kwargs_bad } '
1696- )
1708+ kw_bad [key ] = value
1709+ if kw_bad :
1710+ raise TypeError (f'Unexpected keyword argument(s): { kw_bad !r} ' )
16971711 return kwargs
16981712
16991713
@@ -1757,7 +1771,7 @@ def __init__(self, *args, **kwargs):
17571771 self ._dualx_cache = None
17581772
17591773 def _altx_overrides (self ):
1760- """Applies alternate *x* axis overrides."""
1774+ """Apply alternate *x* axis overrides."""
17611775 # Unlike matplotlib API, we strong arm user into certain twin axes
17621776 # settings... doesn't really make sense to have twin axes without this
17631777 if self ._altx_child is not None : # altx was called on this axes
@@ -1777,7 +1791,7 @@ def _altx_overrides(self):
17771791 self .patch .set_visible (False )
17781792
17791793 def _alty_overrides (self ):
1780- """Applies alternate *y* axis overrides."""
1794+ """Apply alternate *y* axis overrides."""
17811795 if self ._alty_child is not None :
17821796 self ._shared_x_axes .join (self , self ._alty_child )
17831797 self .spines ['right' ].set_visible (False )
@@ -1878,6 +1892,19 @@ def _hide_labels(self):
18781892 # Enforce no minor ticks labels. TODO: Document?
18791893 axis .set_minor_formatter (mticker .NullFormatter ())
18801894
1895+ def _make_twin_axes (self , * args , ** kwargs ):
1896+ """Return a twin of this axes. This is used for twinx and twiny and was
1897+ copied from matplotlib in case the private API changes."""
1898+ # Typically, SubplotBase._make_twin_axes is called instead of this.
1899+ # There is also an override in axes_grid1/axes_divider.py.
1900+ if 'sharex' in kwargs and 'sharey' in kwargs :
1901+ raise ValueError ('Twinned Axes may share only one axis.' )
1902+ ax2 = self .figure .add_axes (self .get_position (True ), * args , ** kwargs )
1903+ self .set_adjustable ('datalim' )
1904+ ax2 .set_adjustable ('datalim' )
1905+ self ._twinned_axes .join (self , ax2 )
1906+ return ax2
1907+
18811908 def _sharex_setup (self , sharex , level ):
18821909 """Sets up shared axes. The input is the 'parent' axes, from which
18831910 this one will draw its properties."""
@@ -2574,8 +2601,8 @@ def _grid_dict(grid):
25742601 self .set_aspect (aspect )
25752602 super ().format (** kwargs )
25762603
2577- def altx (self ):
2578- # TODO: Accept format **kwargs? Is this already in #50?
2604+ def altx (self , ** kwargs ):
2605+ """Docstring is replaced below."""
25792606 # Cannot wrap twiny() because we want to use XYAxes, not
25802607 # matplotlib Axes. Instead use hidden method _make_twin_axes.
25812608 # See https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_subplots.py # noqa
@@ -2591,9 +2618,11 @@ def altx(self):
25912618 ax ._altx_overrides ()
25922619 self .add_child_axes (ax ) # to facilitate tight layout
25932620 self .figure ._axstack .remove (ax ) # or gets drawn twice!
2621+ ax .format (** _parse_alt ('x' , kwargs ))
25942622 return ax
25952623
2596- def alty (self ):
2624+ def alty (self , ** kwargs ):
2625+ """Docstring is replaced below."""
25972626 if self ._alty_child or self ._alty_parent :
25982627 raise RuntimeError ('No more than *two* twin axes are allowed.' )
25992628 with self .figure ._authorize_add_subplot ():
@@ -2606,23 +2635,26 @@ def alty(self):
26062635 ax ._alty_overrides ()
26072636 self .add_child_axes (ax ) # to facilitate tight layout
26082637 self .figure ._axstack .remove (ax ) # or gets drawn twice!
2638+ ax .format (** _parse_alt ('y' , kwargs ))
26092639 return ax
26102640
26112641 def dualx (self , arg , ** kwargs ):
2642+ """Docstring is replaced below."""
26122643 # NOTE: Matplotlib 3.1 has a 'secondary axis' feature. For the time
26132644 # being, our version is more robust (see FuncScale) and simpler, since
26142645 # we do not create an entirely separate _SecondaryAxis class.
26152646 ax = self .altx ()
26162647 self ._dualx_arg = arg
26172648 self ._dualx_overrides ()
2618- ax .format (** _parse_dualxy_args ( 'x' , kwargs ) )
2649+ ax .format (** kwargs )
26192650 return ax
26202651
26212652 def dualy (self , arg , ** kwargs ):
2653+ """Docstring is replaced below."""
26222654 ax = self .alty ()
26232655 self ._dualy_arg = arg
26242656 self ._dualy_overrides ()
2625- ax .format (** _parse_dualxy_args ( 'y' , kwargs ) )
2657+ ax .format (** kwargs )
26262658 return ax
26272659
26282660 def draw (self , renderer = None , * args , ** kwargs ):
@@ -2653,32 +2685,39 @@ def get_tightbbox(self, renderer, *args, **kwargs):
26532685 return super ().get_tightbbox (renderer , * args , ** kwargs )
26542686
26552687 def twinx (self ):
2688+ """Docstring is replaced below."""
26562689 return self .alty ()
26572690
26582691 def twiny (self ):
2692+ """Docstring is replaced below."""
26592693 return self .altx ()
26602694
2661- altx .__doc__ = altxy_descrip % {
2695+ # Add documentation
2696+ altx .__doc__ = _alt_doc % {
26622697 'x' : 'x' , 'x1' : 'bottom' , 'x2' : 'top' ,
26632698 'y' : 'y' , 'y1' : 'left' , 'y2' : 'right' ,
2699+ 'args' : ', ' .join (_twin_kwargs ),
26642700 }
2665- alty .__doc__ = altxy_descrip % {
2701+ alty .__doc__ = _alt_doc % {
26662702 'x' : 'y' , 'x1' : 'left' , 'x2' : 'right' ,
26672703 'y' : 'x' , 'y1' : 'bottom' , 'y2' : 'top' ,
2704+ 'args' : ', ' .join (_twin_kwargs ),
26682705 }
2669- dualx .__doc__ = dualxy_descrip % {
2670- 'x' : 'x' , 'args' : ', ' .join (dualxy_kwargs )
2671- }
2672- dualy .__doc__ = dualxy_descrip % {
2673- 'x' : 'y' , 'args' : ', ' .join (dualxy_kwargs )
2674- }
2675- twinx .__doc__ = twinxy_descrip % {
2706+ twinx .__doc__ = _twin_doc % {
26762707 'x' : 'y' , 'x1' : 'left' , 'x2' : 'right' ,
26772708 'y' : 'x' , 'y1' : 'bottom' , 'y2' : 'top' ,
2709+ 'args' : ', ' .join (_twin_kwargs ),
26782710 }
2679- twiny .__doc__ = twinxy_descrip % {
2711+ twiny .__doc__ = _twin_doc % {
26802712 'x' : 'x' , 'x1' : 'bottom' , 'x2' : 'top' ,
26812713 'y' : 'y' , 'y1' : 'left' , 'y2' : 'right' ,
2714+ 'args' : ', ' .join (_twin_kwargs ),
2715+ }
2716+ dualx .__doc__ = _dual_doc % {
2717+ 'x' : 'x' , 'args' : ', ' .join (_twin_kwargs )
2718+ }
2719+ dualy .__doc__ = _dual_doc % {
2720+ 'x' : 'y' , 'args' : ', ' .join (_twin_kwargs )
26822721 }
26832722
26842723
0 commit comments