Share x axis between matplotlib and seaborn

2019-06-03 08:33发布

I have data in pandas DataFrame:

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

np.random.seed(786)

df = pd.DataFrame({'a':np.arange(0, 1, 0.05),
                   'b':np.random.rand(20) - .5})

print (df)
       a         b
0   0.00  0.256682
1   0.05 -0.192555
2   0.10  0.393919
3   0.15 -0.113310
4   0.20  0.373855
5   0.25 -0.423764
6   0.30 -0.123428
7   0.35 -0.173446
8   0.40  0.440818
9   0.45 -0.016878
10  0.50  0.055467
11  0.55 -0.165294
12  0.60 -0.216684
13  0.65  0.011099
14  0.70  0.059425
15  0.75  0.145865
16  0.80 -0.019171
17  0.85  0.116984
18  0.90 -0.051583
19  0.95 -0.096527

I would like plot barplot and add vertical line:

plt.figure(figsize=(10,5))
sns.barplot(x = 'a', y = 'b', data = df)
plt.vlines(x = 0.45, ymin = 0, ymax = 0.6, color = 'red', linewidth=5)

There are problems with ticklabels, because overlaping and also line should be in point 0.45 instaed near 0 for x axis.

polt

I try many solutions from link1, link2, link3, link4 but still problem set correctly axis for both plots.

What is problem? Is possible share x axis between plots?

Expected output - correctly aligned vertical line and also not overlaping ticks in x axis:

pic

3条回答
孤傲高冷的网名
2楼-- · 2019-06-03 09:03

Using ax.twiny and rounding inputs:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(786)

df = pd.DataFrame({'a':np.round(np.arange(0, 1, 0.05),2),
                   'b':np.round(np.random.rand(20),2) - .5})


plt.figure(figsize=(10,5))
ax = sns.barplot(x = 'a', y = 'b', data = df)
ax.set_xticklabels(ax.get_xticklabels(), rotation=90)
ax2 = ax.twiny()
ax2.vlines(x = 0.45, ymin = 0, ymax = 0.6, color = 'red', linewidth=2)
#ax2.set_visible(False) # this hides the ticks on the top of the plot

enter image description here

查看更多
看我几分像从前
3楼-- · 2019-06-03 09:09

create a figure with two subplots, then you can share x- and y axis between both subplots.

fig = plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212, sharex = ax1, sharey = ax1)
查看更多
何必那么认真
4楼-- · 2019-06-03 09:24

The x-axis in the barplot is categorical, so it doesn't have the values of your df.a as a real scale, but only as tick labels. You could change e.g. df.a[19] = 2 and nothing will change except the label of the last bar tick.

So categorical axis means the coordinates are 0 for the first bar, 1 for the second and so on ... 19 for the last.

My approach then would be to set the vertical line at xpos * 19/.95:

plt.vlines(x = .45*19/.95, ymin = 0, ymax = 0.6, color = 'red', linewidth=5)

enter image description here

For the general case you could add a lambda function to calculate the conversion:

f = lambda x: (x-df.a.values[0]) * (df.a.size-1) / (df.a.values[-1] - df.a.values[0])
plt.vlines(x = f(.45), ymin = 0, ymax = 0.6, color = 'red', linewidth=5)

However, as df.a.values is only printed as tick labels, it should go linearly from start to end.

Regarding the problem with x-axis labeling: I just can tell that it doesn't appear at my system, the code for the plot abovevis identical to yours, except the vertical line. Perhaps it was introduced while doing one attempt of vlines after another.

查看更多
登录 后发表回答