Plotting 1D data

ProPlot adds several new features to matplotlib’s plotting commands using the intermediate PlotAxes subclass. For the most part, these additions represent a superset of matplotlib – if you are not interested, you can use the plotting commands just like you always have. This section documents the features added for 1D plotting commands like plot, scatter, and bar.

Standardized arguments

Input arguments passed to 1D plotting commands are now uniformly standardized. For each command, you can optionally omit the dependent variable coordinates, in which case they are inferred from the data (see xarray and pandas integration), or pass 2D dependent or independent variable coordinates, in which case the plotting command is called for each column of the 2D array(s). If coordinates are string labels, they are converted to indices and tick labels using FixedLocator and IndexFormatter. All positional arguments can also be optionally specified as keyword arguments (see the individual command documentation).

Note

By default, when just the x or y axis was explicitly fixed by set_xlim or set_ylim (or, equivalently, by passing xlim or ylim to proplot.axes.CartesianAxes.format), ProPlot ignores the out of bounds data when determining the other axis limits. This can be useful if you wish to restrict the view within a large dataset. To disable this feature, pass inbounds=False to the plotting command or set rc['axes.inbounds'] to False (see also the rc['cmap.inbounds'] setting and the user guide).

[1]:
import proplot as pplt
import numpy as np

N = 5
state = np.random.RandomState(51423)
with pplt.rc.context({'axes.prop_cycle': pplt.Cycle('Grays', N=N, left=0.3)}):
    # Sample data
    x = np.linspace(-5, 5, N)
    y = state.rand(N, 5)
    fig = pplt.figure(share=False)

    # Plot by passing both x and y coordinates
    ax = fig.subplot(121)
    ax.area(x, -1 * y / N, stack=True)
    ax.bar(x, y, linewidth=0, alpha=1, width=0.8)
    ax.plot(x, y + 1, linewidth=2)
    ax.scatter(x, y + 2, marker='s', markersize=5**2)
    ax.format(title='Manual x coordinates')

    # Plot by passing just y coordinates
    # Default x coordinates are inferred from DataFrame,
    # inferred from DataArray, or set to np.arange(0, y.shape[0])
    ax = fig.subplot(122)
    ax.area(-1 * y / N, stack=True)
    ax.bar(y, linewidth=0, alpha=1)
    ax.plot(y + 1, linewidth=2)
    ax.scatter(y + 2, marker='s', markersize=5**2)
    ax.format(title='Auto x coordinates')
    fig.format(xlabel='xlabel', ylabel='ylabel')
    fig.format(suptitle='Standardized input demonstration')
/home/docs/checkouts/readthedocs.org/user_builds/proplot/conda/v0.8.1/lib/python3.8/site-packages/proplot/__init__.py:46: ProPlotWarning: Rebuilding font cache.
  register_fonts(default=True)
_images/1dplots_2_1.svg
[2]:
import proplot as pplt
import numpy as np

# Sample data
cycle = pplt.Cycle('davos', right=0.8)
state = np.random.RandomState(51423)
N, M = 400, 20
xmax = 20
x = np.linspace(0, 100, N)
y = 100 * (state.rand(N, M) - 0.42).cumsum(axis=0)

# Plot the data
fig = pplt.figure(refwidth=2.2, share=False)
axs = fig.subplots([[0, 1, 1, 0], [2, 2, 3, 3]], wratios=(2, 1, 1, 2))
axs[0].axvspan(
    0, xmax, zorder=3, edgecolor='red', facecolor=pplt.set_alpha('red', 0.2),
)
for i, ax in enumerate(axs):
    inbounds = i == 1
    title = f'Manual limits inbounds={inbounds}'
    title += ' (default)' if inbounds else ''
    ax.format(
        xmax=(None if i == 0 else xmax),
        title=('Auto x axis limits' if i == 0 else title),
    )
    ax.plot(x, y, cycle=cycle, inbounds=inbounds)
fig.format(
    xlabel='xlabel',
    ylabel='ylabel',
    suptitle='Auto y limits with in-bounds data'
)
_images/1dplots_3_0.svg

Pandas and xarray integration

The PlotAxes plotting commands are seamlessly integrated with pandas and xarray. If you omit dependent variable coordinates, the plotting command tries to infer them from the pandas.DataFrame or xarray.DataArray. If you did not explicitly set the x or y axis label or legend or colorbar title, the plotting command tries to retrieve them from the pandas.DataFrame or xarray.DataArray. You can also pass a Dataset, DataFrame, or dict to any plotting command using the data keyword, then pass string keys as the data arguments rather than arrays (for example, ax.plot('y', data=dataset) is translated to ax.plot(dataset['y'])). Finally, if you pass pint.Quantitys or xarray.DataArrays containing pint.Quantitys to a plotting command, ProPlot will automatically call setup_matplotlib and apply the unit string formatted as rc.unitformat for the default content labels.

These features restore some of the convenience you get with the builtin pandas and xarray plotting functions. They are also optional – installation of pandas and xarray are not required. All of these features can be disabled by setting rc.autoformat to False or by passing autoformat=False to any plotting command.

[3]:
import xarray as xr
import numpy as np
import pandas as pd

# DataArray
state = np.random.RandomState(51423)
data = (
    np.sin(np.linspace(0, 2 * np.pi, 20))[:, None]
    + state.rand(20, 8).cumsum(axis=1)
)
coords = {
    'x': xr.DataArray(
        np.linspace(0, 1, 20),
        dims=('x',),
        attrs={'long_name': 'distance', 'units': 'km'}
    ),
    'num': xr.DataArray(
        np.arange(0, 80, 10),
        dims=('num',),
        attrs={'long_name': 'parameter'}
    )
}
da = xr.DataArray(
    data, dims=('x', 'num'), coords=coords, name='energy', attrs={'units': 'kJ'}
)

# DataFrame
data = (
    (np.cos(np.linspace(0, 2 * np.pi, 20))**4)[:, None] + state.rand(20, 5) ** 2
)
ts = pd.date_range('1/1/2000', periods=20)
df = pd.DataFrame(data, index=ts, columns=['foo', 'bar', 'baz', 'zap', 'baf'])
df.name = 'data'
df.index.name = 'date'
df.columns.name = 'category'
[4]:
import proplot as pplt
fig = pplt.figure(share=False)
fig.format(suptitle='Automatic subplot formatting')

# Plot DataArray
cycle = pplt.Cycle('dark blue', space='hpl', N=da.shape[1])
ax = fig.subplot(121)
ax.scatter(da, cycle=cycle, lw=3, colorbar='t', colorbar_kw={'locator': 20})

# Plot Dataframe
cycle = pplt.Cycle('dark green', space='hpl', N=df.shape[1])
ax = fig.subplot(122)
ax.plot(df, cycle=cycle, lw=3, legend='t', legend_kw={'frame': False})
[4]:
[<matplotlib.lines.Line2D at 0x7f06f1c38f10>,
 <matplotlib.lines.Line2D at 0x7f06f1c40190>,
 <matplotlib.lines.Line2D at 0x7f06f1c404f0>,
 <matplotlib.lines.Line2D at 0x7f06f1c40850>,
 <matplotlib.lines.Line2D at 0x7f06f1c40bb0>]
_images/1dplots_6_1.svg

Property cycles

It is often useful to create on-the-fly property cycles and use different property cycles for different plot elements. You can create and apply property cycles on-the-fly using the cycle and cycle_kw keywords, available with most PlotAxes 1D plotting commands. cycle and cycle_kw are passed to the Cycle constructor function, and the resulting property cycle is used for the plot. You can specify cycle once with 2D input data (in which case each column is plotted in succession according to the property cycle) or call a plotting command multiple times with the same cycle argument each time (the property cycle is not reset). You can also disable property cycling with cycle=False, cycle='none', or cycle=() and re-enable the default property cycle with cycle=True. For more information on property cycling, see the color cycles section and this matplotlib tutorial.

[5]:
import proplot as pplt
import numpy as np

# Sample data
M, N = 50, 4
state = np.random.RandomState(51423)
data1 = (state.rand(M, N) - 0.5).cumsum(axis=0)
data2 = (state.rand(M, N) - 0.5).cumsum(axis=0) * 1.5
data1 += state.rand(M, N)
data2 += state.rand(M, N)

with pplt.rc.context({'lines.linewidth': 3}):
    # Use property cycle for columns of 2D input data
    fig = pplt.figure(share=False)
    ax = fig.subplot(121)
    ax.format(title='Grayscale cycle')
    ax.plot(
        data1 * data2,
        cycle='black',  # cycle from monochromatic colormap
        cycle_kw={'ls': ('-', '--', '-.', ':')}
    )

    # Use property cycle with successive plot() calls
    ax = fig.subplot(122)
    ax.format(title='Colorful cycle')
    for i in range(data1.shape[1]):
        ax.plot(data1[:, i], cycle='Reds', cycle_kw={'N': N, 'left': 0.3})
    for i in range(data1.shape[1]):
        ax.plot(data2[:, i], cycle='Blues', cycle_kw={'N': N, 'left': 0.3})
    fig.format(xlabel='xlabel', ylabel='ylabel', suptitle='Local property cycles demo')
_images/1dplots_8_0.svg

Line plots

Line plots can be drawn with plot or plotx (or their aliases, line or linex). For the x commands, positional arguments are interpreted as x coordinates or (y, x) pairs. This is analogous to barh and areax. Also, the default x bounds for lines drawn with plot and y bounds for lines drawn with plotx are now “sticky”, i.e. there is no padding between the lines and axes edges by default.

Step and stem plots can be drawn with step, stepx, stem, and stemx. Plots of parallel vertical and horizontal lines can be drawn with vlines and hlines. You can have different colors for “negative” and “positive” lines using negpos=True, negcolor=color, and poscolor=color (the default colors are rc.negcolor = 'blue7' and rc.poscolor = 'red7').

[6]:
import proplot as pplt
import numpy as np
state = np.random.RandomState(51423)
gs = pplt.GridSpec(nrows=3, ncols=2)
fig = pplt.figure(refwidth=2.2, span=False, share='labels')

# Vertical vs. horizontal
data = (state.rand(10, 5) - 0.5).cumsum(axis=0)
ax = fig.subplot(gs[0])
ax.format(title='Dependent x-axis')
ax.line(data, lw=2.5, cycle='seaborn')
ax = fig.subplot(gs[1])
ax.format(title='Dependent y-axis')
ax.linex(data, lw=2.5, cycle='seaborn')

# Vertical lines
gray = 'gray7'
data = state.rand(20) - 0.5
ax = fig.subplot(gs[2])
ax.area(data, color=gray, alpha=0.2)
ax.vlines(data, negpos=True, lw=2)
ax.format(title='Vertical lines')

# Horizontal lines
ax = fig.subplot(gs[3])
ax.areax(data, color=gray, alpha=0.2)
ax.hlines(data, negpos=True, lw=2)
ax.format(title='Horizontal lines')

# Step
ax = fig.subplot(gs[4])
data = state.rand(20, 4).cumsum(axis=1).cumsum(axis=0)
cycle = ('gray6', 'blue7', 'red7', 'gray4')
ax.step(data, cycle=cycle, labels=list('ABCD'), legend='ul', legend_kw={'ncol': 2})
ax.format(title='Step plot')

# Stems
ax = fig.subplot(gs[5])
data = state.rand(20)
ax.stem(data)
ax.format(title='Stem plot')
fig.format(suptitle='Line plots demo', xlabel='xlabel', ylabel='ylabel')
_images/1dplots_10_0.svg

Scatter plots

The scatter command now permits omitting x coordinates and accepts 2D y coordinates, just like plot. As with plotx, the scatterx command is just like scatter, except positional arguments are interpreted as x coordinates and (y, x) pairs. scatter also now accepts keywords that look like plot keywords (e.g., color instead of c and markersize instead of s). This way, scatter can be used simply to “plot markers, not lines” without changing the input arguments relative to plot.

The property cycler used by scatter can be changed using the cycle keyword argument, and unlike matplotlib it can include properties like marker and markersize. The colormap cmap and normalizer norm used with the optional c color array are now passed through the Colormap and Norm constructor functions, and the the s marker size array can now be conveniently scaled using the keywords smin and smax (analogous to vmin and vmax used for colors).

[7]:
import proplot as pplt
import numpy as np
import pandas as pd

# Sample data
state = np.random.RandomState(51423)
x = (state.rand(20) - 0).cumsum()
data = (state.rand(20, 4) - 0.5).cumsum(axis=0)
data = pd.DataFrame(data, columns=pd.Index(['a', 'b', 'c', 'd'], name='label'))

# Figure
gs = pplt.GridSpec(ncols=2, nrows=2)
fig = pplt.figure(refwidth=2.2, share='labels', span=False)

# Vertical vs. horizontal
ax = fig.subplot(gs[0])
ax.format(title='Dependent x-axis')
ax.scatter(data, cycle='538')
ax = fig.subplot(gs[1])
ax.format(title='Dependent y-axis')
ax.scatterx(data, cycle='538')

# Scatter plot with property cycler
ax = fig.subplot(gs[2])
ax.format(title='With property cycle')
obj = ax.scatter(
    x, data, legend='ul', legend_kw={'ncols': 2},
    cycle='Set2', cycle_kw={'m': ['x', 'o', 'x', 'o'], 'ms': [5, 10, 20, 30]}
)

# Scatter plot with colormap
ax = fig.subplot(gs[3])
ax.format(title='With colormap')
data = state.rand(2, 100)
obj = ax.scatter(
    *data,
    s=state.rand(100), smin=3, smax=60, marker='o',
    c=data.sum(axis=0), cmap='maroon',
    colorbar='lr', colorbar_kw={'label': 'label'},
)
fig.format(suptitle='Scatter plot demo', xlabel='xlabel', ylabel='ylabel')
_images/1dplots_12_0.svg

Bar plots and area plots

The bar and barh commands apply default x or y coordinates if you failed to provide them explicitly and can group or stack columns of data if you pass 2D arrays instead of 1D arrays – just like pandas. Similarly, fill_between and fill_betweenx also apply default x or y coordinates if you failed to provide them explicitly, and can stack or overlay columns of data by passing 2D arrays instead of 1D arrays. You can also use the shorthands area and areax instead of fill_between.

For both bar and area plots, you can have different colors for “negative” and “positive” regions using negpos=True, negcolor=color, and poscolor=color (the default colors are rc.negcolor = 'blue7' and rc.poscolor = 'red7'). Also, the default x bounds for shading drawn with area and y bounds for shading drawn with areax is now “sticky”, i.e. there is no padding between the shading and axes edges by default.

[8]:
import proplot as pplt
import numpy as np
import pandas as pd

# Sample data
state = np.random.RandomState(51423)
data = state.rand(5, 5).cumsum(axis=0).cumsum(axis=1)[:, ::-1]
data = pd.DataFrame(
    data, columns=pd.Index(np.arange(1, 6), name='column'),
    index=pd.Index(['a', 'b', 'c', 'd', 'e'], name='row idx')
)

# Figure
pplt.rc.abc = 'a.'
pplt.rc.titleloc = 'l'
gs = pplt.GridSpec(nrows=2, hratios=(3, 2))
fig = pplt.figure(refaspect=2, refwidth=4.8, share=False)

# Side-by-side bars
ax = fig.subplot(gs[0])
obj = ax.bar(
    data, cycle='Reds', edgecolor='red9', colorbar='ul', colorbar_kw={'frameon': False}
)
ax.format(xlocator=1, xminorlocator=0.5, ytickminor=False, title='Side-by-side')

# Stacked bars
ax = fig.subplot(gs[1])
obj = ax.barh(
    data.iloc[::-1, :], cycle='Blues', edgecolor='blue9', legend='ur', stack=True,
)
ax.format(title='Stacked')
fig.format(grid=False, suptitle='Bar plot demo')
_images/1dplots_14_0.svg
[9]:
import proplot as pplt
import numpy as np

# Sample data
state = np.random.RandomState(51423)
data = state.rand(5, 3).cumsum(axis=0)
cycle = ('gray3', 'gray5', 'gray7')

# Figure
fig = pplt.figure(refwidth=2.3, share=False)

# Overlaid area patches
ax = fig.subplot(121)
ax.area(
    np.arange(5), data, data + state.rand(5)[:, None], cycle=cycle, alpha=0.7,
    legend='uc', legend_kw={'center': True, 'ncols': 2, 'labels': ['z', 'y', 'qqqq']},
)
ax.format(title='Fill between columns')

# Stacked area patches
ax = fig.subplot(122)
ax.area(
    np.arange(5), data, stack=True, cycle=cycle, alpha=0.8,
    legend='ul', legend_kw={'center': True, 'ncols': 2, 'labels': ['z', 'y', 'qqqq']},
)
ax.format(title='Stack between columns')
fig.format(grid=False, xlabel='xlabel', ylabel='ylabel', suptitle='Area plot demo')
_images/1dplots_15_0.svg
[10]:
import proplot as pplt
import numpy as np

# Sample data
state = np.random.RandomState(51423)
data = 4 * (state.rand(40) - 0.5)

# Figure
fig, axs = pplt.subplots(nrows=2, refaspect=2, figwidth=5)
axs.format(
    xmargin=0, xlabel='xlabel', ylabel='ylabel', grid=True,
    suptitle='Positive and negative colors demo',
)
for ax in axs:
    ax.axhline(0, color='k', linewidth=1)  # zero line

# Bar plot
ax = axs[0]
ax.bar(data, width=1, negpos=True)
ax.format(title='Bar plot')

# Area plot
ax = axs[1]
ax.area(data, negpos=True, lw=0.5, edgecolor='k')
ax.format(title='Area plot')

# Reset title styles changed above
pplt.rc.reset()
_images/1dplots_16_0.svg

Shading and error bars

Error bars and error shading can be quickly added on-the-fly to line, linex (equivalently, plot, plotx), scatter, scatterx, bar, and barh plots using any of several keyword arguments.

If you pass 2D arrays to these commands with mean=True, means=True, median=True, or medians=True, the means or medians of each column are drawn as lines, points, or bars, while error bars or error shading indicates the spread of the distribution in each column. Invalid data is ignored. You can also specify the error bounds manually with the bardata, boxdata, shadedata, and fadedata keywords. These commands can draw and style thin error bars (the bar keywords), thick “boxes” overlaid on top of these bars (the box keywords; think of them as miniature boxplots), a transparent primary shading region (the shade keywords), and a more transparent secondary shading region (the fade keywords). See the documentation on the plotting commands for details.

[11]:
import numpy as np
import pandas as pd

# Sample data
# Each column represents a distribution
state = np.random.RandomState(51423)
data = state.rand(20, 8).cumsum(axis=0).cumsum(axis=1)[:, ::-1]
data = data + 20 * state.normal(size=(20, 8)) + 30
data = pd.DataFrame(data, columns=np.arange(0, 16, 2))
data.columns.name = 'column number'
data.name = 'variable'

# Calculate error data
# Passed to 'errdata' in the 3rd subplot example
means = data.mean(axis=0)
means.name = data.name  # copy name for formatting
fadedata = np.percentile(data, (5, 95), axis=0)  # light shading
shadedata = np.percentile(data, (25, 75), axis=0)  # dark shading
[12]:
import proplot as pplt
import numpy as np

# Loop through "vertical" and "horizontal" versions
varray = [[1], [2], [3]]
harray = [[1, 1], [2, 3], [2, 3]]
for orientation, array in zip(('horizontal', 'vertical'), (harray, varray)):
    # Figure
    fig = pplt.figure(refwidth=4, refaspect=1.5, share=False)
    axs = fig.subplots(array, hratios=(2, 1, 1))
    axs.format(abc='A.', suptitle=f'Indicating {orientation} error bounds')

    # Medians and percentile ranges
    ax = axs[0]
    kw = dict(
        color='light red', legend=True,
        median=True, barpctile=90, boxpctile=True,
        # median=True, barpctile=(5, 95), boxpctile=(25, 75)  # equivalent
    )
    if orientation == 'horizontal':
        ax.barh(data, **kw)
    else:
        ax.bar(data, **kw)
    ax.format(title='Bar plot')

    # Means and standard deviation range
    ax = axs[1]
    kw = dict(
        color='denim', marker='x', markersize=8**2, linewidth=0.8,
        label='mean', shadelabel=True,
        mean=True, shadestd=1,
        # mean=True, shadestd=(-1, 1)  # equivalent
    )
    if orientation == 'horizontal':
        ax.scatterx(data, legend='b', legend_kw={'ncol': 1}, **kw)
    else:
        ax.scatter(data, legend='ll', **kw)
    ax.format(title='Marker plot')

    # User-defined error bars
    ax = axs[2]
    kw = dict(
        shadedata=shadedata, fadedata=fadedata,
        label='mean', shadelabel='50% CI', fadelabel='90% CI',
        color='ocean blue', barzorder=0, boxmarker=False,
    )
    if orientation == 'horizontal':
        ax.linex(means, legend='b', legend_kw={'ncol': 1}, **kw)
    else:
        ax.line(means, legend='ll', **kw)
    ax.format(title='Line plot')
_images/1dplots_19_0.svg
_images/1dplots_19_1.svg

Histogram plots

Vertical and horizontal histograms can be drawn with hist and histh. As with the other plotting commands, multiple histograms can be drawn by passing 2D arrays instead of 1D arrays, and the color cycle used to color histograms can be changed on-the-fly using the cycle and cycle_kw keywords. Likewise, 2D histograms can be drawn with the hist2d hexbin commands, and their colormaps can be changed on-the-fly with the cmap and cmap_kw keywords (see the 2d plotting section). Marginal distributions for the 2D histograms can be added using panel axes. In the future, ProPlot may include options for drawing “smooth” kernel density estimations with these commands.

[13]:
import proplot as pplt
import numpy as np

# Sample data
M, N = 300, 3
state = np.random.RandomState(51423)
x = state.normal(size=(M, N)) + state.rand(M)[:, None] * np.arange(N) + 2 * np.arange(N)

# Sample overlayed histograms
fig, ax = pplt.subplots(refwidth=4, refaspect=(3, 2))
ax.format(suptitle='Overlaid histograms', xlabel='distribution', ylabel='count')
res = ax.hist(
    x, pplt.arange(-3, 8, 0.2), alpha=0.7,
    cycle=('indigo9', 'gray3', 'red9'), labels=list('abc'), legend='ul',
)
_images/1dplots_21_0.svg
[14]:
import proplot as pplt
import numpy as np

# Sample data
N = 500
state = np.random.RandomState(51423)
x = state.normal(size=(N,))
y = state.normal(size=(N,))
bins = pplt.arange(-3, 3, 0.25)

# Histogram with marginal distributions
fig, axs = pplt.subplots(ncols=2, refwidth=2.3)
axs.format(
    abc='A.', abcloc='l', titleabove=True,
    ylabel='y axis', suptitle='Histograms with marginal distributions'
)
colors = ('indigo9', 'red9')
titles = ('Group 1', 'Group 2')
for ax, which, color, title in zip(axs, 'lr', colors, titles):
    ax.hist2d(
        x, y, bins, vmin=0, vmax=10, levels=50,
        cmap=color, colorbar='b', colorbar_kw={'label': 'count'}
    )
    color = pplt.scale_luminance(color, 1.5)  # histogram colors
    px = ax.panel(which, space=0)
    px.hist(y, bins, lw=0, color=color, vert=False)  # or orientation='horizontal'
    px.format(grid=False, xlocator=[], xreverse=(which == 'l'))
    px = ax.panel('t', space=0)
    px.hist(x, bins, lw=0, color=color)
    px.format(grid=False, ylocator=[], title=title, titleloc='l')
_images/1dplots_22_0.svg

Box plots and violin plots

Vertical and horizontal box and violin plots can be drawn using boxplot, violinplot, boxploth, and violinploth (or their new shorthands, box, violin, boxh, and violinh). The ProPlot versions employ aesthetically pleasing defaults and permit flexible configuration using keywords like color, barcolor, and fillcolor. They also automatically apply axis labels based on the DataFrame or DataArray column labels.

[15]:
import proplot as pplt
import numpy as np
import pandas as pd

# Sample data
N = 500
state = np.random.RandomState(51423)
data1 = state.normal(size=(N, 5)) + 2 * (state.rand(N, 5) - 0.5) * np.arange(5)
data1 = pd.DataFrame(data1, columns=pd.Index(list('abcde'), name='label'))
data2 = state.rand(100, 7)
data2 = pd.DataFrame(data2, columns=pd.Index(list('abcdefg'), name='label'))

# Figure
fig, axs = pplt.subplots([[1, 1, 2, 2], [0, 3, 3, 0]], span=False)
axs.format(
    abc='A.', titleloc='l', grid=False,
    suptitle='Boxes and violins demo'
)

# Box plots
ax = axs[0]
obj1 = ax.boxplot(data1, means=True, marker='x', meancolor='r', fillcolor='gray4')
ax.format(title='Box plots')

# Violin plots
ax = axs[1]
obj2 = ax.violinplot(data1, fillcolor='gray6', means=True, points=100)
ax.format(title='Violin plots')

# Boxes with different colors
ax = axs[2]
colors = pplt.get_colors('pastel2')  # list of colors from the cycle
ax.boxplot(data2, fillcolor=colors, orientation='horizontal')
ax.format(title='Multiple colors', ymargin=0.15)
_images/1dplots_24_0.svg

Parametric plots

Parametric plots can be drawn using the new parametric command. This creates LineCollections that map individual line segments to individual colors, where each segment represents a “parametric” coordinate (e.g., time). The parametric coordinates are specified with a third positional argument or with the keywords c, color, colors or values. Representing parametric coordinates with colors instead of text labels can be cleaner. The below example makes a simple parametric plot with a colorbar indicating the parametric coordinate.

[16]:
import proplot as pplt
import numpy as np
import pandas as pd
gs = pplt.GridSpec(ncols=2, wratios=(2, 1))
fig = pplt.figure(figwidth='16cm', refaspect=(2, 1), share=False)
fig.format(suptitle='Parametric plots demo')
cmap = 'IceFire'

# Sample data
state = np.random.RandomState(51423)
N = 50
x = (state.rand(N) - 0.52).cumsum()
y = state.rand(N)
c = np.linspace(-N / 2, N / 2, N)  # color values
c = pd.Series(c, name='parametric coordinate')

# Parametric line with smooth gradations
ax = fig.subplot(gs[0])
m = ax.parametric(
    x, y, c, interp=10, capstyle='round', joinstyle='round',
    lw=7, cmap=cmap, colorbar='b', colorbar_kw={'locator': 5}
)
ax.format(xlabel='xlabel', ylabel='ylabel', title='Line with smooth gradations')

# Sample data
N = 12
radii = np.linspace(1, 0.2, N + 1)
angles = np.linspace(0, 4 * np.pi, N + 1)
x = radii * np.cos(1.4 * angles)
y = radii * np.sin(1.4 * angles)
c = np.linspace(-N / 2, N / 2, N + 1)

# Parametric line with stepped gradations
ax = fig.subplot(gs[1])
m = ax.parametric(x, y, c, cmap=cmap, lw=15)
ax.format(
    xlim=(-1, 1), ylim=(-1, 1), title='Step gradations',
    xlabel='cosine angle', ylabel='sine angle'
)
ax.colorbar(m, loc='b', maxn=10, label='parametric coordinate')
[16]:
<matplotlib.colorbar.Colorbar at 0x7f06f1361c10>
_images/1dplots_26_1.svg