Seaborn boxplot horizontal line annotation
Asked Answered
B

2

5

I'm wanting to add a horizontal line i.e. a 'target' line to some plots: stripplots, boxplots, and violin plots, to show ideal values data (or ideally a range).

This R example (Add multiple horizontal lines in a boxplot) - the first image - is basically it (although i'd do some formatting to make presentable).

R abline() equivalent in Python doesn't help me (or I havent figured out how) as I'm using categorical data, so I just want to essentially define (e.g.) y=3 and plot this. My code (below) works fine, I just don't know how to add a line.

fig, ax = plt.subplots(nrows=4,figsize=(20,20))

sns.violinplot(x="Wafer", y="Means", hue='Feature', 
           data=Means[Means.Target == 1], ax=ax[0])
sns.violinplot(x="Wafer", y="Means", hue='Feature', 
           data=Means[Means.Target == 3], ax=ax[1])
sns.boxplot(x="Feature", y="Means", 
        data=Means, linewidth=0.8, ax=ax[2])
sns.stripplot(x="Feature", y="Means", hue='Wafer',
          data=Means, palette="plasma", jitter=0.1, size=5.5, ax=ax[3])

Any help greatly appreciated.

Bewilderment answered 24/8, 2018 at 13:30 Comment(1)
It should be plt.hlines(y, xmin, xmax)Stratfordonavon
S
6

Let's say you wan't to plot a horizontal line at height y and from x1 to x2 where x1 and x2 are your actual x-data values. The following are just three out of possibly several ways you can do that:

First:

ax.hlines(y, x1, x2)

Second:

plt.plot([x1, x2], [y, y])

Third (x1 and x2 now in relative/fractional coordinates between 0 meaning far left and 1 meaning far right):

ax.axhline(y, x1, x2)
Stratfordonavon answered 24/8, 2018 at 13:43 Comment(3)
Thanks - your 3rd version was what i was looking for. How can this be done for multiple lines: e.g. ax.axhline[(3, 0, 1),(1,0,1)] (which doesn't work) if i wanted a line at y=3 and y=1Bewilderment
Ok, then you just write two lines: ax.axhline(1, 0, 1) and ax.axhline(3, 0, 1). You can also put it in a for loop but for just two lines, I don't think it is necessaryStratfordonavon
I did this in a for-loop actually, as i couldn't get it to work (in the context of my code above), calling the function twice. The for loop worked well thanks.Bewilderment
K
2

If you want to define a good or bad area I general find placing a patch behind the data to be easier for the user to interpret.

fig, ax = plt.subplots(figsize=(4, 4))
ax.plot([1,2,3,4], [1,2,3,4], color='blue')  # simple example line

# define patch area
rect = patches.Rectangle(
    xy=(ax.get_xlim()[0], 2),  # lower left corner of box: beginning of x-axis range & y coord)
    width=ax.get_xlim()[1]-ax.get_xlim()[0],  # width from x-axis range
    height=1,
    color='green', alpha=0.1, ec='red'
)
ax.add_patch(rect)
plt.show()

enter image description here

Kelila answered 24/8, 2018 at 15:12 Comment(1)
Thanks ak_slick, that's a very good point; i'll try and implement and feedback.Bewilderment

© 2022 - 2024 — McMap. All rights reserved.