Converting Gapminder Plot.ly example to Dash App

Should I even try to do that?

There are dependencies on plot.ly/cloud accounts (paid) which may not be able to be run without it.
Has anyone tried to do this? (grid ie.)

If the Gapminder example can be run as a Dash app, this opens up myriad possibilities for using Dash to show evolving time-series data elegantly as Hans Rosling has. I have run a full implementation using Bokeh but have a deep effort in the Dash framework as of now.

Chris?

Hello @thoughtsociety,

Thank for bringing this up. I will upload an dash animation app for the Gapminder example soon. Meanwhile, I created a sample 3d animation app, which you can probably base off from.

import dash
from dash.dependencies import Input, Output, Event, State
import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objs as go
import pandas as pd
import numpy as np
import datetime
from scipy import integrate
from itertools import cycle


app = dash.Dash()
interval_state = 1000
app.layout = html.Div([
    dcc.Markdown('''

Enter Number of trajectories (e.g. 1 or 2 or 3 or etc...):
'''),
    dcc.Input(
        id='n_traject_input',
        placeholder='Enter a value',
        type='text',
        value= '5'
    ),
    dcc.Interval(
        id='interval-element',
        interval=interval_state,
        n_intervals=0,
        max_intervals=10
    ),
    dcc.Markdown('''

Select frame speed:
'''),
    dcc.RadioItems(id='set-time',
        value=1000,
        options=[
            {'label': '1x', 'value': 1000},
            {'label': '2x', 'value': 500},
            {'label': '4x', 'value': 250},
            {'label': '10x', 'value': 50},
            {'label': 'Off', 'value': 60*60*1000} # or just every hour
        ]),
    dcc.Markdown('''

Epoch state:
'''),
    html.Div(id='display-time'),
    html.Button('Reset animation!', id='button'),

    html.Div([
    dcc.Graph(id='graph-with-slider', animate=True, animation_options = {'frame':{'duration': 0,'redraw': False},
                                                'layout': {'scene': {'xaxis': {'range': [-35, 35], 'autorange': False},
                                                                    'yaxis': {'range': [-40, 40], 'autorange': False},
                                                                    'zaxis': {'range': [-35, 75], 'autorange': False}}},
                                                'transition': {'duration': 0,'ease': 'cubic-in-out'}})
        ], style={'width': 800}),
    html.Div([
        dcc.Slider(
            id='time-slider',
            min=0,
            max=1000
            )
        ], style={'width': 700}),
])

@app.callback(Output('graph-with-slider', 'figure'), [Input('n_traject_input', 'value'),
                                                        Input('time-slider', 'value')],
                                                    [State('graph-with-slider', 'relayoutData')])
def display_data(n_trajectories, n_intervals, relayoutData):
    print(n_intervals)
    x_t, _ = calc_trajectories(int(n_trajectories))
    traces = {'data': [], 'name': str(n_intervals)}
    colors = ['#7FDBFF', '#39CCCC', '#3D9970', '#85144b', '#F012BE', '#B10DC9', 
    '#001f3f', '#0074D9', '#2ECC40', '#01FF70', '#FF4136', '#FFDC00 ','#FF851B', '#AAAAAA']
    for i in range(x_t.shape[0]):
        c = colors[(i + 1) % len(colors)]
        data_dict = {
            'x': x_t[i,:n_intervals+1,0],
            'y': x_t[i,:n_intervals+1,1],
            'z': x_t[i,:n_intervals+1,2],
            'mode': 'lines',
            'line': {'width': 3, 'color': c},
            'name': 'object-'+str(i),
            'type': 'scatter3d',
        }
        traces['data'].append(data_dict)
        data_dict = {
            'x': [x_t[i,n_intervals,0]],
            'y': [x_t[i,n_intervals,1]],
            'z': [x_t[i,n_intervals,2]],
            'mode': 'markers',
            'marker': {'size': 4, 'color': c, 'maxdisplayed': 1},
            'name': 'object-'+str(i),
            'type': 'scatter3d',
            'showlegend': False
        }
        traces['data'].append(data_dict)
    figure = {
        'data': traces,
        'layout': {'scene': {'xaxis': {'range': [-35, 35], 'autorange': False},
                        'yaxis': {'range': [-40, 40], 'autorange': False},
                        'zaxis': {'range': [-35, 75], 'autorange': False},
                        'aspectmode': "cube"
                        },
                'hovermode': 'closest',     
                    }
            }
    return figure

@app.callback(Output('display-time', 'children'), events=[Event('interval-element', 'interval')])
def display_time():
    return str(datetime.datetime.now())

@app.callback(Output('interval-element', 'interval'), [Input('set-time', 'value')])
def update_interval(value):
    return value
    
@app.callback(Output('time-slider', 'value'), [Input('interval-element', 'n_intervals')])
def update_slider_value(n_intervals):
    return n_intervals

@app.callback(Output('interval-element', 'n_intervals'), [Input('button', 'n_clicks')],
                                                events=[Event('n_traject_input', 'change')])
def reset_interval(n_clicks):
    return 0

def lorentz_deriv(data, t0, sigma=10., beta=8./3, rho=28.0):
    """Compute the time-derivative of a Lorentz system."""
    (x,y,z) = data
    return [sigma * (y - x), x * (rho - z) - y, x * y - beta * z]

def calc_trajectories(n_trajectories):
    """
    Choose random starting points, uniformly distributed from -15 to 15
    """
    np.random.seed(1)
    x0 = -15 + 30 * np.random.random((n_trajectories, 3))

    # Solve for the trajectories
    t = np.linspace(0, 4, 1000)
    x_t = np.asarray([integrate.odeint(lorentz_deriv, x0i, t)
                    for x0i in x0])

    return (x_t, t)

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

The above example was inspired from: https://jakevdp.github.io/blog/2013/02/16/animating-the-lorentz-system-in-3d/

Hi Priyatharsan,

Thanks for responding.
I see some errors when running this.

Traceback (most recent call last):
File “dash-animation.py”, line 29, in
max_intervals=10
File “”, line 29, in init
File “/Users/salvideoguy/anaconda3/envs/mydashenv/lib/python3.6/site-packages/dash/development/base_component.py”, line 31, in init
', '.join(sorted(self._prop_names))
TypeError: Unexpected keyword argument max_intervals
Allowed arguments: disabled, id, interval, n_intervals

any ideas?

Interesting! It’s working on my side. Are you running the latest version of dash? https://dash.plot.ly/installation

Hi,

I am running dash v 0.21.0

Steve

Are you getting the same error, after updating dash?
(after running):

# The core dash backend
pip install dash==0.27.0  

# HTML components
pip install dash-html-components==0.13.2  

# Supercharged components
pip install dash-core-components==0.30.2

I just checked and dcc, html are both out of date from those you cited.
I will update and try and reply afterwards.

thanks!