简体   繁体   中英

How to plot a paired histogram using seaborn

I would like to make a paired histogram like the one shown here using the seaborn distplot. This kind of plot can also be referred to as the back-to-back histogram shown here , or a bihistogram inverted/mirrored along the x-axis as discussed here .

Here is my code:

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

green = np.random.normal(20,10,1000)
blue = np.random.poisson(60,1000)

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

sns.distplot(blue, hist=True, kde=True, hist_kws={'edgecolor':'black'}, kde_kws={'linewidth':2}, bins=10, color='blue')
sns.distplot(green, hist=True, kde=True, hist_kws={'edgecolor':'black'}, kde_kws={'linewidth':2}, bins=10, color='green')
ax.set_xticks(np.arange(-20,121,20))
ax.set_yticks(np.arange(0.0,0.07,0.01))
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

plt.show()

Here is the output: seaborn 分布图

When I use the method discussed here (plt.barh), I get the bar plot shown just below, which is not what I am looking for. 水平条形图

Or maybe I haven't understood the workaround well enough... A simple/short implementation of python-seaborn-distplot similar to these kinds of plots would be perfect. I edited the figure of my first plot above to show the kind of plot I hope to achieve (though y-axis not upside down): 配对直方图

Any leads would be greatly appreciated.

You could use two subplots and invert the y-axis of the lower one and plot with the same bins.

df = pd.DataFrame({'a': np.random.normal(0,5,1000), 'b': np.random.normal(20,5,1000)})

fig =plt.figure(figsize=(5,5))
ax = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

bins = np.arange(-20,40)

ax.hist(df['a'], bins=bins)
ax2.hist(df['b'],color='orange', bins=bins)
ax2.invert_yaxis()

在此处输入图像描述

edit:

improvements suggested by @mwaskom

fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True, figsize=(5,5))

bins = np.arange(-20,40)

for ax, column, color, invert in zip(axes.ravel(), df.columns, ['teal', 'orange'],  [False,True]):
    ax.hist(df[column], bins=bins, color=color)
    
    if invert:
        ax.invert_yaxis()
        
plt.subplots_adjust(hspace=0)

在此处输入图像描述

Here is a possible approach using seaborn's displots. Seaborn doesn't return the created graphical elements, but the ax can be interrogated. To make sure the ax only contains the elements you want upside down, those elements can be drawn first. Then, all the patches (the rectangular bars) and the lines (the curve for the kde) can be given their height in negative. Optionally the x-axis can be set at y == 0 using ax.spines['bottom'].set_position('zero') .

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

green = np.random.normal(20, 10, 1000)
blue = np.random.poisson(60, 1000)

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

sns.distplot(green, hist=True, kde=True, hist_kws={'edgecolor': 'black'}, kde_kws={'linewidth': 2}, bins=10,
             color='green')
for p in ax.patches:  # turn the histogram upside down
    p.set_height(-p.get_height())
for l in ax.lines:  # turn the kde curve upside down
    l.set_ydata(-l.get_ydata())

sns.distplot(blue, hist=True, kde=True, hist_kws={'edgecolor': 'black'}, kde_kws={'linewidth': 2}, bins=10,
             color='blue')
ax.set_xticks(np.arange(-20, 121, 20))
ax.set_yticks(np.arange(0.0, 0.07, 0.01))
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

pos_ticks = np.array([t for t in ax.get_yticks() if t > 0])
ticks = np.concatenate([-pos_ticks[::-1], [0], pos_ticks])
ax.set_yticks(ticks)
ax.set_yticklabels([f'{abs(t):.2f}' for t in ticks])
ax.spines['bottom'].set_position('zero')

plt.show()

示例图

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM