Создать интерактивную иерархическую диаграмму из панд / словаря - PullRequest
7 голосов
/ 10 марта 2020

У меня есть данные, которые показывают отношения для каждого сотрудника с их менеджерами (Person: Manager) -

data = {'PersonX':'Person1', 'PersonY':'Person1', 'PersonZ':'Person 2', 'Person1':'Person100','Person2':'Person100' }

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

Данные, которые я получаю, могут содержать иногда 5 человек, а иногда количество записей превышает 5000.

Я пытался эти подходы, но они не близки к созданию любых интерактивных графиков.

Код -

Попробуйте 1 -

import pandas as pd
import networkx as nx

d = {'PersonX': 'Person1', 'PersonY': 'Person1', 'PersonZ': 'Person2', 'Person1': 'Person100', 'Person2': 'Person100'}
df = pd.DataFrame(d.items(), columns=['Person', 'Manager'])
G = nx.from_pandas_edgelist(df,  source='Person', target='Manager')
nx.draw(G, with_labels=True)
plt.show()

Network X graph

Попробуйте 2 -

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
from scipy.cluster import hierarchy
df2 = df.apply(LabelEncoder().fit_transform)
df2.set_index('Manager', inplace=True)
Z = hierarchy.linkage(df2, 'ward')
hierarchy.dendrogram(hierarchy.linkage(df2, method='ward'))
plt.show()

Attempt 2nd

Попробуйте 3 -

print('strict digraph tree {')
for row in d.items():
    print('    {0} -> {1};'.format(*row))
print('}')

И запустил

test.py | dot -Tpng -otree.png

GraphViz

Ответы [ 2 ]

4 голосов
/ 20 марта 2020

Я использовал следующий код для создания интерактивного графика, эта работа еще не завершена, но я хотел опубликовать ее, чтобы люди могли использовать ее в случае необходимости.

import pandas as pd
import dash
import dash_html_components as html
import dash_cytoscape as cyto
from matplotlib import colors as mcolors
from itertools import zip_longest
from ast import literal_eval

colors = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS)
# Sort colors by hue, saturation, value and name.
by_hsv = sorted((tuple(mcolors.rgb_to_hsv(mcolors.to_rgba(color)[:3])), name)
                for name, color in colors.items())
sorted_names = [name for hsv, name in by_hsv]

app = dash.Dash(__name__)
# colors = ['red', 'blue', 'green', 'yellow', 'pink']

# stylesheet for the web page generated

default_stylesheet = [
    {
        "selector": 'node',
        'style': {
            "opacity": 0.9,
            'height': 15,
            'width': 15,
            'background-color': '#222222',
            'label': 'data(label)'
        }
    },
    {
        "selector": 'edge',
        'style': {
            "curve-style": "bezier",
            "opacity": 0.3,
            'width': 2
        }
    },
    *[{
        "selector": '.' + color,
        'style': {'line-color': color}
    } for color in sorted_names]
]

# Example data for illustration
# My actual data was in the excel file with two columns Managers and Person

managers = ['Person A',
            'Person A',
            'Person A',
            'Person A',
            'Person A',
            'Person A',
            'Person B',
            'Person B',
            'Person B',
            'Person B',
            'Person B',
            'Person B',
            'Person C',
            'Person C',
            'Person C',
            'Person C',
            'Person C',
            'Person C',
            'Person V',
            'Person V',
            'Person V',
            'Person V',
            'Person V']

person = ['Person D',
          'Person E',
          'Person F',
          'Person G',
          'Person H',
          'Person I',
          'Person J',
          'Person K',
          'Person L',
          'Person M',
          'Person N',
          'Person O',
          'Person P',
          'Person Q',
          'Person R',
          'Person S',
          'Person T',
          'Person U',
          'Person A',
          'Person W',
          'Person X',
          'Person B',
          'Person C']

# Creating a dataframe with the illustration data
df = pd.DataFrame(list(zip(person, managers)), columns=['Person', 'Manager'])
# Giving colors to each managers in the dataframe
df['colors'] = df['Manager'].map(dict(zip_longest(list(set(managers)), sorted_names)))
# Creating the nodes within the dataframe
df['y_node_target'] = "{\"data\": {\"id\": \"" + df['Person'] + "\", \"label\":\""+df['Person']+"\"}, \"classes\": \"" + df['colors'] + "\"}"
df['y_node'] = "{\"data\": {\"id\": \"" + df['Manager'] + "\", \"label\":\""+df['Manager']+"\"}, \"classes\": \"" + df['colors'] + "\"}"
nodes = list(set(pd.concat([df['y_node'], df['y_node_target']]).to_list()))
df['Edges'] = "{\'data\': {\'source\':\"" + df['Manager'] + "\", \'target\': \"" + df[
    'Person'] + "\"},\'classes\': \"" + df['colors'] + "\"}"


# Converting the strings to dictionaries and assigning them to variables
edges = list(set(df['Edges'].astype(str).to_list()))
edges = list(map(literal_eval, edges))
nodes = list(map(literal_eval, nodes))

app.layout = html.Div([
    cyto.Cytoscape(
        id='cytoscape',
        elements=edges + nodes,
        stylesheet=default_stylesheet,
        layout={
            'name': 'breadthfirst'
        },
        style={'height': '95vh', 'width': '100%'}
    )
])

if __name__ == '__main__':
    app.run_server(debug=True)

Вывод был веб-страница -

enter image description here

3 голосов
/ 13 марта 2020

Вы можете попробовать использовать Plotly для создания интерактивной диаграммы для вашего графика. Вот пример из их документации:

Создать случайный график

import plotly.graph_objects as go

import networkx as nx

G = nx.random_geometric_graph(200, 0.125)

Создать ребра

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

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

Цветовые узлы

node_adjacencies = []
node_text = []
for node, adjacencies in enumerate(G.adjacency()):
    node_adjacencies.append(len(adjacencies[1]))
    node_text.append('# of connections: '+str(len(adjacencies[1])))

node_trace.marker.color = node_adjacencies
node_trace.text = node_text

Сетевой график

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.show()

Создает интерактивную диаграмму, например:

enter image description here

Источник: Сетевые графики

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