创建一个可以使用Plotly Dash轻松可视化的Web应用程序


什么是Plotly Dash?

Plotly Dash(正式名称似乎是Dash,但是由于还有其他许多名为Dash的应用程序,我将使用此表示法)是Python制作的Web应用程序的框架。
有许多Python Web框架,例如Flask和Bottle,但是Plotly Dash可以使用Plotly合并可视化数据。

安装

pip安装。我尚未确认它是否可以与conda一起安装。

1
2
3
4
5
pip install dash==0.17.7  # The core dash backend
pip install dash-renderer==0.7.4  # The dash front-end
pip install dash-html-components==0.7.0  # HTML components
pip install dash-core-components==0.11.0  # Supercharged components
pip install plotly==2.0.12  # Plotly graphing library used in examples

我会暂时写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np

x = np.linspace(-np.pi, np.pi, 10)
y = np.sin(x)
app = dash.Dash()

app.layout = html.Div(children=[
    html.H1(children='H1の文章'),

    html.Div(children='''
        divの文章
    '''),

    dcc.Graph(
        id='example-graph',
        figure={
            'data': [
                {'x': x, 'y': np.sin(x), 'type': 'line', 'name': 'line'},
                {'x': x, 'y': np.cos(x), 'type': 'bar', 'name': 'bar'},
            ],
            'layout': {
                'title': 'グラフのタイトル'
            }
        }
    )
])

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

Screenshot at 2017-08-05 13-45-20.png

您不必如上所述编写HTML,只需编写Python代码即可。
Plotly负责绘制图形。

降价促销

支持Markdown表示法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import dash
import dash_html_components as html
import dash_core_components as dcc

markdown_doc = dcc.Markdown('''
# 見出し1
## 見出し2
### 見出し3
---
* 箇条書き
* 箇条書き
---

[りんく](http://commonmark.org/help)
![いめーじ](https://images.plot.ly/static/marketing/dash/dash-logo.png)

> 引用
''')

app = dash.Dash()
app.layout = html.Div(markdown_doc)

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

image.png

我无法在我的环境中表示表格。如果有人成功,请告诉我。

实时更新

它还支持动态图。

以下示例使用psutil实时监视计算机的资源状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import dash
from dash.dependencies import Input, Output, Event
import dash_core_components as dcc
import dash_html_components as html
import datetime
import plotly
import numpy as np
import pandas as pd
import psutil

colors = {
    'background': '#111111',
    'text': '#7FDBFF'
}

app = dash.Dash(__name__)
app.layout = html.Div(children=[
    html.Div([
        html.H4('オレオレシステムモニタ'),
        html.Div(id='live-update-text'),
        dcc.Graph(id='live-update-graph'),
        html.H4('プロセスリスト'),
        html.Div(id='live-update-proc'),
        dcc.Interval(
            id='interval-component',
            interval=1 * 1000  # in milliseconds
        )
    ])
],
    style={'backgroundColor': colors['background'], 'color': colors['text']}
)


class Context:
    def __init__(self):
        self.t = []
        self.cpu = []
        self.per_cpu = [[] for x in range(psutil.cpu_count())]
        self.mem = []

    @classmethod
    def append_data(cls, d1, d2):
        n = len(d1)
        if n > 100:
            del d1[0:n - 99]
        d1.append(d2)


context = Context()

# The `dcc.Interval` component emits an event called "interval"
# every `interval` number of milliseconds.
# Subscribe to this event with the `events` argument of `app.callback`


@app.callback(Output('live-update-text', 'children'),
              events=[Event('interval-component', 'interval')])
def update_metrics():
    now = datetime.datetime.now()
    hour, minute, second = now.hour, now.minute, now.second
    style = {'padding': '5px', 'fontSize': '16px'}
    return [
        html.Span('CPU: {}%'.format(context.cpu[-1]), style=style),
        html.Span('Memory: {}%'.format(context.mem[-1]), style=style)
    ]


# Multiple components can update everytime interval gets fired.
@app.callback(Output('live-update-graph', 'figure'),
              events=[Event('interval-component', 'interval')])
def update_graph_live():
    # global context
    context.append_data(context.t, datetime.datetime.now())
    context.append_data(context.cpu, psutil.cpu_percent())
    for data, pct in zip(context.per_cpu, psutil.cpu_percent(percpu=True)):
        context.append_data(data, pct)
    context.append_data(context.mem, psutil.virtual_memory().percent)

    # Create the graph with subplots
    fig = plotly.tools.make_subplots(rows=2, cols=1, vertical_spacing=0.2)
    fig['layout']['margin'] = {
        'l': 30, 'r': 10, 'b': 30, 't': 10
    }
    fig['layout']['plot_bgcolor'] = colors['background']
    fig['layout']['paper_bgcolor'] = colors['background']
    fig['layout']['font'] = {'color': colors['text']}
    fig['layout']['legend'] = {'x': 0, 'y': 1, 'xanchor': 'left'}
    fig['layout']['yaxis1'].update(range=[0, 100])
    fig['layout']['yaxis2'].update(range=[0, 100])

    fig.append_trace({
        'x': context.t,
        'y': context.cpu,
        'name': 'cpu',
        'mode': 'lines',
        'type': 'scatter',
    }, 1, 1)
    for i, y in enumerate(context.per_cpu):
        fig.append_trace({
            'x': context.t,
            'y': y,
            'name': 'cpu {}'.format(i),
            'mode': 'lines',
            'type': 'scatter',
        }, 1, 1)
    fig.append_trace({
        'x': context.t,
        'y': context.mem,
        'name': 'memory',
        'mode': 'lines',
        'type': 'scatter',
        'fill': 'tonexty',
    }, 2, 1)

    return fig


def get_proc_df():
    def get_proc(proc):
        try:
            pinfo = proc
        except psutil.NoSuchProcess:
            pass
        return (pinfo.pid, pinfo.name(), pinfo.memory_percent(), pinfo.cpu_percent())

    data = [get_proc(proc) for proc in psutil.process_iter()]
    df = pd.DataFrame(data, columns=['pid', 'name', 'memory', 'cpu'])
    df['memory'] = df['memory'].map(lambda x: '{:.2f}%'.format(x))
    df['cpu'] = df['cpu'] / psutil.cpu_count()
    df['cpu'] = df['cpu'].map(lambda x: '{:.2f}%'.format(x))
    return df.sort_values('cpu', ascending=False)


@app.callback(Output('live-update-proc', 'children'),
              events=[Event('interval-component', 'interval')])
def generate_table():
    df = get_proc_df()
    max_rows = 10
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in df.columns])] +

        # Body
        [html.Tr([
            html.Td(df.iloc[i][col], style={'width': '8em'}) for col in df.columns
        ]) for i in range(min(len(df), max_rows))]
    )


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

Peek 2017-08-05 16-52.gif

互动操作

您可以在操作UI时交互地控制输出内容。
我将尽快写出如何做。