每条直方图曲线下方的渐变填充 - Python

Gradient fill underneath each histogram curve - Python

我正在尝试使用 seaborn facet grid 将渐变填充与多个直方图合并,其中渐变由每条曲线下的值的分布决定,而不仅仅是由一系列 rowcol 使用 hue。下面有一些链接在 python:

中部分执行了一些类似的功能

How to fill histogram with gradient color 填充发散梯度,但每个直方图都独立于其他直方图,因此直方图之间的比较有些无效。使用下图,每个直方图应该相对于其他直方图。此外,它没有使用 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调整渐变,但我希望将此渐变传递到每个直方图曲线下方的区域。类似于上图。因此,每条曲线下方的区域在低于零时会更亮,而在高于零时会变暗。

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

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

因此,您可以使用创建图像时可用的任何 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 = [])