¿Cómo podemos formatear números en un gráfico Sankey y establecer etiquetas fuera del gráfico?

0

Tengo un código simple que produce un buen gráfico de 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")

ingrese la descripción de la imagen aquí

Desafortunadamente, los números son exponenciales. Realmente quiero que se muestren en millones. Además, ¿hay alguna manera de que las etiquetas de la derecha se muestren a la derecha y, al mismo tiempo, las etiquetas de la izquierda se muestren a la izquierda, de modo que estén todas fuera del gráfico y sean más fáciles de leer?

¡Gracias por tu tiempo!

2
  • Has etiquetado la pregunta con plotly, pero la usaste holoviewspara construir la figura. ¿A qué busca una respuesta? ¿El primero o el último? 13 oct a las 22:17
  • Bueno, pensé que esto requiere ambas bibliotecas. En realidad, no estoy seguro. Nunca antes había usado Sankey u holoviews. He usado plotly antes, pero no con un gráfico de Sankey.
    ASH
    13 oct a las 22:29
1

La siguiente solución funciona holoviewsy (probablemente) no es válida para plotly.

En holoviewspuede agregar hv.Dimension(spec, **params), lo que le brinda la oportunidad de aplicar un formateador con la palabra clave value_formata un nombre de columna. Este formateador puede ser creado de forma predefinida o defensiva. El siguiente ejemplo muestra cómo definir un formateador simple mediante una función personalizada de Python.

Código de ejemplo

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

Producción

Sanky con valores formateados

0
1

Primero, holoview permite la configuración de formateadores personalizados para dimensiones.

Para representar los números tal como están, puede usar la strfunción como formateador para la dimensión.

He utilizado un marco de datos de muestra para mostrar un ejemplo de cómo se puede lograr esto. Puede ejecutarlo en este cuaderno de colaboración ejecutable .

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)],
)

Ahora, para personalizar la posición de las etiquetas, necesita el gráfico renderizado.

Aquí lo estamos usando bokehcomo backend y podemos obtener el gráfico enviando el objeto gráfico como argumento al get_plotmétodo del bokehrenderizador.

renderer = Store.renderers['bokeh']
plot = renderer.get_plot(graph)

Ahora, podemos acceder a los manejadores de la trama que deseamos personalizar. El x_offsetvalor predeterminado que se aplica a todas las etiquetas es 0. Solo necesitamos aplicar compensaciones en las etiquetas de la izquierda.

Para hacerlo, aumentamos la fuente de datos de las etiquetas para incluir un campo 'x_offset' y establecemos el desplazamiento para las etiquetas que deseamos colocar en el lado izquierdo de los quads.

Además, necesitamos establecer el punto de partida de plot.xrangela trama para que no se corte.

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)

Por último, podemos convertir el gráfico en un componente SVG y mostrarlo en el cuaderno.

hv.ipython.notebook_extension('bokeh')
data, metadata = hv.ipython.display_hooks.render(plot, fmt='svg')
hv.ipython.display(hv.ipython.HTML(data["text/html"]))

Parcela Sankey con posiciones de etiquetas personalizadas.

1
  • ¡Funciona para mi! ¡¡Muchas gracias!!
    ASH
    17 oct a las 14:50