我们如何在桑基图中格式化数字并在图表外设置标签?
How can we format numbers in a Sankey chart and set labels outside of the chart?
我有一些简单的代码可以生成漂亮的桑基图。
import holoviews as hv
import plotly.graph_objects as go
import plotly.express as pex
hv.extension('bokeh')
sankey1 = hv.Sankey(df_final, kdims=['Sub_Market', 'Sport League'], vdims=["Revenue"])
hv.Sankey(sankey1)
sankey1.opts(cmap='Colorblind',label_position='right',
edge_color='Sub_Market', edge_line_width=0,
node_alpha=1.0, node_width=40, node_sort=True,
width=800, height=600, bgcolor="snow",
title="Flow of Revenue between Sub Market and Conference")
不幸的是,数字呈指数增长。我真的想让它们以百万为单位显示。还有,有没有办法让右边的标签显示在右边,同时让左边的标签显示在左边,这样都在图表之外,更容易阅读?
感谢您的宝贵时间!
下面的解决方案适用于 holoviews
,但(可能)对 plotly
无效。
在 holoviews
中,您可以添加 hv.Dimension(spec, **params)
,这样您就可以将带有关键字 value_format
的格式化程序应用于列名。此格式化程序可以预定义或定义创建。下面的示例显示了如何通过自定义 python 函数定义简单的格式化程序。
示例代码
import holoviews as hv
import pandas as pd
data = {'A':['XX','XY','YY','XY','XX','XX'],
'B':['RR','KK','KK','RR','RK','KK'],
'values':[1e6,5e5,8e4,15e3,19e2,1],
}
df = pd.DataFrame(data)
def fmt(tick):
if tick < 1e3:
unit = ''
num = round(tick,2)
elif tick < 1e6:
unit = 'k'
num = round(tick/1e3,2)
else:
unit = 'm'
num = round(tick/1e6,2)
return f'{num} {unit}'
hv.Sankey(df, vdims = hv.Dimension('values', value_format=fmt))
输出
首先,holoview 允许为维度配置自定义格式化程序。
要按原样呈现数字,您可以使用 str
函数作为维度的格式化程序。
我使用了一个示例数据框来展示如何实现这一点的示例。你可以 运行 它在 this runnable collab notebook.
import holoviews as hv
from holoviews.core import Store
import pandas as pd
hv.ipython.notebook_extension('bokeh')
Store.set_current_backend('bokeh')
renderer = Store.renderers['bokeh']
df_final = pd.DataFrame({
'Sub_Market': ['Central texas', 'Southern California', 'Florida'],
'Sport League': ['MLS', 'NBA', 'MLS'],
'Revenue': [1.4981211 * 10**5, 2.921212* 10**6, 1.2121112*10**6]
})
graph = hv.Sankey(
df_final,
kdims=['Sub_Market', 'Sport League'],
vdims=[hv.Dimension("Revenue", value_format=str)],
)
现在要自定义标签的位置,您需要渲染图。
这里我们使用 bokeh
作为后端,可以通过将图形对象作为参数转发给 bokeh
渲染器的 get_plot
方法来获取绘图。
renderer = Store.renderers['bokeh']
plot = renderer.get_plot(graph)
现在,我们可以访问我们希望自定义的绘图句柄。
应用于所有标签的默认 x_offset
值为 0
。
我们只需要在左侧标签上应用偏移量。
为此,我们扩充标签的数据源以包含一个 'x_offset' 字段,并为我们希望放置在四边形左侧的标签设置偏移量。
此外,我们需要设置plot.xrange
的起点,这样剧情就不会被截断。
offset = -200
num_nodes = len(plot.handles['text_1_source'].data['x'])
plot.handles['text_1_source'].data['x_offset'] = [0]* num_nodes
num_left_nodes = 3
left_nodes_selection = slice(0, num_left_nodes)
plot.handles['text_1_source'].data['x_offset'][left_nodes_selection] = [offset]* num_left_nodes
plot.handles['text_1_glyph'].x_offset = {'field': 'x_offset' }
plot.handles['plot'].x_range.start += (2*offset)
最后,我们可以将绘图渲染为 SVG 组件并将其显示在笔记本中。
hv.ipython.notebook_extension('bokeh')
data, metadata = hv.ipython.display_hooks.render(plot, fmt='svg')
hv.ipython.display(hv.ipython.HTML(data["text/html"]))
我有一些简单的代码可以生成漂亮的桑基图。
import holoviews as hv
import plotly.graph_objects as go
import plotly.express as pex
hv.extension('bokeh')
sankey1 = hv.Sankey(df_final, kdims=['Sub_Market', 'Sport League'], vdims=["Revenue"])
hv.Sankey(sankey1)
sankey1.opts(cmap='Colorblind',label_position='right',
edge_color='Sub_Market', edge_line_width=0,
node_alpha=1.0, node_width=40, node_sort=True,
width=800, height=600, bgcolor="snow",
title="Flow of Revenue between Sub Market and Conference")
不幸的是,数字呈指数增长。我真的想让它们以百万为单位显示。还有,有没有办法让右边的标签显示在右边,同时让左边的标签显示在左边,这样都在图表之外,更容易阅读?
感谢您的宝贵时间!
下面的解决方案适用于 holoviews
,但(可能)对 plotly
无效。
在 holoviews
中,您可以添加 hv.Dimension(spec, **params)
,这样您就可以将带有关键字 value_format
的格式化程序应用于列名。此格式化程序可以预定义或定义创建。下面的示例显示了如何通过自定义 python 函数定义简单的格式化程序。
示例代码
import holoviews as hv
import pandas as pd
data = {'A':['XX','XY','YY','XY','XX','XX'],
'B':['RR','KK','KK','RR','RK','KK'],
'values':[1e6,5e5,8e4,15e3,19e2,1],
}
df = pd.DataFrame(data)
def fmt(tick):
if tick < 1e3:
unit = ''
num = round(tick,2)
elif tick < 1e6:
unit = 'k'
num = round(tick/1e3,2)
else:
unit = 'm'
num = round(tick/1e6,2)
return f'{num} {unit}'
hv.Sankey(df, vdims = hv.Dimension('values', value_format=fmt))
输出
首先,holoview 允许为维度配置自定义格式化程序。
要按原样呈现数字,您可以使用 str
函数作为维度的格式化程序。
我使用了一个示例数据框来展示如何实现这一点的示例。你可以 运行 它在 this runnable collab notebook.
import holoviews as hv
from holoviews.core import Store
import pandas as pd
hv.ipython.notebook_extension('bokeh')
Store.set_current_backend('bokeh')
renderer = Store.renderers['bokeh']
df_final = pd.DataFrame({
'Sub_Market': ['Central texas', 'Southern California', 'Florida'],
'Sport League': ['MLS', 'NBA', 'MLS'],
'Revenue': [1.4981211 * 10**5, 2.921212* 10**6, 1.2121112*10**6]
})
graph = hv.Sankey(
df_final,
kdims=['Sub_Market', 'Sport League'],
vdims=[hv.Dimension("Revenue", value_format=str)],
)
现在要自定义标签的位置,您需要渲染图。
这里我们使用 bokeh
作为后端,可以通过将图形对象作为参数转发给 bokeh
渲染器的 get_plot
方法来获取绘图。
renderer = Store.renderers['bokeh']
plot = renderer.get_plot(graph)
现在,我们可以访问我们希望自定义的绘图句柄。
应用于所有标签的默认 x_offset
值为 0
。
我们只需要在左侧标签上应用偏移量。
为此,我们扩充标签的数据源以包含一个 'x_offset' 字段,并为我们希望放置在四边形左侧的标签设置偏移量。
此外,我们需要设置plot.xrange
的起点,这样剧情就不会被截断。
offset = -200
num_nodes = len(plot.handles['text_1_source'].data['x'])
plot.handles['text_1_source'].data['x_offset'] = [0]* num_nodes
num_left_nodes = 3
left_nodes_selection = slice(0, num_left_nodes)
plot.handles['text_1_source'].data['x_offset'][left_nodes_selection] = [offset]* num_left_nodes
plot.handles['text_1_glyph'].x_offset = {'field': 'x_offset' }
plot.handles['plot'].x_range.start += (2*offset)
最后,我们可以将绘图渲染为 SVG 组件并将其显示在笔记本中。
hv.ipython.notebook_extension('bokeh')
data, metadata = hv.ipython.display_hooks.render(plot, fmt='svg')
hv.ipython.display(hv.ipython.HTML(data["text/html"]))