Datashader:使用手动 RGB 颜色绘图
Datashader: plot with manual RGB colors
我想使用 python 中的 Datashader 模块做类似于 pyplot.scatter
的事情,为每个点独立指定一个单独的 (x,y), RGB\hex 值:
#what i'd like to do, but using Datashader:
import numpy as np
#make sample arrays
n = int(1e+8)
point_array = np.random.normal(0, 1, [n, 2])
color_array = np.random.randint(0, 256, [n, 3])/255 # RGB. I can
#convert between it and hex if needed
#the part I need - make an image similar to plt.scatter, using datashader instead:
import matplotlib.pyplot as plt
fig = plt.figure()
plot = fig.add_subplot(111)
fig.canvas.draw()
plot.scatter(point_array[:, 0], point_array[:, 1], c=color_array)
img = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
因此 img
是一个 RGB numpy 数组(或 PIL 数组,或任何可以通过 python 保存为图像的数组)
我尝试过的事情
我看过 datashader.Canvas.points
以及它如何处理 3 维 pandas 数组,我认为我可以将它与仅红色、仅绿色和仅"linear interpolation" 的蓝色值在标签之间,但我没能真正让它发挥作用(陷入了 pandas 的困境,因为我大部分时间都只使用 numpy)。
我认为你上面的代码可以简化为:
import numpy as np, pandas as pd, matplotlib.pyplot as plt
%matplotlib inline
np.random.seed(0)
n = int(1e+4)
p = np.random.normal(0, 1, [n, 2])
c = np.random.randint(0, 256, [n, 3])/255.0
plt.scatter(p[:,0], p[:,1], c=c);
如果数据着色器提供一种方便的方法来处理 RGB 值,那就太好了(请随意打开一个问题请求!),但现在您可以计算每个点的平均 R、G、B 值:
import datashader as ds, datashader.transfer_functions as tf
df = pd.DataFrame.from_dict(dict(x=p[:,0], y=p[:,1], r=c[:,0], g=c[:,1], b=c[:,2]))
cvs = ds.Canvas(plot_width=70, plot_height=40)
a = cvs.points(df,'x','y', ds.summary(r=ds.mean('r'),g=ds.mean('g'),b=ds.mean('b')))
结果将是包含 r、g、b 通道的 Xarray 数据集,每个通道的比例为 0 到 1.0。然后,您可以根据需要将这些通道组合成图像,例如使用 HoloViews:
import holoviews as hv
hv.extension('bokeh')
hv.RGB(np.dstack([a.r.values, a.g.values, a.b.values])).options(width=450, invert_yaxis=True)
请注意,Datashader 目前仅支持无限小的点,而不是 disks/filled 圆圈,就像您的 Matplotlib 示例一样,这就是为什么我使用如此小的分辨率(使点可见以进行比较)。扩展 Datashader 以呈现具有非零范围的形状会很有用,但它不在当前路线图上。
我想使用 python 中的 Datashader 模块做类似于 pyplot.scatter
的事情,为每个点独立指定一个单独的 (x,y), RGB\hex 值:
#what i'd like to do, but using Datashader:
import numpy as np
#make sample arrays
n = int(1e+8)
point_array = np.random.normal(0, 1, [n, 2])
color_array = np.random.randint(0, 256, [n, 3])/255 # RGB. I can
#convert between it and hex if needed
#the part I need - make an image similar to plt.scatter, using datashader instead:
import matplotlib.pyplot as plt
fig = plt.figure()
plot = fig.add_subplot(111)
fig.canvas.draw()
plot.scatter(point_array[:, 0], point_array[:, 1], c=color_array)
img = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
因此 img
是一个 RGB numpy 数组(或 PIL 数组,或任何可以通过 python 保存为图像的数组)
我尝试过的事情
我看过 datashader.Canvas.points
以及它如何处理 3 维 pandas 数组,我认为我可以将它与仅红色、仅绿色和仅"linear interpolation" 的蓝色值在标签之间,但我没能真正让它发挥作用(陷入了 pandas 的困境,因为我大部分时间都只使用 numpy)。
我认为你上面的代码可以简化为:
import numpy as np, pandas as pd, matplotlib.pyplot as plt
%matplotlib inline
np.random.seed(0)
n = int(1e+4)
p = np.random.normal(0, 1, [n, 2])
c = np.random.randint(0, 256, [n, 3])/255.0
plt.scatter(p[:,0], p[:,1], c=c);
如果数据着色器提供一种方便的方法来处理 RGB 值,那就太好了(请随意打开一个问题请求!),但现在您可以计算每个点的平均 R、G、B 值:
import datashader as ds, datashader.transfer_functions as tf
df = pd.DataFrame.from_dict(dict(x=p[:,0], y=p[:,1], r=c[:,0], g=c[:,1], b=c[:,2]))
cvs = ds.Canvas(plot_width=70, plot_height=40)
a = cvs.points(df,'x','y', ds.summary(r=ds.mean('r'),g=ds.mean('g'),b=ds.mean('b')))
结果将是包含 r、g、b 通道的 Xarray 数据集,每个通道的比例为 0 到 1.0。然后,您可以根据需要将这些通道组合成图像,例如使用 HoloViews:
import holoviews as hv
hv.extension('bokeh')
hv.RGB(np.dstack([a.r.values, a.g.values, a.b.values])).options(width=450, invert_yaxis=True)
请注意,Datashader 目前仅支持无限小的点,而不是 disks/filled 圆圈,就像您的 Matplotlib 示例一样,这就是为什么我使用如此小的分辨率(使点可见以进行比较)。扩展 Datashader 以呈现具有非零范围的形状会很有用,但它不在当前路线图上。