简体   繁体   English

使用 Python 在 3D 轴上绘制直方图

[英]Plotting histograms on 3D axes with Python

I am trying to plot a few histograms on a 3d axis using the PolyCollection function, my desired plot looks something like this: (except of course the coloured plots are histograms) I am trying to plot a few histograms on a 3d axis using the PolyCollection function, my desired plot looks something like this: (except of course the coloured plots are histograms) 在此处输入图像描述

For me, my x-values are the distribution of values of a parameter C_l, y-values are the values of l (ranging from 2 to 33) and z is the frequency of each C_l (so the histogram is on the xz plane, with y specifying the histogram for each value of l).对我来说,我的 x 值是参数 C_l 的值的分布,y 值是 l 的值(范围从 2 到 33),z 是每个 C_l 的频率(所以直方图在 xz 平面上, y 为 l) 的每个值指定直方图。 This is the code I have but I can't seem to get it to work:这是我拥有的代码,但我似乎无法让它工作:

fig = plt.figure()
ax = fig.gca(projection='3d')
nside=16

'multi_dens_auto_cl_dist is just a 33x1001 matrix of all the C_l values, with the rows denoting each iteration I calculated previously and the columns being the l's)
xs=np.linspace(multi_dens_auto_cl_dist.min(),multi_dens_auto_cl_dist.max(),num=1001)

def cc(arg):
    return mcolors.to_rgba(arg, alpha=0.6)

verts = []
zs = np.arange(2,2*nside+1,1)

for z in zs:
    ys,binvals,_ = plt.hist(multi_dens_auto_cl_dist[:][z],bins=xs)
    ys[0], ys[-1] = 0, 0
    verts.append(list(zip(xs, ys)))

poly = PolyCollection(verts,facecolors=[cc('r'), cc('g'), cc('b'), cc('y')]*4+[cc('r')])
poly.set_alpha(0.7)
ax.add_collection3d(poly, zs=zs, zdir='y')

ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')


plt.title('Density auto power spectrum distribution')
plt.show()

Any help would be greatly appreciated thank you!任何帮助将不胜感激,谢谢!

Data file of multi_dens_auto_cl_dist multi_dens_auto_cl_dist 的数据文件

There are still several unknowns here.这里还有几个未知数。 For one, it is still unclear what the structure of your dataframe is.一方面,目前还不清楚你的 dataframe 的结构是什么。 Even more problematic, we don't know how you want to create your histograms.更有问题的是,我们不知道您想如何创建直方图。 Your code creates 1001 bins for 1001 data points.您的代码为 1001 个数据点创建了 1001 个 bin。 Why?为什么? It is also not clear why you try to create polygon shapes when a histogram is a specific type of bar chart.当直方图是特定类型的条形图时,为什么要尝试创建多边形形状也不清楚。 I have tried to keep the script as flexible as possible given these unknowns:考虑到这些未知因素,我试图使脚本尽可能灵活:

from matplotlib import pyplot as plt
import numpy as np
from cycler import cycler
import pandas as pd

inputarr = np.loadtxt("data.txt")
df = pd.DataFrame(inputarr.reshape(1001, 33))
#determine the number of columns
ncol = df.shape[1]

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(projection="3d")

#since you have so many columns, it is difficult to give them all unique colors
#but we can define through which colors we cycle
#you could also create a range of colors along a color map and give each histogram 
#its unique color, which would then be similar to neighbouring colors
color_cycler = (cycler(color=["tab:orange", "yellow", "red", "blue", "green"]))
ax.set_prop_cycle(color_cycler)

#define the yticks, i.e., the column numbers
yticks = np.arange(ncol)

#just to demonstrate that bins don't have to be evenly spaced, we define normalized bins 
xbinnorm = [0, 0.1, 0.2, 0.3, 0.5, 1]
#we adapt the normalized bins to the minimum and maximum of the entire dataframe
xbins = [df.min().min() + i * (df.max().max()-df.min().min()) for i in xbinnorm]

#calculate now the histogram and plot it for each column
for ytick in yticks:
    
    #extract the current column from your df by its number
    col =  df.iloc[:, ytick]
    
    #determine the histogram values, here you have to adapt it to your needs
    histvals, edges = np.histogram(col, bins=xbins)
    
    #calculate the center and width of each bar
    #obviously not necessary to do this for each column if you always have the same bins 
    #but if you choose for np.histogram other parameters, the bins may not be the same for each histogram
    xcenter = np.convolve(edges, np.ones(2), "valid")/2
    xwidth = np.diff(edges)

    #plot the histogram as a bar for each bin
    ax.bar(left=xcenter, height=histvals, width=xwidth, zs=ytick, zdir="y", alpha=0.666)

ax.set_xlabel("bin")
ax.set_ylabel("column")
ax.set_zlabel("value")

#label every other column number
ax.set_yticks(yticks[::2])
#label bin edges, obviously only possible if all have the same bins
ax.set_xticks(xbins)

plt.show()

Sample output:样品 output:

在此处输入图像描述

Update更新
Given that we actually see in your data a development, a continuous colormap might be more informative (and cause less ophthalmological emergencies).鉴于我们实际上在您的数据中看到了发展,连续的颜色图可能会提供更多信息(并减少眼科紧急情况)。 Not much change needed to achieve this.实现这一目标不需要太多改变。

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd

inputarr = np.loadtxt("data.txt")
df = pd.DataFrame(inputarr.reshape(1001, 33))
#determine the number of columns
ncol = df.shape[1]

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(projection="3d")

#define the colormap 
my_cmap = plt.cm.inferno

#define the yticks, i.e., the column numbers
yticks = np.arange(ncol)

#just to demonstrate that bins don't have to be evenly spaced, we define normalized bins 
xbinnorm = [0, 0.1, 0.3, 0.5, 0.8, 1]
#we adapt the normalized bins to the minimum and maximum of the entire dataframe
xbins = [df.min().min() + i * (df.max().max()-df.min().min()) for i in xbinnorm]

#calculate now the histogram and plot it for each column
for i, ytick in enumerate(yticks):

    #extract the current column from your df by its number
    col =  df.iloc[:, ytick]

    #determine the histogram values, here you have to adapt it to your needs
    histvals, edges = np.histogram(col, bins=xbins)

    #calculate the center and width of each bar
    #obviously not necessary to do this for each column if you always have the same bins 
    #but if you choose for np.histogram other parameters, the bins may not be the same for each histogram
    xcenter = np.convolve(edges, np.ones(2), "valid")/2
    xwidth = np.diff(edges)

    #plot the histogram as a bar for each bin
    #now with continuous color mapping and edgecolor, so we can better see all bars
    ax.bar(left=xcenter, height=histvals, width=xwidth, zs=ytick, zdir="y", color=my_cmap(1-i/ncol), alpha=0.666, edgecolor="grey")

ax.set_xlabel("bin")
ax.set_ylabel("column")
ax.set_zlabel("value")

#label every other column number
ax.set_yticks(yticks[::2])
#label bin edges, obviously only possible if all have the same bins
ax.set_xticks(xbins)

plt.show()

Sample output (with different bins):样品 output(具有不同的 bin): 在此处输入图像描述

This version can also easily adapted to the bins="auto" option in np.histogram by removing everything related to xbins .通过删除与xbins相关的所有内容,此版本还可以轻松适应np.histogram中的bins="auto"选项。 Sample output with view from the opposite site:样品 output 与对面站点的视图:

在此处输入图像描述

Update2更新2

Given your data structure, you most likely prefer evenly spaced bins.鉴于您的数据结构,您很可能更喜欢均匀间隔的 bin。 In this case, we don't have to calculate the bar position for each slice individually.在这种情况下,我们不必单独计算每个切片的条形 position。

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd

inputarr = np.loadtxt("data.txt")
df = pd.DataFrame(inputarr.reshape(1001, 33))
#determine the number of columns
ncol = df.shape[1]

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(projection="3d")

#define the colormap 
my_cmap = plt.cm.inferno

#define the yticks, i.e., the column numbers
yticks = np.arange(ncol)

#we create evenly spaced bins between the minimum and maximum of the entire dataframe
xbins = np.linspace(df.min().min(), df.max().max(), 100)
#and calculate the center and widths of the bars
xcenter = np.convolve(xbins, np.ones(2), "valid")/2
xwidth = np.diff(xbins)

#calculate now the histogram and plot it for each column
for i, ytick in enumerate(yticks):

    #extract the current column from your df by its number
    col =  df.iloc[:, ytick]

    #determine the histogram values, here you have to adapt it to your needs
    histvals, _ = np.histogram(col, bins=xbins)

    #plot the histogram as a bar for each bin
    #now with continuous color mapping and edgecolor, but thinner lines, so we can better see all bars
    ax.bar(left=xcenter, height=histvals, width=xwidth, zs=ytick, zdir="y", color=my_cmap(i/ncol), alpha=0.666, edgecolor="grey", linewidth=0.3)

ax.set_xlabel("bin")
ax.set_ylabel("column")
ax.set_zlabel("value")

#label every other column number
ax.set_yticks(yticks[::2])
ax.set_zlim3d(0,60)
plt.show()

Sample output (view from the opposite site, the first histograms are cut off because of excessive values in comparison to the rest):示例 output(从对面站点查看,第一个直方图由于与其他直方图相比值过多而被截断):

![![在此处输入图像描述

Disclaimer: The rolling mean calculation was adapted from this SO answer .免责声明:滚动平均值计算改编自这个 SO answer

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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