1
+ import dash
2
+ import dash_core_components as dcc
3
+ import dash_html_components as html
4
+ import pandas as pd
5
+ import plotly .graph_objs as go
6
+
7
+ external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css' ]
8
+
9
+ app = dash .Dash (__name__ , external_stylesheets = external_stylesheets )
10
+
11
+ df = pd .read_csv ('indicators.csv' )
12
+
13
+ available_indicators = df ['Indicator Name' ].unique ()
14
+
15
+ app .layout = html .Div ([
16
+ html .Div ([
17
+
18
+ html .Div ([
19
+ dcc .Dropdown (
20
+ id = 'crossfilter-xaxis-column' ,
21
+ options = [{'label' : i , 'value' : i } for i in available_indicators ],
22
+ value = 'Fertility rate, total (births per woman)'
23
+ ),
24
+ dcc .RadioItems (
25
+ id = 'crossfilter-xaxis-type' ,
26
+ options = [{'label' : i , 'value' : i } for i in ['Linear' , 'Log' ]],
27
+ value = 'Linear' ,
28
+ labelStyle = {'display' : 'inline-block' }
29
+ )
30
+ ],
31
+ style = {'width' : '49%' , 'display' : 'inline-block' }),
32
+
33
+ html .Div ([
34
+ dcc .Dropdown (
35
+ id = 'crossfilter-yaxis-column' ,
36
+ options = [{'label' : i , 'value' : i } for i in available_indicators ],
37
+ value = 'Life expectancy at birth, total (years)'
38
+ ),
39
+ dcc .RadioItems (
40
+ id = 'crossfilter-yaxis-type' ,
41
+ options = [{'label' : i , 'value' : i } for i in ['Linear' , 'Log' ]],
42
+ value = 'Linear' ,
43
+ labelStyle = {'display' : 'inline-block' }
44
+ )
45
+ ], style = {'width' : '49%' , 'float' : 'right' , 'display' : 'inline-block' })
46
+ ], style = {
47
+ 'borderBottom' : 'thin lightgrey solid' ,
48
+ 'backgroundColor' : 'rgb(250, 250, 250)' ,
49
+ 'padding' : '10px 5px'
50
+ }),
51
+
52
+ html .Div ([
53
+ dcc .Graph (
54
+ id = 'crossfilter-indicator-scatter' ,
55
+ hoverData = {'points' : [{'customdata' : 'Japan' }]}
56
+ )
57
+ ], style = {'width' : '49%' , 'display' : 'inline-block' , 'padding' : '0 20' }),
58
+ html .Div ([
59
+ dcc .Graph (id = 'x-time-series' ),
60
+ dcc .Graph (id = 'y-time-series' ),
61
+ ], style = {'display' : 'inline-block' , 'width' : '49%' }),
62
+
63
+ html .Div (dcc .Slider (
64
+ id = 'crossfilter-year--slider' ,
65
+ min = df ['Year' ].min (),
66
+ max = df ['Year' ].max (),
67
+ value = df ['Year' ].max (),
68
+ marks = {str (year ): str (year ) for year in df ['Year' ].unique ()}
69
+ ), style = {'width' : '49%' , 'padding' : '0px 20px 20px 20px' })
70
+ ])
71
+
72
+
73
+ @app .callback (
74
+ dash .dependencies .Output ('crossfilter-indicator-scatter' , 'figure' ),
75
+ [dash .dependencies .Input ('crossfilter-xaxis-column' , 'value' ),
76
+ dash .dependencies .Input ('crossfilter-yaxis-column' , 'value' ),
77
+ dash .dependencies .Input ('crossfilter-xaxis-type' , 'value' ),
78
+ dash .dependencies .Input ('crossfilter-yaxis-type' , 'value' ),
79
+ dash .dependencies .Input ('crossfilter-year--slider' , 'value' )])
80
+ def update_graph (xaxis_column_name , yaxis_column_name ,
81
+ xaxis_type , yaxis_type ,
82
+ year_value ):
83
+ dff = df [df ['Year' ] == year_value ]
84
+
85
+ return {
86
+ 'data' : [go .Scatter (
87
+ x = dff [dff ['Indicator Name' ] == xaxis_column_name ]['Value' ],
88
+ y = dff [dff ['Indicator Name' ] == yaxis_column_name ]['Value' ],
89
+ text = dff [dff ['Indicator Name' ] == yaxis_column_name ]['Country Name' ],
90
+ customdata = dff [dff ['Indicator Name' ] == yaxis_column_name ]['Country Name' ],
91
+ mode = 'markers' ,
92
+ marker = {
93
+ 'size' : 15 ,
94
+ 'opacity' : 0.5 ,
95
+ 'line' : {'width' : 0.5 , 'color' : 'white' }
96
+ }
97
+ )],
98
+ 'layout' : go .Layout (
99
+ xaxis = {
100
+ 'title' : xaxis_column_name ,
101
+ 'type' : 'linear' if xaxis_type == 'Linear' else 'log'
102
+ },
103
+ yaxis = {
104
+ 'title' : yaxis_column_name ,
105
+ 'type' : 'linear' if yaxis_type == 'Linear' else 'log'
106
+ },
107
+ margin = {'l' : 40 , 'b' : 30 , 't' : 10 , 'r' : 0 },
108
+ height = 450 ,
109
+ hovermode = 'closest'
110
+ )
111
+ }
112
+
113
+
114
+ def create_time_series (dff , axis_type , title ):
115
+ return {
116
+ 'data' : [go .Scatter (
117
+ x = dff ['Year' ],
118
+ y = dff ['Value' ],
119
+ mode = 'lines+markers'
120
+ )],
121
+ 'layout' : {
122
+ 'height' : 225 ,
123
+ 'margin' : {'l' : 20 , 'b' : 30 , 'r' : 10 , 't' : 10 },
124
+ 'annotations' : [{
125
+ 'x' : 0 , 'y' : 0.85 , 'xanchor' : 'left' , 'yanchor' : 'bottom' ,
126
+ 'xref' : 'paper' , 'yref' : 'paper' , 'showarrow' : False ,
127
+ 'align' : 'left' , 'bgcolor' : 'rgba(255, 255, 255, 0.5)' ,
128
+ 'text' : title
129
+ }],
130
+ 'yaxis' : {'type' : 'linear' if axis_type == 'Linear' else 'log' },
131
+ 'xaxis' : {'showgrid' : False }
132
+ }
133
+ }
134
+
135
+
136
+ @app .callback (
137
+ dash .dependencies .Output ('x-time-series' , 'figure' ),
138
+ [dash .dependencies .Input ('crossfilter-indicator-scatter' , 'hoverData' ),
139
+ dash .dependencies .Input ('crossfilter-xaxis-column' , 'value' ),
140
+ dash .dependencies .Input ('crossfilter-xaxis-type' , 'value' )])
141
+ def update_y_timeseries (hoverData , xaxis_column_name , axis_type ):
142
+ country_name = hoverData ['points' ][0 ]['customdata' ]
143
+ dff = df [df ['Country Name' ] == country_name ]
144
+ dff = dff [dff ['Indicator Name' ] == xaxis_column_name ]
145
+ title = '<b>{}</b><br>{}' .format (country_name , xaxis_column_name )
146
+ return create_time_series (dff , axis_type , title )
147
+
148
+
149
+ @app .callback (
150
+ dash .dependencies .Output ('y-time-series' , 'figure' ),
151
+ [dash .dependencies .Input ('crossfilter-indicator-scatter' , 'hoverData' ),
152
+ dash .dependencies .Input ('crossfilter-yaxis-column' , 'value' ),
153
+ dash .dependencies .Input ('crossfilter-yaxis-type' , 'value' )])
154
+ def update_x_timeseries (hoverData , yaxis_column_name , axis_type ):
155
+ dff = df [df ['Country Name' ] == hoverData ['points' ][0 ]['customdata' ]]
156
+ dff = dff [dff ['Indicator Name' ] == yaxis_column_name ]
157
+ return create_time_series (dff , axis_type , yaxis_column_name )
158
+
159
+
160
+ if __name__ == '__main__' :
161
+ app .run_server ()
0 commit comments