plotly / plotly.py

The interactive graphing library for Python :sparkles: This project now includes Plotly Express!
https://plotly.com/python/
MIT License
15.98k stars 2.53k forks source link

node positions do not work with link value zero in Sankey #2152

Open rubenbfeld opened 4 years ago

rubenbfeld commented 4 years ago

Hello, I'm new to the plot.ly lib but I already discovered an issue. If there is a node with:

the manual positioning doesn't work anymore except if you delete the relating coordinates of this node and keep the node in the list (see third example).

Below you can find a short testing code with the generated output.

working example

import plotly.graph_objects as go
data=go.Sankey(
    arrangement = "freeform",
    node = {
        "label": ["A", "B", "C", "D", "E", "F"],
        "x": [0.2, 0.1, 0.9, 0.7, 0.3, 0.9],
        "y": [0.1, 0.9, 0.2, 0.1, 0.9, 0.9],
        'pad':100},  # 10 Pixels 
    link = {
        "source": [0, 0, 1, 4, 4, 3, 3],
        "target": [1, 3, 4, 3, 5, 2, 5],
        "value": [3, 3, 5, 4, 10, 1, 7 ]})
fig_sankey = go.Figure(data=data)
fig_sankey.show()

newplot(6)

node with only one link with value of zero

import plotly.graph_objects as go
data=go.Sankey(
    arrangement = "freeform",
    node = {
        "label": ["A", "B", "C", "D", "E", "F"],
        "x": [0.2, 0.1, 0.9, 0.7, 0.3, 0.9],
        "y": [0.1, 0.9, 0.2, 0.1, 0.9, 0.9],
        'pad':100},  # 10 Pixels 
    link = {
        "source": [0, 0, 1, 4, 4, 3, 3],
        "target": [1, 3, 4, 3, 5, 2, 5],
        "value": [3, 3, 5, 4, 10, 0, 7 ]})
fig_sankey = go.Figure(data=data)
fig_sankey.show()

newplot(7)

kind of working again cause coordinates of C are deleted

import plotly.graph_objects as go
data=go.Sankey(
    arrangement = "freeform",
    node = {
        "label": ["A", "B", "C", "D", "E", "F"],
        "x": [0.2, 0.1, 0.7, 0.3, 0.9],
        "y": [0.1, 0.9, 0.1, 0.9, 0.9],
        'pad':100},  # 10 Pixels 
    link = {
        "source": [0, 0, 1, 4, 4, 3, 3],
        "target": [1, 3, 4, 3, 5, 2, 5],
        "value": [3, 3, 5, 4, 10, 0, 7 ]})
fig_sankey = go.Figure(data=data)
fig_sankey.show()

newplot(12)

smarti57 commented 3 years ago

As of today, this is still an issue. While I find plotly generally useful and appreciate the work, the sankey interface is not a high point.

Panbati commented 2 years ago

Hi guys,

Don't know if this helps you, but I maybe found a workaround for this, at least for my use case. This is my first post on Github, so excuse any weird rambling or lack of structure.

My understanding is that when a value = 0, it shifts the relationship between source and target. My value dictionary consists of dataframe rows since I retrieve it from a SQL database.

I built a simple function which just checks if the data in values is 0 or not.

def test(index: int, values: list): if values[index] == 0: return None else: return index

I do this because I build my value, source and target as lists first, then throw them as a dictionary in link. When you throw None in source or target, it just eliminates that specific flow. So in my mind, you can never have a node with a flow of 0, because that's technically just an empty flow.

So, originally my source : source = [ 0,0 ,2,2 ,3,3 ,4,4 ,6,6,6 ]

So what I did was just replace all those numbers, since they are technically indexes for my dataframe. I implemented this into my source list. As a quick example my source then became: source = [test(0, value), test(0, value), test(2, value), test(2, value), test(3, value), test(3, value), test(4, value), test(4, value), test(6, value), test(6, value), test(6, value)]

This should not change the structure, in the end leaving your formatting as is.

Let me know if you have any questions or of this works for you or not. For me it works by removing the sources with dead targets.