Визуализация данных временных рядов узлов графа в виде графика - PullRequest
2 голосов
/ 09 марта 2020

У меня есть график, созданный в Networkx и построенный с использованием графика

Код:

import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import plotly.graph_objects as go

from pprint import pprint
from collections import OrderedDict


def get_edge_trace(G):
    edge_x = []
    edge_y = []
    for edge in G.edges():
        x0, y0 = G.nodes[edge[0]]['pos']
        x1, y1 = G.nodes[edge[1]]['pos']
        edge_x.append(x0)
        edge_x.append(x1)
        edge_x.append(None)
        edge_y.append(y0)
        edge_y.append(y1)
        edge_y.append(None)

    edge_trace = go.Scatter(
        x=edge_x, y=edge_y,
        line=dict(width=0.5, color='#888'),
        hoverinfo='none',
        mode='lines')
    return edge_trace


def get_node_trace(G):
    node_x = []
    node_y = []
    for node in G.nodes():
        x, y = G.nodes[node]['pos']
        node_x.append(x)
        node_y.append(y)

    node_trace = go.Scatter(
        x=node_x, y=node_y,
        mode='markers',
        hoverinfo='text',
        marker=dict(
            showscale=True,
            # colorscale options
            # 'Greys' | 'YlGnBu' | 'Greens' | 'YlOrRd' | 'Bluered' | 'RdBu' |
            # 'Reds' | 'Blues' | 'Picnic' | 'Rainbow' | 'Portland' | 'Jet' |
            # 'Hot' | 'Blackbody' | 'Earth' | 'Electric' | 'Viridis' |
            colorscale='YlGnBu',
            reversescale=True,
            color=[],
            size=10,
            colorbar=dict(
                thickness=15,
                title='Node Connections',
                xanchor='left',
                titleside='right'
            ),
            line_width=2))

    return node_trace


if __name__ == '__main__':

    tail = [1, 2, 3]
    head = [2, 3, 4]

    xpos = [0, 1, 2, 3]
    ypos = [0, 0, 0, 0]
    xpos_ypos = [(x, y) for x, y in zip(xpos, ypos)]

    ed_ls = [(x, y) for x, y in zip(tail, head)]
    G = nx.OrderedDiGraph()
    G.add_edges_from(ed_ls)


    pos = OrderedDict(zip(G.nodes, xpos_ypos))
    nx.draw(G, pos=pos, with_labels=True)
    nx.set_node_attributes(G, pos, 'pos')

    plt.show()

    # convert to plotly graph
    edge_trace = get_edge_trace(G)
    node_trace = get_node_trace(G)

    pprint(edge_trace)
    pprint(node_trace)

    fig = go.Figure(data=[edge_trace, node_trace],
                    layout=go.Layout(
                        title='<br>Network graph made with Python',
                        titlefont_size=16,
                        showlegend=False,
                        hovermode='closest',
                        margin=dict(b=20, l=5, r=5, t=40),
                        annotations=[dict(
                            text="Python code: <a href='https://plot.ly/ipython-notebooks/network-graphs/'> https://plot.ly/ipython-notebooks/network-graphs/</a>",
                            showarrow=False,
                            xref="paper", yref="paper",
                            x=0.005, y=-0.002)],
                        xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
                        yaxis=dict(showgrid=False, zeroline=False, showticklabels=False))
                    )
    fig.write_html('plot.html', auto_open=True)

Вывод:

enter image description here

Данные временных рядов узлов на приведенном выше графике считываются из столбцов фрейма данных, представленных ниже:

import plotly.graph_objects as go
import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randint(0, 100, size=(20, 5)), columns=list('tABCD'))

fig = go.Figure()
fig.add_trace(go.Scatter(
                x=df.t,
                y=df['A'],
                name="1",
                line_color='deepskyblue',
                opacity=0.8))

fig.add_trace(go.Scatter(
                x=df.t,
                y=df['B'],
                name="2",
                line_color='dimgray',
                opacity=0.8))

fig.add_trace(go.Scatter(
                x=df.t,
                y=df['C'],
                name="3",
                line_color='blue',
                opacity=0.8))

fig.add_trace(go.Scatter(
                x=df.t,
                y=df['D'],
                name="4",
                line_color='red',
                opacity=0.8))

fig.write_html('ts.html', auto_open=True)

Я хочу связать два вышеупомянутых графика, т.е. я хочу создать графики интерактивный. Например, я хотел бы иметь два вспомогательных участка с графиком временных рядов слева и графиком Networkx справа. Я хотел бы отобразить графики временных рядов, соответствующие узлам, выбранным на графике Networkx. Например, если выбраны узлы с метками 1 и 4, данные временного ряда, соответствующие name= 1 и name = 4, должны отображаться слева.

Любые предложения о том, как это сделать, будут действительно полезны.

РЕДАКТИРОВАТЬ: я нашел это , мы могли выбирать и отменять линии на графике, нажав на легенду. Кроме того, я хотел бы выбрать и отменить выбор линий, нажав на узлы в графе Networkx.

РЕДАКТИРОВАТЬ 2: Для создания подзаголовков

import plotly.graph_objects as go
import numpy as np
import pandas as pd
from plotly.subplots import make_subplots

df = pd.DataFrame(np.random.randint(0, 100, size=(20, 5)), columns=list('tABCD'))
df2 = pd.DataFrame(np.random.randint(0, 100, size=(20, 5)), columns=list('tABCD'))

fig = go.Figure()
fig = make_subplots(rows=1, cols=2)

fig.add_trace(go.Scatter(
                x=df.t,
                y=df['A'],
                name="1",
                line_color='deepskyblue',
                opacity=0.8,
                legendgroup='group1'),
                row=1, col=1
                )

fig.add_trace(go.Scatter(
                x=df.t,
                y=df['B'],
                name="2",
                line_color='dimgray',
                opacity=0.8,
                legendgroup='group2'),
                row=1, col=1
                )

fig.add_trace(go.Scatter(
                x=df.t,
                y=df['C'],
                name="3",
                line_color='blue',
                opacity=0.8,
                legendgroup='group3'),
                row=1, col=1
                )

fig.add_trace(go.Scatter(
                x=df.t,
                y=df['D'],
                name="4",
                line_color='red',
                opacity=0.8,
                legendgroup='group4'),
                row=1, col=1
                )

fig.add_trace(go.Scatter(
                x=df2.t,
                y=df2['A'],
                name="1",
                line_color='deepskyblue',
                opacity=0.8,
                legendgroup='group1',
                showlegend=False),
                row=1, col=2
                )

fig.add_trace(go.Scatter(
                x=df2.t,
                y=df2['B'],
                name="2",
                line_color='dimgray',
                opacity=0.8,
                legendgroup='group2',
                showlegend=False),
                row=1, col=2
                )

fig.add_trace(go.Scatter(
                x=df2.t,
                y=df2['C'],
                name="3",
                line_color='blue',
                opacity=0.8,
                legendgroup='group3',
                showlegend=False),
                row=1, col=2
                )

fig.add_trace(go.Scatter(
                x=df2.t,
                y=df2['D'],
                name="4",
                line_color='red',
                opacity=0.8,
                legendgroup='group4',
                showlegend=False),
                row=1, col=2
                )

fig.write_html('ts.html', auto_open=True)

enter image description here

Я хотел бы знать, как обновить представленное ниже решение для добавления подзаголовков

1 Ответ

1 голос
/ 18 марта 2020

Запись post_script, который является Javascript кодом, который будет добавлен в результирующий div после его создания.

В post_script,

  • добавить прослушиватель событий для plotly_click событие
  • проверка, является ли точка нажатия маркером
  • свойство visible переключения соответствующего графика рассеяния от true до 'legendonly'
import numpy as np
import pandas as pd
import networkx as nx
import plotly.graph_objects as go
from plotly.subplots import make_subplots

from pprint import pprint
from collections import OrderedDict


def get_edge_trace(G):
    edge_x = []
    edge_y = []
    for edge in G.edges():
        x0, y0 = G.nodes[edge[0]]["pos"]
        x1, y1 = G.nodes[edge[1]]["pos"]
        edge_x.append(x0)
        edge_x.append(x1)
        edge_x.append(None)
        edge_y.append(y0)
        edge_y.append(y1)
        edge_y.append(None)

    edge_trace = go.Scatter(
        x=edge_x,
        y=edge_y,
        line=dict(width=0.5, color="#888"),
        hoverinfo="none",
        showlegend=False,
        xaxis="x2",
        yaxis="y2",
        mode="lines",
    )
    return edge_trace


def get_node_trace(G):
    node_x = []
    node_y = []
    for node in G.nodes():
        x, y = G.nodes[node]["pos"]
        node_x.append(x)
        node_y.append(y)

    node_trace = go.Scatter(
        x=node_x,
        y=node_y,
        mode="markers",
        hoverinfo="text",
        xaxis="x2",
        yaxis="y2",
        showlegend=False,
        marker=dict(
            showscale=True,
            # colorscale options
            # 'Greys' | 'YlGnBu' | 'Greens' | 'YlOrRd' | 'Bluered' | 'RdBu' |
            # 'Reds' | 'Blues' | 'Picnic' | 'Rainbow' | 'Portland' | 'Jet' |
            # 'Hot' | 'Blackbody' | 'Earth' | 'Electric' | 'Viridis' |
            colorscale="YlGnBu",
            reversescale=True,
            color=[],
            size=10,
            colorbar=dict(
                thickness=15,
                title="Node Connections",
                titleside="right",
                x=0.95,
            ),
            line_width=2,
        ),
    )

    return node_trace


if __name__ == "__main__":

    tail = [1, 2, 3]
    head = [2, 3, 4]

    xpos = [0, 1, 2, 3]
    ypos = [0, 0, 0, 0]
    xpos_ypos = [(x, y) for x, y in zip(xpos, ypos)]

    ed_ls = [(x, y) for x, y in zip(tail, head)]
    G = nx.OrderedDiGraph()
    G.add_edges_from(ed_ls)

    pos = OrderedDict(zip(G.nodes, xpos_ypos))
    nx.draw(G, pos=pos, with_labels=True)
    nx.set_node_attributes(G, pos, "pos")

    fig = make_subplots(rows=1, cols=2)
    fig.layout.update(
        dict(
            title="<br>Network graph made with Python",
            titlefont_size=16,
            hovermode="closest",
            # margin=dict(b=20, l=5, r=5, t=40),
            annotations=[
                dict(
                    text="Python code: <a href='https://plot.ly/ipython-notebooks/network-graphs/'> https://plot.ly/ipython-notebooks/network-graphs/</a>",
                    showarrow=False,
                    xref="paper",
                    yref="paper",
                    x=0,
                    y=0,
                    yshift=-0.1,
                )
            ],
            yaxis=dict(domain=[0.1, 1]),
            xaxis=dict(domain=[0, 0.6]),
            xaxis2=dict(
                domain=[0.7, 0.94],
                showgrid=False,
                zeroline=False,
                showticklabels=False,
            ),
            yaxis2=dict(showgrid=False, zeroline=False, showticklabels=False),
        )
    )

    df = pd.DataFrame(
        np.random.randint(0, 100, size=(20, 5)), columns=list("tABCD")
    )

    data = [
        go.Scatter(
            x=df.t, y=df["A"], name="1", line_color="deepskyblue", opacity=0.8
        ),
        go.Scatter(
            x=df.t, y=df["B"], name="2", line_color="dimgray", opacity=0.8
        ),
        go.Scatter(
            x=df.t, y=df["C"], name="3", line_color="blue", opacity=0.8
        ),
        go.Scatter(x=df.t, y=df["D"], name="4", line_color="red", opacity=0.8),
    ]

    fig.add_traces(data=data, rows=[1, 1, 1, 1], cols=[1, 1, 1, 1])

    fig.add_traces(
        data=[get_edge_trace(G), get_node_trace(G),], rows=[1, 1], cols=[2, 2]
    )

    post_script = """
    gd = document.getElementById('{plot_id}');
    gd.on('plotly_click', function(data) {
        var pn='',
        tn='',
        isNodeClick=false;
        for (var i=0; i < data.points.length; i++){
            pn = data.points[i].pointNumber;
            tn = data.points[i].curveNumber;
            if(data.points[i].fullData.mode === 'markers') {
                isNodeClick = true;
            }
        };
        if (!isNodeClick) return;
        var visible = gd.calcdata[pn][0].trace.visible;
        const update = {'visible': visible === true ? 'legendonly': true}
        Plotly.restyle(gd, update, [pn]);
        return false;
    });
    """
    fig.write_html("plot.html", post_script=post_script, auto_open=True)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...