首页 > 解决方案 > 每个直方图曲线下方的渐变填充 - Python

问题描述

我正在尝试将渐变填充与多个直方图结合使用seaborn facet grid,其中渐变由每条曲线下的值的分布确定,而不仅仅是由序列rowcol使用hue. 下面有一些链接在 python 中执行部分类似的功能:

如何用渐变颜色填充直方图填充发散渐变,但每个直方图独立于其他直方图,因此直方图之间的比较有些无效。使用下图,每个直方图都应该与其他直方图相关。此外,它不使用 seaborn facet grid,这是这里的核心问题。

如何生成一系列直方图不会绘制直方图。它只是填充曲线下的区域。

我发现一些图像显示了我希望执行的内容,但它们似乎都是R在 python 中生成的。我的假设是使用 seaborn 的功能还不存在,我将不得不使用R,但我认为这将适用于许多用户。

在此处输入图像描述

使用下面的代码,我们可以使用或更改调整渐变hue,但这不考虑曲线下的面积。rowcol

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

# Create the data
rs = np.random.RandomState(1979)
x = rs.randn(120)
g = np.tile(list("ABCD"), 30)
h = np.tile(list("XYZ"), 40)

# Generate df
df = pd.DataFrame(dict(x = x, g = g, h = h))

# Initialize the FacetGrid object
pal = sns.cubehelix_palette(4, rot = -0.25, light = 0.7)
g = sns.FacetGrid(df, col = 'h', hue = 'h', row = 'g', aspect = 3, height= 1, palette = pal)

# Draw the densities 
g = g.map(sns.kdeplot, 'x', shade = True, alpha = 0.8, lw = 1, bw = 0.8)
g = g.map(sns.kdeplot, 'x', color= 'w', lw = 1, bw = 0.8)
g = g.map(plt.axhline, y = 0, lw = 1)

# Adjust title and axis labels directly
g.axes[0,0].set_ylabel('L 1')
g.axes[1,0].set_ylabel('L 2')
g.axes[2,0].set_ylabel('L 3')
g.axes[3,0].set_ylabel('L 4')

g.axes[0,0].set_title('Top 1')
g.axes[0,1].set_title('Top 2')
g.axes[0,2].set_title('Top 3')

g.axes[1,0].set_title('')
g.axes[1,1].set_title('')
g.axes[1,2].set_title('')
g.axes[2,0].set_title('')
g.axes[2,1].set_title('')
g.axes[2,2].set_title('')
g.axes[3,0].set_title('')
g.axes[3,1].set_title('')
g.axes[3,2].set_title('')

g.set_axis_labels(x_var = 'Total Amount')
g.set(yticks = [])

出去:

有一个可以调整的渐变,rowcol我希望将这个渐变传递到每个直方图曲线下方的区域。类似于上图。因此,每条曲线下方的区域在低于零时会更亮,而在高于零时会更暗。

即使将曲线下面积调整为中值也可能就足够了。

在此处输入图像描述

标签: pythonhistogramseaborngradientfacet-grid

解决方案


您可以创建图像渐变,并将直方图本身用作图像的剪切路径,以便唯一可见的部分是曲线下方的部分。

因此,您可以在创建图像时使用任何可用的 cmap 和规范化。

这是一个简单的例子:

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

# Create the data
rs = np.random.RandomState(1979)
x = rs.randn(120)
g = np.tile(list("ABCD"), 30)
h = np.tile(list("XYZ"), 40)

# Generate df
df = pd.DataFrame(dict(x = x, g = g, h = h))

# Initialize the FacetGrid object
pal = sns.cubehelix_palette(4, rot = -0.25, light = 0.7)
g = sns.FacetGrid(df, col = 'h', hue = 'h', row = 'g', aspect = 3, height= 1, palette = pal)

# Draw the densities 
g = g.map(sns.kdeplot, 'x', shade = True, alpha = 0.8, lw = 1, bw = 0.8)
g = g.map(sns.kdeplot, 'x', color= 'w', lw = 1, bw = 0.8)
g = g.map(plt.axhline, y = 0, lw = 1)

for ax in g.axes.flat:
    ax.set_title("")

# Adjust title and axis labels directly
for i in range(4):
    g.axes[i,0].set_ylabel('L {:d}'.format(i))
for i in range(3):
    g.axes[0,i].set_title('Top {:d}'.format(i))



# generate a gradient
cmap = 'coolwarm'
x = np.linspace(0,1,100)
for ax in g.axes.flat:
    im = ax.imshow(np.vstack([x,x]), aspect='auto', extent=[*ax.get_xlim(), *ax.get_ylim()], cmap=cmap, zorder=10)
    path = ax.collections[0].get_paths()[0]
    patch = matplotlib.patches.PathPatch(path, transform=ax.transData)
    im.set_clip_path(patch)

g.set_axis_labels(x_var = 'Total Amount')
g.set(yticks = [])

在此处输入图像描述


推荐阅读