python 我们如何在Sankey图表中格式化数字并在图表外部设置标签?

cnh2zyt3  于 2023-05-21  发布在  Python
关注(0)|答案(2)|浏览(177)

我有一些简单的代码,可以生成一个漂亮的Sankey图表。

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")

不幸的是,这些数字呈指数级增长。我真的想把它们以百万计展示出来。还有,有没有一种方法可以让右边的标签显示在右边,同时让左边的标签显示在左边,这样它们都在图表之外,更容易阅读?

o2rvlv0m

o2rvlv0m1#

下面的解决方案适用于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))

输出

wfveoks0

wfveoks02#

首先,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作为后端,可以通过将graph对象作为参数转发给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"]))

相关问题