Edge Color Control

This example demonstrates how to control edge color across all plot types, either globally through pp.rcParams['edgecolor'] or per-call via the edgecolor= argument.

By default, pp.rcParams['edgecolor'] is None, which means each plot picks its own edge automatically (typically the face/palette color). Setting it once applies uniform edges across every plot in the figure.

import publiplots as pp
import pandas as pd
import numpy as np

# Use a higher alpha for this example so face colors are vivid — it makes
# edge colors easier to spot by contrast.
pp.rcParams['alpha'] = 0.8

Default Behavior: Automatic Edges

With the default rcParam (None), edges match the face color. Each bar’s outline follows its palette entry.

np.random.seed(7)
bar_data = pd.DataFrame({
    'group': np.repeat(['A', 'B', 'C', 'D'], 12),
    'value': np.concatenate([
        np.random.normal(45, 7, 12),
        np.random.normal(60, 8, 12),
        np.random.normal(75, 9, 12),
        np.random.normal(90, 10, 12),
    ])
})

fig, ax = pp.subplots(axes_size=(60, 40))
pp.barplot(
    data=bar_data,
    x='group',
    y='value',
    hue='group',
    palette='pastel',
    errorbar='se',
    title='Default: edges match palette',
    ax=ax,
)
pp.show()
Default: edges match palette

Global Override via rcParams

Set pp.rcParams['edgecolor'] to apply a single edge color across every plot in the script. This is the recommended way to enforce a consistent publication style without repeating edgecolor= on every call.

pp.rcParams['edgecolor'] = 'black'

fig, ax = pp.subplots(axes_size=(60, 40))
pp.barplot(
    data=bar_data,
    x='group',
    y='value',
    hue='group',
    palette='pastel',
    errorbar='se',
    title="rcParams['edgecolor'] = 'black'",
    ax=ax,
)
pp.show()
rcParams['edgecolor'] = 'black'

Uniform Edges Across Plot Types

The same rcParam applies to every publiplots function: bars, boxes, violins, scatter, strip/swarm, point, raincloud, and dot-heatmaps.

np.random.seed(11)
mixed_data = pd.DataFrame({
    'group': np.repeat(['A', 'B', 'C'], 30),
    'value': np.concatenate([
        np.random.normal(50, 8, 30),
        np.random.normal(65, 9, 30),
        np.random.normal(80, 10, 30),
    ]),
})

# `pp.subplots` declares axes dimensions in mm and extends the figure to
# accommodate decorations. `pp.legend_group` reserves a shared legend
# column on the right whose width is auto-measured from the rendered
# entries — no manual `legend_column=...` guess.
#
# `pp.legend(anchor=...)` attaches BEFORE the plot calls. Plotting
# functions that stash entries (scatterplot, stripplot, swarmplot,
# pointplot in this release) see the group and skip their own per-axis
# legend — the group claims and renders their entries instead.
#
# For plots that don't yet stash (bar, box), we pass `legend=False`; the
# scatterplot on the right anchors the shared "group" entry for the whole
# row since all three panels share the same hue variable.
fig, axes = pp.subplots(1, 3, axes_size=(45, 30))
pp.legend(anchor=axes[-1])

pp.barplot(
    data=mixed_data, x='group', y='value', hue='group',
    palette='pastel', errorbar='se', title='Bar', ax=axes[0], legend=False,
)
pp.boxplot(
    data=mixed_data, x='group', y='value', hue='group',
    palette='pastel', title='Box', ax=axes[1], legend=False,
)
pp.scatterplot(
    data=mixed_data, x='group', y='value', hue='group',
    palette='pastel', title='Scatter', ax=axes[2],
)
pp.show()
Bar, Box, Scatter

Composite Plots: Raincloud

Raincloud plots layer a violin (KDE cloud), a box, and a strip of raw points in one figure. Before the rcParam, each layer had to be passed edgecolor individually (or inherit palette edges per layer). Setting the rcParam once gives every sub-artist the same outline, which reads much cleaner for publications — especially across groups sharing a palette.

Note the rain_kws=dict(linewidth=0.5) override: the raincloud default draws rain points with linewidth=0 for a clean look, but that also hides any edge color. Pass a small positive linewidth to make the edge visible on the individual points.

np.random.seed(21)
rain_data = pd.DataFrame({
    'condition': np.repeat(['Control', 'Low Dose', 'High Dose'], 40),
    'response': np.concatenate([
        np.random.normal(50, 8, 40),
        np.random.normal(62, 10, 40),
        np.random.normal(78, 9, 40),
    ]),
})

fig, axes = pp.subplots(1, 2, axes_size=(55, 50), sharey=True)

# Left: palette-driven edges (rcParam temporarily off)
pp.rcParams['edgecolor'] = None
pp.raincloudplot(
    data=rain_data,
    x='condition',
    y='response',
    hue='condition',
    palette='pastel',
    title='Auto edges (palette)',
    ax=axes[0],
    legend=False,
)

# Right: uniform black edges via rcParam + visible rain-point strokes.
pp.rcParams['edgecolor'] = 'black'
pp.raincloudplot(
    data=rain_data,
    x='condition',
    y='response',
    hue='condition',
    palette='pastel',
    rain_kws=dict(alpha=0.5, linewidth=0.5),
    title="rcParams['edgecolor'] = 'black'",
    ax=axes[1],
    legend=False,
)

# Both panels share the same groups, so one legend to the right of the
# rightmost axes serves both.
group = pp.legend(anchor=axes[-1])
group.add_legend(
    handles=pp.create_legend_handles(
        labels=['Control', 'Low Dose', 'High Dose'],
        colors=list(pp.color_palette('pastel', 3)),
        alpha=pp.rcParams['alpha'],
        linewidth=pp.rcParams['lines.linewidth'],
        edgecolors='black',
    ),
    label='condition',
)
pp.show()
Auto edges (palette), rcParams['edgecolor'] = 'black'

Per-Call Override

A per-call edgecolor= argument always wins over the rcParam. Use this to tweak a single plot without resetting the global default.

fig, axes = pp.subplots(1, 2, axes_size=(55, 35))
pp.barplot(
    data=bar_data,
    x='group',
    y='value',
    hue='group',
    palette='pastel',
    errorbar='se',
    title="rcParam (black) inherited",
    ax=axes[0],
)
pp.barplot(
    data=bar_data,
    x='group',
    y='value',
    hue='group',
    palette='pastel',
    errorbar='se',
    edgecolor='#c0392b',
    title="edgecolor='#c0392b' (per-call)",
    ax=axes[1],
)
pp.show()
rcParam (black) inherited, edgecolor='#c0392b' (per-call)

Restoring the Default

Set the rcParam back to None to return to per-plot automatic edges.

pp.rcParams['edgecolor'] = None

fig, ax = pp.subplots(axes_size=(60, 40))
pp.barplot(
    data=bar_data,
    x='group',
    y='value',
    hue='group',
    palette='pastel',
    errorbar='se',
    title="Back to default (None = auto)",
    ax=ax,
)
pp.show()

# Restore the global alpha default.
pp.rcParams['alpha'] = 0.1
Back to default (None = auto)

Total running time of the script: (0 minutes 3.138 seconds)

Gallery generated by Sphinx-Gallery