Seaborn boxplot individual box spacing
Asked Answered
M

2

7

How can I increase the space between two specefic boxes in a seaborn boxplot? In the tips dataset, how can i modify the spacing between Sat and Sun without affecting the other boxes. I already included empty columns in the dataframe but with this workaround it's not possible to controll the spacing.

%matplotlib inline
import seaborn as sns
tips = sns.load_dataset("tips")
ax = sns.boxplot(x="day", y="total_bill", data=tips)

Tips Boxplot Example

Mead answered 29/6, 2018 at 15:38 Comment(0)
M
4

To my knowledge, this is not possible with seaborn because it sadly does not provide any means of modifying the positions keyword. See also this similar question.

The easiest workaround is to use a different boxplot function, for example the one that comes with pandas dataframes:

bplot = tips.boxplot(by="day", column="total_bill", positions=[1,2,3,4.5])

Of course, this is nowhere near as nicely styled as the seaborn version.

Fortunately, matplotlib provides infinite options to those willing to explore them, so one could create something similar to the seaborn plot by modifying the different parts of the plot accordingly.

This comes close:

# Prep
import matplotlib.pyplot as plt
import seaborn as sns
tips = sns.load_dataset("tips")

# Create boxplot
bplot = tips.boxplot(by="day", column="total_bill", positions=[1,2,3,4.5], 
                     return_type='dict', figsize=(8,6), grid=False, patch_artist=True, 
                     sym='d', fontsize=16)

# Style boxplot
colors = ['blue', 'green', 'red', 'cyan']
for patch, color in zip(bplot['total_bill']['boxes'], colors):
    patch.set_facecolor(color)
    patch.set_edgecolor('0.2')
    patch.set_linewidth(1.5)
for whisker in bplot['total_bill']['whiskers']:
    whisker.set_color('0.2')
    whisker.set_linewidth(1.5)
for fliers in bplot['total_bill']['fliers']:
    fliers.set_markerfacecolor('0.2')
for median in bplot['total_bill']['medians']:
    median.set_color('0.2')
    median.set_linewidth(1.5)
for caps in bplot['total_bill']['caps']:
    caps.set_color('0.2')
    caps.set_linewidth(1.5)

# Other adjustments
plt.title("")
plt.suptitle("")
plt.xlabel("day", fontsize=18)
plt.ylabel("total_bill", fontsize=18)

enter image description here

Minni answered 30/6, 2018 at 23:5 Comment(0)
S
2

Seaborn does no provide this functionnality (see e.g. this issue). You still may tweak matplotlib after plotting the boxes:

ax = plt.gca()  # Or get the axis another way

def _reduce_box_width(artist, factor=.5):
    vertices = artist.get_path().vertices
    artist_width = vertices[1, 0] - vertices[0, 0]
    vertices[0, 0] += artist_width * (factor/2)
    vertices[1, 0] -= artist_width * (factor/2)
    vertices[2, 0] -= artist_width * (factor/2)
    vertices[3, 0] += artist_width * (factor/2)
    vertices[4, 0] += artist_width * (factor/2)

for artist in ax.artists:
    _reduce_box_width(artist, factor=.5)

def _reduce_horizontal_line_width(artist, factor=.5):
    vertices = artist.get_path().vertices
    artist_width = vertices[1, 0] - vertices[0, 0]
    vertices[0, 0] += artist_width * (factor/2)
    vertices[1, 0] -= artist_width * (factor/2)

horizontal_lines = [l for l in ax.lines
                    if len(l.get_path().vertices) != 0 and
                       l.get_path().vertices[0, 1] = = l.get_path().vertices[1, 1]]
for line in horizontal_lines:
    _reduce_horizontal_line_width(line)

ax.redraw_in_frame()

It may need to be adapted to your exact situation.

Stepmother answered 17/9, 2019 at 10:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.