Python 基于线的热图或二维线直方图

Python 基于线的热图或二维线直方图,python,plot,heatmap,Python,Plot,Heatmap,我有一个合成数据集,其中包含1000个不同阶次的嘈杂多边形和正弦/余弦曲线,我可以使用python seaborn将其绘制为直线 因为我有很多重叠的线条,所以我想画一些热图或线条图的直方图。 我试着用seaborn的热图图对列进行迭代并汇总计数,但对于许多行,这需要相当长的时间 我想要的第二个最好的结果是hexbin图(带有seaborn jointgraph) 但这是运行时和粒度之间的折衷(图中显示的gridsize为750)。我找不到解决我的问题的任何其他图形类型。但我也不知道它到底叫什

我有一个合成数据集,其中包含1000个不同阶次的嘈杂多边形和正弦/余弦曲线,我可以使用python seaborn将其绘制为直线

因为我有很多重叠的线条,所以我想画一些热图或线条图的直方图。 我试着用seaborn的热图图对列进行迭代并汇总计数,但对于许多行,这需要相当长的时间

我想要的第二个最好的结果是hexbin图(带有seaborn jointgraph)

但这是运行时和粒度之间的折衷(图中显示的gridsize为750)。我找不到解决我的问题的任何其他图形类型。但我也不知道它到底叫什么

我还尝试将line alpha设置为0.2。这将产生一个类似于我想要的图形。但它的精确度较低(如果在同一点上有超过5条线重叠,我已经没有透明度了)。此外,它还忽略了典型的热图着色

(模拟搜索词有:热图、二维直线直方图、直线直方图、密度图……)


是否有人知道如何更高效、更高(er)质量地绘制此的软件包,或者知道如何使用流行的python绘图仪(即matplotlib系列:matplotlib、seaborn、bokeh)。不过,我对任何软件包都很满意。

尽管您似乎已经尝试过这个方法,但绘制计数似乎可以很好地表示数据。然而,这实际上取决于您试图在数据中找到什么,它应该告诉您什么

运行时间长的原因是绘制了如此多的线,但基于计数的热图绘制速度相当快

我根据噪声、线数、振幅和位移创建了一些窦波的虚拟数据。添加了箱线图和热图

import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
import random
import pandas as pd

np.random.seed(0)

#create dummy data
N = 200
sinuses = []
no_lines = 200
for i in range(no_lines):
    a = np.random.randint(5, 40)/5 #amplitude
    x = random.choice([int(N/5),  int(N/(2/5))]) #random shift
    sinuses.append(np.roll(a * np.sin(np.linspace(0, 2 * np.pi, N))  + np.random.randn(N), x))

fig = plt.figure(figsize=(20 / 2.54, 20 / 2.54))
sins = pd.DataFrame(sinuses, )

ax1 = plt.subplot2grid((3,10), (0,0), colspan=10)
ax2 = plt.subplot2grid((3,10), (1,0), colspan=10)
ax3 = plt.subplot2grid((3,10), (2,0), colspan=9)
ax4 = plt.subplot2grid((3,10), (2,9))

# plot line data
sins.T.plot(ax=ax1, color='lightblue',linewidth=.3)
ax1.legend_.remove()
ax1.set_xlim(0, N)

# try boxplot
sins.plot.box(ax=ax2, showfliers=False)
xticks = ax2.xaxis.get_major_ticks()
for index, label in enumerate(ax2.get_xaxis().get_ticklabels()):
    xticks[index].set_visible(False)  # hide ticks where labels are hidden

#make a list of bins
no_bins = 20
bins = list(np.arange(sins.min().min(), sins.max().max(), int(abs(sins.min().min())+sins.max().max())/no_bins))
bins.append(sins.max().max())

# calculate histogram
hists = []
for col in sins.columns:
    count, division = np.histogram(sins.iloc[:,col], bins=bins)
    hists.append(count)
hists = pd.DataFrame(hists, columns=[str(i) for i in bins[1:]])
print(hists.shape, '\n', hists.head())

cmap = mpl.colors.ListedColormap(['white', '#FFFFBB', '#C3FDB8', '#B5EAAA', '#64E986', '#54C571',
          '#4AA02C', '#347C17', '#347235', '#25383C', '#254117'])

#heatmap
im = ax3.pcolor(hists.T, cmap=cmap)
cbar = plt.colorbar(im, cax=ax4)

yticks = np.arange(0, len(bins))
yticklabels = hists.columns.tolist()
ax3.set_yticks(yticks)
ax3.set_yticklabels([round(i,1) for i in bins])
ax3.set_title('Count')
yticks = ax3.yaxis.get_major_ticks()

for index, label in enumerate(ax3.get_yaxis().get_ticklabels()):
    if index % 3 != 0: #make some labels invisible
        yticks[index].set_visible(False)  # hide ticks where labels are hidden

plt.show()

虽然箱线图很容易解释,但它不能很好地显示数据的实际分布,但是知道中位数和分位数的位置可能会有所帮助

增加行数和每行值的数量将显著增加线图的绘制时间,尽管生成热图仍然相当快。然而,箱线图变得难以辨认


我无法准确地复制您的数据(或知道数据的实际大小),但热图可能会有所帮助。

我花了一段时间,但我最终通过使用解决了这个问题。如果使用笔记本,这些绘图可以嵌入到交互式绘图中,看起来非常漂亮

无论如何,这里是静态图像的代码,以防其他人需要类似的东西:

# coding: utf-8
import time

import numpy as np
from numpy.polynomial import polynomial
import pandas as pd

import matplotlib.pyplot as plt
import datashader as ds
import datashader.transfer_functions as tf


plt.style.use("seaborn-whitegrid")

def create_data():
    # ...

# Each column is one data sample
df = create_data()

# Following will append a nan-row and reshape the dataframe into two columns, with each sample stacked on top of each other
#   THIS IS CRUCIAL TO OPTIMIZE SPEED: https://github.com/bokeh/datashader/issues/286

# Append row with nan-values
df = df.append(pd.DataFrame([np.array([np.nan] * len(df.columns))], columns=df.columns, index=[np.nan]))

# Reshape
x, y = df.shape
arr = df.as_matrix().reshape((x * y, 1), order='F')
df_reshaped = pd.DataFrame(arr, columns=list('y'), index=np.tile(df.index.values, y))
df_reshaped = df_reshaped.reset_index()
df_reshaped.columns.values[0] = 'x'

# Plotting parameters
x_range = (min(df.index.values), max(df.index.values))
y_range = (df.min().min(), df.max().max())
w = 1000
h = 750
dpi = 150
cvs = ds.Canvas(x_range=x_range, y_range=y_range, plot_height=h, plot_width=w)

# Aggregate data
t0 = time.time()
aggs = cvs.line(df_reshaped, 'x', 'y', ds.count())
print("Time to aggregate line data: {}".format(time.time()-t0))

# One colored plot
t1 = time.time()
stacked_img = tf.Image(tf.shade(aggs, cmap=["darkblue", "darkblue"]))
print("Time to create stacked image: {}".format(time.time() - t1))

# Save
f0 = plt.figure(figsize=(w / dpi, h / dpi), dpi=dpi)
ax0 = f0.add_subplot(111)
ax0.imshow(stacked_img.to_pil())
ax0.grid(False)
f0.savefig("stacked.png", bbox_inches="tight", dpi=dpi)

# Heat map - This uses a equalized histogram (built-in default), there are other options, though.
t2 = time.time()
heatmap_img = tf.Image(tf.shade(aggs, cmap=plt.cm.Spectral_r))
print("Time to create stacked image: {}".format(time.time() - t2))

# Save
f1 = plt.figure(figsize=(w / dpi, h / dpi), dpi=dpi)
ax1 = f1.add_subplot(111)
ax1.imshow(heatmap_img.to_pil())
ax1.grid(False)
f1.savefig("heatmap.png", bbox_inches="tight", dpi=dpi)
具有以下运行时间(以秒为单位):

结果图:

Time to aggregate line data: 0.7710442543029785
Time to create stacked image: 0.06000351905822754
Time to create stacked image: 0.05600309371948242