My Seaborn boxplot numbers are not on the correct charts

For some reason my median box plot numbers are not on top of the correct boxplot. Here is my code:

# bar plot for all filenames based on their mean pixel value
sns.set(style = "ticks", palette = "pastel")

box_plot = sns.boxplot(y="mean_pixel_value", x="filename",
                      palette=["m","g"],
                      data=df_ts)
sns.despine(offset=10, trim=True)
plt.setp(box_plot.get_xticklabels(),rotation=70)

medians = df_ts.groupby(['filename'])['mean_pixel_value'].median()
vertical_offset=df_ts['mean_pixel_value'].median()*0.3

for xtick in box_plot.get_xticks():
    box_plot.text(xtick,medians[xtick] + vertical_offset,medians[xtick],
                 horizontalalignment='center',size='small',color='blue',weight='semibold', rotation = 90)

As you can see in the screenshot below, the median numbers aren’t matching up to their respective box plot, especially in the last 3 filenames. 5049 should be on top of SM05334, 4908 on top of SM05330 and 4826 on top off SM05326. Any ideas on why this is happening?

capture_1

Answer

The order on your boxplot is different from the order obtained from your groupby and medians. A simple solution is calculate your medians first and pass the order into the boxplot plot, for example:

import pandas as pd
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(999)

df_ts = pd.DataFrame({"filename" : np.random.choice(['A','B','C','D'],50),
                     "mean_pixel_value" : np.random.normal(10,1.5,50)})

medians = df_ts.groupby(['filename'])['mean_pixel_value'].median()
vertical_offset=df_ts['mean_pixel_value'].median()*0.3

You can see the order if your file name and medians is sorted alphabetically:

filename
A     9.802534
B    10.189704
C    11.043807
D    10.041651

Now pass the index into boxplot:

box_plot = sns.boxplot(y="mean_pixel_value", x="filename",
                      palette=["m","g"],
                      data=df_ts,order=medians.index)

sns.despine(offset=10, trim=True)
plt.setp(box_plot.get_xticklabels(),rotation=70)

for xtick in box_plot.get_xticks():
    box_plot.text(xtick,medians[xtick] + vertical_offset,medians[xtick],
                 horizontalalignment='center',size='small',color='blue',weight='semibold', rotation = 90)

enter image description here