两个轴都已排序的 Holoviews 热图

Holoviews heatmap with both axes sorted

我有以下代码使用 pandas 和全息视图生成热图:

cols = ['source','sink','net','avg']
data = [['13002','13002',5.0,2.161478e+06],
['13002','13003',5.0,6.959788e+04],
['13002','23002',5.0,4.233500e+03],
['13002','33006',5.0,8.104000e+03],
['13002','43002',5.0,9.374625e+05],
['13002','43004',5.0,2.865538e+03],
['13002','53001',5.0,1.737890e+05],
['13002','53008',5.0,3.693100e+04],
['13002','53017',5.0,4.541660e+05],
['13002','unk',23.0,1.205498e+05],
['13003','13002',23.0,2.275744e+05],
['13003','43002',23.0,3.250252e+05],
['13003','43003',23.0,4.248433e+04],
['13003','43008',23.0,7.541023e+04],
['13003','53012',23.0,5.000000e+02],
['13003','unk',23.0,5.247462e+03],
['13005','43004',23.0,2.355648e+05],
['23002','13002',23.0,1.317475e+05],
['23002','13003',23.0,1.000000e+04],
['23002','53008',23.0,4.716667e+03]]

df = pd.DataFrame(data, columns=cols)

hm = hv.HeatMap(data, kdims = ['source','sink']
                , vdims =['net', 'avg']).sort(['sink','source'])
layout = hv.Layout([hm])
layout.opts(
    opts.HeatMap(xticks=None, tools=['hover'], xrotation=90)
)

它产生以下内容:

请注意,x 轴 ('source') 的排序不正确。我尝试使用 'sort()' 但它似乎只能对一个轴或另一个轴进行排序。如何使两个轴都针对全息视图热图正确排序?

最佳解决方法 -

到目前为止,我可以通过执行以下操作来绕过它:

df = pd.DataFrame(data, columns=cols)
temp = pd.Series(df.sink.unique(),name='sink').sort_values()
df = df.groupby('source').apply(lambda x: x.merge(temp, how='outer', on='sink'))
df.source = df.source.ffill()
df = df.fillna(0).droplevel([0])

hm = hv.HeatMap(df, kdims = ['source', 'sink']
                , vdims =['net', 'avg']).sort()
layout = hv.Layout([hm])
layout.opts(
    opts.HeatMap(xticks=None, tools=['hover'], xrotation=90)
)

要实现这种类型的独立排序,您需要手动指定顺序。您可以通过定义维度来预先执行此操作,也可以在创建绘图时重新调整以设置值。

预先定义Dimension

# np.unique sorts the unique values by default
source = hv.Dimension("source", values=np.unique(df["source"]))
sink = hv.Dimension("sink", values=np.unique(df["sink"]))

(hv.HeatMap(df, kdims = [source, sink], vdims =['net', 'avg'])
 .opts(xticks=None, tools=['hover'], xrotation=90)
)

之后使用redim.values设置维度值

(hv.HeatMap(data, kdims = ["source", "sink"], vdims =['net', 'avg'])
 .opts(xticks=None, tools=['hover'], xrotation=90)
 .redim.values(
     sink=np.unique(df["sink"]),
     source=np.unique(df["source"]))
)

无论哪种情况,您最终都会得到如下所示的情节:

更合适的解决方案是使用@Riddell 的解决方案,但对于重新维度使用:

.redim.values(x=temp['x'].sort_values(), y=temp['y'].sort_values())

为了完成,我强烈建议使用钩子来修改散景的图x_range参数。

cols = ['source','sink','net','avg']
data = [['13002','13002',5.0,2.161478e+06],
['13002','13003',5.0,6.959788e+04],
['13002','23002',5.0,4.233500e+03],
['13002','33006',5.0,8.104000e+03],
['13002','43002',5.0,9.374625e+05],
['13002','43004',5.0,2.865538e+03],
['13002','53001',5.0,1.737890e+05],
['13002','53008',5.0,3.693100e+04],
['13002','53017',5.0,4.541660e+05],
['13002','unk',23.0,1.205498e+05],
['13003','13002',23.0,2.275744e+05],
['13003','43002',23.0,3.250252e+05],
['13003','43003',23.0,4.248433e+04],
['13003','43008',23.0,7.541023e+04],
['13003','53012',23.0,5.000000e+02],
['13003','unk',23.0,5.247462e+03],
['13005','43004',23.0,2.355648e+05],
['23002','13002',23.0,1.317475e+05],
['23002','13003',23.0,1.000000e+04],
['23002','53008',23.0,4.716667e+03]]

df = pd.DataFrame(data, columns=cols)

def hook(plot, element):
    plot.handles['x_range'].factors = sorted(df['source'].unique())
hm = hv.HeatMap(data, kdims = ['source','sink']
                , vdims =['net', 'avg']).opts(hooks=[hook])
layout = hv.Layout([hm])

layout.opts(
    hv.opts.HeatMap(xticks=None, tools=['hover'], xrotation=90)
)

根据数据的大小,修改散景 x_range 可能比处理 pandas 操作快得多。而且代码更清晰一些,只添加了两行。

缺点是你想使用其他渲染器,如 matplotlib。