1414 _add_errorbars , _bar_wrapper , _barh_wrapper , _boxplot_wrapper ,
1515 _cmap_changer , _cycle_changer ,
1616 _fill_between_wrapper , _fill_betweenx_wrapper ,
17- _hist_wrapper , _plot_wrapper , _scatter_wrapper ,
17+ _hist_wrapper , _parametric_wrapper , _plot_wrapper , _scatter_wrapper ,
1818 _standardize_1d , _standardize_2d ,
1919 _text_wrapper , _violinplot_wrapper ,
2020 colorbar_wrapper , legend_wrapper ,
@@ -1506,6 +1506,7 @@ def panel_axes(self, side, **kwargs):
15061506 side = self ._loc_translate (side , 'panel' )
15071507 return self .figure ._add_axes_panel (self , side , ** kwargs )
15081508
1509+ @_parametric_wrapper
15091510 @_standardize_1d
15101511 @_cmap_changer
15111512 def parametric (
@@ -1522,15 +1523,19 @@ def parametric(
15221523
15231524 Parameters
15241525 ----------
1525- *args : (y,) or (x,y )
1526+ *args : (y,), (x, y), or (x, y, values )
15261527 The coordinates. If `x` is not provided, it is inferred from `y`.
1527- cmap : colormap spec, optional
1528- The colormap specifier, passed to `~proplot.constructor.Colormap`.
15291528 values : list of float
15301529 The parametric values used to map points on the line to colors
1531- in the colormap.
1530+ in the colormap. This can also be passed as a third positional argument.
1531+ cmap : colormap spec, optional
1532+ The colormap specifier, passed to `~proplot.constructor.Colormap`.
1533+ cmap_kw : dict, optional
1534+ Keyword arguments passed to `~proplot.constructor.Colormap`.
15321535 norm : normalizer spec, optional
15331536 The normalizer, passed to `~proplot.constructor.Norm`.
1537+ norm_kw : dict, optional
1538+ Keyword arguments passed to `~proplot.constructor.Norm`.
15341539 interp : int, optional
15351540 If greater than ``0``, we interpolate to additional points
15361541 between the `values` coordinates. The number corresponds to the
@@ -1552,74 +1557,35 @@ def parametric(
15521557 The parametric line. See `this matplotlib example \
15531558 <https://matplotlib.org/gallery/lines_bars_and_markers/multicolored_line>`__.
15541559 """
1555- # First error check
1556- # WARNING: So far this only works for 1D *x* and *y* coordinates.
1557- # Cannot draw multiple colormap lines at once
1558- if values is None :
1559- raise ValueError ('Requires a "values" keyword arg.' )
1560- if len (args ) not in (1 , 2 ):
1561- raise ValueError (f'Requires 1-2 arguments, got { len (args )} .' )
1562- y = np .array (args [- 1 ]).squeeze ()
1563- x = np .arange (
1564- y .shape [- 1 ]) if len (args ) == 1 else np .array (args [0 ]).squeeze ()
1565- values = np .array (values ).squeeze ()
1566- if x .ndim != 1 or y .ndim != 1 or values .ndim != 1 :
1567- raise ValueError (
1568- f'x ({ x .ndim } d), y ({ y .ndim } d), and values ({ values .ndim } d)'
1569- ' must be 1-dimensional.'
1570- )
1571- if len (x ) != len (y ) or len (x ) != len (values ) or len (y ) != len (values ):
1572- raise ValueError (
1573- f'{ len (x )} xs, { len (y )} ys, but { len (values )} '
1574- ' colormap values.'
1575- )
1576-
1577- # Interpolate values to allow for smooth gradations between values
1578- # (interp=False) or color switchover halfway between points
1579- # (interp=True). Then optionally interpolate the colormap values.
1580- if interp > 0 :
1581- x , y , values = [], [], []
1582- xorig , yorig , vorig = x , y , values
1583- for j in range (xorig .shape [0 ] - 1 ):
1584- idx = slice (None )
1585- if j + 1 < xorig .shape [0 ] - 1 :
1586- idx = slice (None , - 1 )
1587- x .extend (
1588- np .linspace (xorig [j ], xorig [j + 1 ], interp + 2 )[idx ].flat
1589- )
1590- y .extend (
1591- np .linspace (yorig [j ], yorig [j + 1 ], interp + 2 )[idx ].flat
1592- )
1593- values .extend (
1594- np .linspace (vorig [j ], vorig [j + 1 ], interp + 2 )[idx ].flat
1595- )
1596- x , y , values = np .array (x ), np .array (y ), np .array (values )
1597-
15981560 # Get x/y coordinates and values for points to the 'left' and 'right'
15991561 # of each joint
1562+ x , y = args # standardized by parametric wrapper
1563+ interp # avoid U100 unused argument error (arg is handled by wrapper)
16001564 coords = []
16011565 levels = edges (values )
16021566 for j in range (y .shape [0 ]):
16031567 if j == 0 :
16041568 xleft , yleft = [], []
16051569 else :
1606- xleft = [(x [j - 1 ] + x [j ]) / 2 , x [j ]]
1607- yleft = [(y [j - 1 ] + y [j ]) / 2 , y [j ]]
1570+ xleft = [0.5 * (x [j - 1 ] + x [j ]), x [j ]]
1571+ yleft = [0.5 * (y [j - 1 ] + y [j ]), y [j ]]
16081572 if j + 1 == y .shape [0 ]:
16091573 xright , yright = [], []
16101574 else :
16111575 xleft = xleft [:- 1 ] # prevent repetition when joined with right
16121576 yleft = yleft [:- 1 ]
1613- xright = [x [j ], (x [j + 1 ] + x [j ]) / 2 ]
1614- yright = [y [j ], (y [j + 1 ] + y [j ]) / 2 ]
1577+ xright = [x [j ], 0.5 * (x [j + 1 ] + x [j ])]
1578+ yright = [y [j ], 0.5 * (y [j + 1 ] + y [j ])]
16151579 pleft = np .stack ((xleft , yleft ), axis = 1 )
16161580 pright = np .stack ((xright , yright ), axis = 1 )
16171581 coords .append (np .concatenate ((pleft , pright ), axis = 0 ))
1582+ coords = np .array (coords )
16181583
16191584 # Create LineCollection and update with values
1585+ # NOTE: Default capstyle is butt but this may look weird with vector graphics
16201586 hs = mcollections .LineCollection (
1621- np . array ( coords ) , cmap = cmap , norm = norm ,
1622- linestyles = '-' , capstyle = 'butt' , joinstyle = 'miter'
1587+ coords , cmap = cmap , norm = norm ,
1588+ linestyles = '-' , capstyle = 'butt' , joinstyle = 'miter' ,
16231589 )
16241590 hs .set_array (np .array (values ))
16251591 hs .update ({
0 commit comments