我需要生成与此示例中所示的图像类似的图像:
区别在于,我没有二维散点,而是使用 numpy 的 histogram2d 生成二维直方图,并使用
imshow
和 gridspec
绘制:
如何将此 2D 直方图投影为水平和垂直直方图(或曲线),使其看起来对齐,就像第一个图像一样?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
data = # Uploaded to http://pastebin.com/tjLqM9gQ
# Create a meshgrid of coordinates (0,1,...,N) times (0,1,...,N)
y, x = np.mgrid[:len(data[0, :, 0]), :len(data[0, 0, :])]
# duplicating the grids
xcoord, ycoord = np.array([x] * len(data)), np.array([y] * len(data))
# compute histogram with coordinates as x,y
h, xe, ye = np.histogram2d(
xcoord.ravel(), ycoord.ravel(),
bins=[len(data[0, 0, :]), len(data[0, :, 0])],
weights=stars.ravel())
# Projected histograms inx and y
hx, hy = h.sum(axis=0), h.sum(axis=1)
# Define size of figure
fig = plt.figure(figsize=(20, 15))
gs = gridspec.GridSpec(10, 12)
# Define the positions of the subplots.
ax0 = plt.subplot(gs[6:10, 5:9])
axx = plt.subplot(gs[5:6, 5:9])
axy = plt.subplot(gs[6:10, 9:10])
ax0.imshow(h, cmap=plt.cm.viridis, interpolation='nearest',
origin='lower', vmin=0.)
# Remove tick labels
nullfmt = NullFormatter()
axx.xaxis.set_major_formatter(nullfmt)
axx.yaxis.set_major_formatter(nullfmt)
axy.xaxis.set_major_formatter(nullfmt)
axy.yaxis.set_major_formatter(nullfmt)
# Top plot
axx.plot(hx)
axx.set_xlim(ax0.get_xlim())
# Right plot
axy.plot(hy, range(len(hy)))
axy.set_ylim(ax0.get_ylim())
fig.tight_layout()
plt.savefig('del.png')
seaborn.jointplot 可能可以解决问题。
或者,如果您同意边缘分布全部垂直,则可以使用corner。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
N = 10000
D = 2
quantiles_1d = [0.16, 0.84] # 90% CI
sigmas_2d = (1 - np.exp(-0.5), 1 - np.exp(-2), 1 - np.exp(-9 / 2.0)) # 1, 2, 3 sigma
def generate_data(dim=2):
"""Generate some data."""
return pd.DataFrame({f"x[{i}]": np.random.normal(0, 1, N) for i in range(dim)})
def plot_with_corner(data: pd.DataFrame):
import corner
fig = corner.corner(
data,
smooth=0.9,
label_kwargs=dict(fontsize=30),
title_kwargs=dict(fontsize=16),
truth_color="tab:orange",
quantiles=quantiles_1d,
levels=sigmas_2d,
plot_density=False,
plot_datapoints=False,
fill_contours=True,
max_n_ticks=3,
verbose=False,
use_math_text=True,
)
plt.savefig("corner.png")
def plot_with_seaborn(data):
import seaborn as sns
kdeplot = sns.jointplot(
data=data, x="x[0]", y="x[1]",
kind="kde", fill=True,
space=0,
levels=100,
cbar=True,
common_norm=True,
)
lkwg = dict(linestyle="-", linewidth=2, color="k")
# overplot 1, 2, 3 sigma contours
sns.kdeplot(data=data, x="x[0]", y="x[1]", levels=sigmas_2d, ax=kdeplot.ax_joint, **lkwg)
# overplot 90% CI quantiles on marginals
for q in quantiles_1d:
kdeplot.ax_marg_x.vlines(data["x[0]"].quantile(q), *kdeplot.ax_marg_x.get_ylim(), **lkwg)
kdeplot.ax_marg_y.hlines(data["x[1]"].quantile(q), *kdeplot.ax_marg_y.get_xlim(), **lkwg)
# reposition colorbar to right of plot
# https://stackoverflow.com/a/60962023/10177759
plt.subplots_adjust(left=0.1, right=0.8, top=0.9, bottom=0.1)
pos_joint_ax = kdeplot.ax_joint.get_position()
pos_marg_x_ax = kdeplot.ax_marg_x.get_position()
kdeplot.ax_joint.set_position([pos_joint_ax.x0, pos_joint_ax.y0, pos_marg_x_ax.width, pos_joint_ax.height])
cbar_ax = kdeplot.fig.axes[-1]
cbar_ax.set_position([.83, pos_joint_ax.y0, .07, pos_joint_ax.height])
# # set ticks and labels for colorbar at sigmas_2d
_, cbar_max = cbar_ax.get_ylim()
cbar_sigma2d = [s * cbar_max for s in sigmas_2d]
cbar_ax.set_yticks(cbar_sigma2d)
cbar_ax.set_yticklabels([r"$3\sigma$", r"$2\sigma$", r"$1\sigma$"])
plt.savefig("seaborn.png")
if __name__ == "__main__":
data = generate_data(dim=D)
plot_with_corner(data)
plot_with_seaborn(data)