绘制分类数据时如何告诉数据着色器对 NA 值使用灰色

How to tell datashader to use gray color for NA values when plotting categorical data

我有非常大的数据集,无法使用全息视图直接绘制。我想用分类数据制作散点图。不幸的是,我的数据非常稀疏,很多点都以 NA 作为类别。我想把这些点变成灰色。有没有办法让datashader知道我想做什么?

我将向您展示我现在的做法(或多或少在 https://holoviews.org/user_guide/Large_Data.html 中提出)。 我给你举个例子:

import numpy as np
import pandas as pd
import holoviews as hv
hv.extension('bokeh')
import datashader as ds
from datashader.colors import Sets1to3
from holoviews.operation.datashader import datashade,spread



raw_data = [('Alice', 60, 'London', 5) ,
           ('Bob', 14, 'Delhi' , 7) ,
           ('Charlie', 66, np.NaN, 11) ,
           ('Dave', np.NaN,'Delhi' , 15) ,
           ('Eveline', 33, 'Delhi' , 4) ,
           ('Fred', 32, 'New York', np.NaN ),
           ('George', 95, 'Paris', 11)
            ]
# Create a DataFrame object
df = pd.DataFrame(raw_data, columns=['Name', 'Age', 'City', 'Experience'])
df['City']=pd.Categorical(df['City'])



x='Age'
y='Experience'
color='City'
cats=df[color].cat.categories





# Make dummy-points (currently the only way to make a legend: https://holoviews.org/user_guide/Large_Data.html)
for cat in cats:
    #Just to make clear how many points of a given category we have
    print(cat,((df[color]==cat)&(df[x].notnull())&(df[y].notnull())).sum())
color_key=[(name,color) for name, color in zip(cats,Sets1to3)]
color_points = hv.NdOverlay({n: hv.Points([0,0], label=str(n)).opts(color=c,size=0) for n,c in color_key})


# Create the plot with datashader
points=hv.Points(df, [x, y],label="%s vs %s" % (x, y),)
datashaded=datashade(points,aggregator=ds.by(color)).opts(width=800, height=480)

(spread(datashaded,px=4, shape='square')*color_points).opts(legend_position='right')

生成如下图:

您可以看到一些问题: 最重要的是,尽管只有一个人来自巴黎,但您会看到 NA 人(查理)也印有紫色,这是巴黎的颜色。有没有办法让点变成灰色?我试过很多图,似乎 NA 总是采用图例中最后一项的颜色。

还有一些我不想公开提问的小问题。 (如果您认为他们应该提出自己的问题,请告诉我,我是 Whosebug 的新手,感谢您的建议。)

另一个问题: 这些点的大小不尽相同。这很丑陋。有办法改变吗?

然后我还有一个问题:数据着色器内部是否也使用 .cat.categories 方法来决定使用什么颜色?数据着色器使用的颜色是如何确定的?因为我想知道图例是否始终处于正确的顺序(显示正确的颜色:如果您排列 cats 中的顺序,那么 color_keycats 不再是相同的顺序并且图例显示错误的颜色)。它似乎总是按照我的方式工作,但我觉得有点不安全。

也许有人想就 Points 在这种情况下是否可以用于散点图发表意见。因为我看不出 Scatter 有任何区别,而且在语义上并没有真正的一个变量导致另一个变量(尽管有人可能会争辩说在这种情况下年龄会导致经验,但我将在没有变量的地方绘制变量很容易找到这些因果关系)所以最好使用 Points 如果我正确理解文档 https://holoviews.org/reference/elements/bokeh/Points.html

Most importantly although there is just one person from Paris you see that the NA-person (Charlie) is also printed in purple, the color for Paris. Is there a way to make the dot gray? I have tried many plots and it seems like the NAs always take the color of the last item in the legend.

现在我相信 Datashader 会用零替换 NaN(参见 https://github.com/holoviz/datashader/blob/master/datashader/transfer_functions/__init__.py#L351)。似乎是一个很好的功能请求,能够为 Datashader 提供颜色以代替 NaN,但与此同时,我建议用实际类别名称替换 NaN,如“其他”、“缺失”或“未知” ,然后颜色和图例都应反映该名称。

One other problem: The dots are not all of the same size. This is quite ugly. Is there a way to change that?

通常,Bokeh HoloViews 图中的 Datashader 在放入 Bokeh 布局之前最初会渲染一次,并在布局完成最终版本后触发更新。在这里,初始渲染被自动调整到精确的数据点范围,然后被绘图的边界裁剪(使靠近边缘的正方形变成矩形),然后一旦图例被更新,绘图的范围就会更新。添加。要查看它是如何工作的,请删除 *color_points,您会看到相同形状的点,但现在被绘图边缘裁剪了:

您可以在绘图显示后通过稍微缩放或平移来手动触发更新,但要强制更新而不需要手动干预,您可以提供明确的绘图范围:

points=hv.Points(df, [x, y],label="%s vs %s" % (x, y),).redim.range(Age=(0,90), Experience=(0,14))

如果您能在 HoloViews 上提交错误报告,询问为什么在包含图例的情况下它不自动刷新,那就太好了。希望有一个简单的修复!

Does the datashader internally also use the .cat.categories-method to decide what color to use? How are the colors, that datashader uses, determined? Because I wonder whether the legend is always in correct order (showing the correct colors: If you permute the order in cats then color_key and cats are not in the same order anymore and the legend shows wrong colors). It seems to always work the way I do but I feel a bit insecure.

当然!每当您显示图例时,您应该确保将颜色键作为字典传递,以便您可以确保图例和绘图着色为每个类别使用相同的颜色。调用 datashade.

时传入 color_key={k:v for k,v in color_key}

And maybe someone wants to give their opinion whether Points is okay to use for scatterplots in this case. Because I do not see any difference to Scatter and also semantically there is not really one variable that causes the other (although one might argue that age causes experience in this case, but I am going to plot variables where it is not easy at all to find those kinds of causalities) so it is best to use Points if I understood the documentation https://holoviews.org/reference/elements/bokeh/Points.html correctly.

Points 用于两个轴可互换的平面中的二维位置,例如几何平面上的物理 x,y 位置。 Points 有两个独立的维度,并且希望你有任何依赖维度用于颜色、标记形状等。确实,如果你不知道哪个变量可能依赖于另一个,Scatter 就很难使用,但是简单地选择将某些东西放在 x 轴上会使人们认为该变量是独立的,因此对此无能为力。在这种情况下绝对不适合使用积分。