Skip to content

Styling and Colors

Customize box plot appearance through color schemes, line styles, and component-specific properties.

Mental Model

By default, boxplot() draws unfilled outlines. Set patch_artist=True to get filled rectangles, then use boxprops, medianprops, whiskerprops, capprops, and flierprops dictionaries to style each component independently. Think of each dictionary as a CSS rule targeting one part of the box plot anatomy.

Styling Principles

Good styling serves the data, not the designer:

  • Median line should stand out — use a contrasting color or thicker linewidth
  • Boxes should be subtle — muted fills with thin borders keep the focus on the data pattern
  • Outliers should not dominate — smaller markers and muted colors prevent outlier dots from overwhelming the plot
  • Consistency across groups — use the same styling for comparable groups so differences come from data, not aesthetics

Box Colors

Use patch_artist=True to enable box filling with colors.

1. Single Color

```python import matplotlib.pyplot as plt import numpy as np

np.random.seed(42) data = [np.random.normal(0, std, 100) for std in range(1, 5)]

fig, ax = plt.subplots() bp = ax.boxplot(data, patch_artist=True)

for patch in bp['boxes']: patch.set_facecolor('lightblue')

plt.show() ```

2. Multiple Colors

```python colors = ['lightblue', 'lightgreen', 'lightyellow', 'lightpink']

bp = ax.boxplot(data, patch_artist=True) for patch, color in zip(bp['boxes'], colors): patch.set_facecolor(color) ```

3. Colormap Colors

```python import matplotlib.cm as cm

cmap = cm.get_cmap('viridis') colors = [cmap(i / len(data)) for i in range(len(data))]

bp = ax.boxplot(data, patch_artist=True) for patch, color in zip(bp['boxes'], colors): patch.set_facecolor(color) ```

Component Properties

Each box plot component can be styled individually using property dictionaries.

1. Box Properties

python boxprops = dict(facecolor='lightblue', edgecolor='navy', linewidth=2) ax.boxplot(data, patch_artist=True, boxprops=boxprops)

2. Whisker Properties

python whiskerprops = dict(color='gray', linewidth=1.5, linestyle='--') ax.boxplot(data, whiskerprops=whiskerprops)

3. Cap Properties

python capprops = dict(color='black', linewidth=2) ax.boxplot(data, capprops=capprops)

Median Styling

Customize the median line appearance.

1. Color and Width

python medianprops = dict(color='red', linewidth=2) ax.boxplot(data, medianprops=medianprops)

2. Line Style

python medianprops = dict(color='darkred', linewidth=2, linestyle='-') ax.boxplot(data, medianprops=medianprops)

3. Full Example

```python fig, ax = plt.subplots() bp = ax.boxplot(data, patch_artist=True, medianprops=dict(color='white', linewidth=2))

for patch in bp['boxes']: patch.set_facecolor('steelblue')

plt.show() ```

Mean Marker Styling

Customize the mean indicator appearance.

1. Mean Properties

```python meanprops = dict(marker='D', markerfacecolor='red', markeredgecolor='darkred', markersize=8)

ax.boxplot(data, showmeans=True, meanprops=meanprops) ```

2. Mean as Line

python meanprops = dict(color='green', linewidth=2, linestyle='--') ax.boxplot(data, showmeans=True, meanline=True, meanprops=meanprops)

3. Diamond vs Triangle

```python

Diamond marker

meanprops = dict(marker='D', markerfacecolor='red')

Triangle marker

meanprops = dict(marker='^', markerfacecolor='green') ```

Outlier Styling

Customize flier (outlier) point appearance.

1. Basic Flier Properties

```python flierprops = dict(marker='o', markerfacecolor='red', markersize=8, markeredgecolor='darkred')

ax.boxplot(data, flierprops=flierprops) ```

2. Different Marker Shapes

```python

Circle

flierprops = dict(marker='o', markerfacecolor='red')

Star

flierprops = dict(marker='*', markerfacecolor='gold', markersize=10)

Diamond

flierprops = dict(marker='D', markerfacecolor='purple') ```

3. Transparent Outliers

python flierprops = dict(marker='o', markerfacecolor='none', markeredgecolor='gray', alpha=0.5)

Complete Styled Example

Combine all styling options for a polished visualization.

1. Professional Style

```python import matplotlib.pyplot as plt import numpy as np

np.random.seed(42) data = [np.random.normal(0, std, 100) for std in range(1, 5)]

fig, ax = plt.subplots(figsize=(8, 5))

bp = ax.boxplot(data, patch_artist=True, notch=True, widths=0.6, boxprops=dict(facecolor='steelblue', edgecolor='navy'), whiskerprops=dict(color='navy', linewidth=1.5), capprops=dict(color='navy', linewidth=1.5), medianprops=dict(color='white', linewidth=2), flierprops=dict(marker='o', markerfacecolor='coral', markeredgecolor='darkred', markersize=6))

ax.set_xticklabels([r'\(\sigma=1\)', r'\(\sigma=2\)', r'\(\sigma=3\)', r'\(\sigma=4\)']) ax.set_ylabel('Value') ax.set_title('Customized Box Plot') ax.grid(axis='y', alpha=0.3)

plt.tight_layout() plt.show() ```

2. Return Value Dictionary

```python

bp dictionary contains all artists

print(bp.keys())

dict_keys(['whiskers', 'caps', 'boxes', 'medians', 'fliers', 'means'])

```

3. Post-Creation Modification

```python bp = ax.boxplot(data, patch_artist=True)

Modify after creation

bp['boxes'][0].set_facecolor('red') bp['medians'][0].set_color('white') bp['whiskers'][0].set_linestyle('--') ```


Exercises

Exercise 1. Create a box plot for five groups using patch_artist=True where each box is filled with a color from the tab10 colormap. Set the median line to white with linewidth=2 and the whiskers to match the box face color.

Solution to Exercise 1
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data = [np.random.randn(100) + i for i in range(5)]

fig, ax = plt.subplots(figsize=(8, 5))
bp = ax.boxplot(data, patch_artist=True,
                 medianprops=dict(color='white', linewidth=2))

cmap = plt.cm.tab10
for i, (patch, whisker_pair) in enumerate(zip(bp['boxes'],
        zip(bp['whiskers'][::2], bp['whiskers'][1::2]))):
    color = cmap(i / 5)
    patch.set_facecolor(color)
    for w in whisker_pair:
        w.set_color(color)

ax.set_xticklabels([f'Group {i+1}' for i in range(5)])
ax.set_title('Colormap-Styled Box Plot')
plt.show()

Exercise 2. Create a dark-themed box plot by setting plt.style.use('dark_background'). Plot four datasets with neon-colored boxes (bright green, cyan, magenta, yellow). Set edge colors to white and flier markers to star shape with white color.

Solution to Exercise 2
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)
data = [np.random.randn(100) + i for i in range(4)]

plt.style.use('dark_background')
fig, ax = plt.subplots(figsize=(8, 5))

bp = ax.boxplot(data, patch_artist=True,
                 flierprops=dict(marker='*', markerfacecolor='white', markersize=6))

neon_colors = ['#39ff14', '#00ffff', '#ff00ff', '#ffff00']
for patch, color in zip(bp['boxes'], neon_colors):
    patch.set_facecolor(color)
    patch.set_edgecolor('white')
    patch.set_alpha(0.7)

ax.set_xticklabels(['A', 'B', 'C', 'D'])
ax.set_title('Dark Theme Box Plot')
plt.show()
plt.style.use('default')

Exercise 3. Create a box plot where the box color reflects the median value using a colormap. Generate 6 datasets with medians ranging from low to high. Map each median to a color using plt.cm.RdYlGn (red for low, green for high). Add a colorbar to show the mapping.

Solution to Exercise 3
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import Normalize

np.random.seed(42)
medians_target = [1, 3, 5, 7, 9, 11]
data = [np.random.randn(100) + m for m in medians_target]
actual_medians = [np.median(d) for d in data]

norm = Normalize(vmin=min(actual_medians), vmax=max(actual_medians))
cmap = plt.cm.RdYlGn

fig, ax = plt.subplots(figsize=(10, 5))
bp = ax.boxplot(data, patch_artist=True)

for patch, med in zip(bp['boxes'], actual_medians):
    patch.set_facecolor(cmap(norm(med)))

sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
plt.colorbar(sm, ax=ax, label='Median Value')
ax.set_xticklabels([f'Set {i+1}' for i in range(6)])
ax.set_title('Box Colors Mapped to Median Value')
plt.show()