Example #1
0
    {"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})
#app.css.append_css({'external_url': 'https://cdn.rawgit.com/plotly/dash-app-stylesheets/2d266c578d2a6e8850ebce48fdb52759b2aef506/stylesheet-oil-and-gas.css'})  # noqa: E501

app.layout = html.Div(children=[
    html.Div([html.Button(id='button', n_clicks=0, children='STARTING...')],
             style={'color': 'white'}),
    html.Div([dcc.Graph(id='graph_one', figure={})],
             style={'display': 'inline-block'}),
    dcc.Interval(id='live-update', interval=1000),
],
                      style={'background-color': "#F0F0F0"})


@app.callback(dep.Output('graph_one',
                         'figure'), [], [dep.State('graph_one', 'figure')],
              [dep.Event('live-update', 'interval')])
def do_plot(figure):
    df = pd.read_csv('/tmp/mon.csv')

    plt_w = uj2w(df.time, df.cpu_uj)
    sys_w = uj2w(df.time, df.sys_uj) * 2

    t = df.time - df.time[0]

    y_data = (
        df.v0 / 1e6,
        df.v1 / 1e6,
        df.i0 / 1e6,
        df.i1 / 1e6,
        df.i0 * df.v0 / 1e12,
        df.i1 * df.v1 / 1e12,
Example #2
0
    def init_dash(self):
        """Load the inital Dataset and show it in initial layout."""
        app = dash.Dash()

        # The following config were neccessary, as the CDN serving the files
        # seems to be unstable.
        app.css.config.serve_locally = True
        app.scripts.config.serve_locally = True

        # Values for Checkboxes
        topics_options = [{'label': i, 'value': i} for i in self.topics]

        # Layout of Dashboard
        app.layout = html.Div([
            html.Link(
                rel='stylesheet',
                href='/static/style.css'
            ),
            html.Link(
                rel='stylesheet',
                href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'
            ),

            # Header
            html.Div([
                html.H1('Crypto Crawler\'s Dashboard'),
                html.Img(
                    src='/static/logo.png'),
            ], className='banner'),

            # Live Tweets
            html.Div([
                html.Div([
                    html.H3(
                        'Tweets per {} sec.' \
                        .format(self.update_interval))
                ], className='title'),
                html.Div([
                    # Dropdown to select time range for Live Tweet Chart
                    dcc.Dropdown(
                        id='tweets-live-dropdown',
                        options=[
                            {'label': 'Stop', 'value': 0},
                            {'label': 'Last minute', 'value': 1},
                            {'label': 'Last 5 min', 'value': 5},
                            {'label': 'Last 15 min', 'value': 15},
                            {'label': 'Last 30 min', 'value': 30}
                        ],
                        value=5
                    ),
                    # Chart for Live Tweets
                    dcc.Graph(
                        id='tweets-live-plot',
                        style={'width': '878px', 'height': '200px'},
                        figure=self.plot_live_tweets(
                            self.topics_default, 5),
                        config={
                            'displayModeBar': False
                        })
                ], className='content')
            ], className='live-box'),

            # Hidden element to store data
            # See: https://plot.ly/dash/sharing-data-between-callbacks
            html.Div(id='hidden-tweet-data', style={'display': 'none'}),
            html.Div(id='hidden-stock-data', style={'display': 'none'}),
            html.Div(id='hidden-layout-data', style={'display': 'none'}),

            # Topic Selection
            html.Div([
                html.Div([
                    html.H3("Topic Selection")
                ], className='title'),
                html.Div([
                    dcc.Checklist(
                        id='global-topic-checklist',
                        options=topics_options,
                        values=self.topics_default
                    ),
                ], className='content')
            ], className='box'),

            # Overall Tweets per Hour
            html.Div([
                html.Div([
                    html.H3([
                        html.Span('∑', className='icon'),
                         'Tweets per Hour'])
                ], className='title'),
                html.Div([
                    dcc.Checklist(
                        id='tweet-anoms-toggle',
                        options=[
                            {'label': 'Show Anomalies',
                             'value': 'anoms'}
                        ],
                        className='anoms-toggle',
                        values=[]
                    ),
                ], className='content'),
                html.Div([
                    # Chart for All Tweets
                    dcc.Graph(
                        style={'width': '878px', 'height': '250px'},
                        id='tweets-plot')
                ], className='content')
            ], className='box'),

            # Sentiment per Hour
            html.Div([
                html.Div([
                    html.H3([
                        html.Span('☺', className='icon'),
                         'Avg. Sentiment per Hour'])
                ], className='title'),
                html.Div([
                    dcc.Checklist(
                        id='senti-anoms-toggle',
                        options=[
                            {'label': 'Show Anomalies',
                             'value': 'anoms'}
                        ],
                        className='anoms-toggle',
                        values=[]
                    ),
                ], className='content'),
                html.Div([
                    dcc.Graph(
                        style={'width': '878px', 'height': '250px'},
                        id='senti-plot')
                ], className='content')
            ], className='box'),

            # Prices per Hour
            html.Div([
                html.Div([
                    html.H3([
                        html.Span('€', className='icon'),
                         'Avg. Stock Prices per Hour'])
                ], className='title'),
                html.Div([
                    dcc.Checklist(
                        id='stock-anoms-toggle',
                        options=[
                            {'label': 'Show Anomalies',
                             'value': 'anoms'}
                        ],
                        values=[],
                        className='anoms-toggle'
                    ),
                ], className='content'),
                html.Div([
                    dcc.Graph(
                        style={'width': '878px', 'height': '250px'},
                        id='stock-plot')
                ], className='content')
            ], className='box'),

            # Random Tweets
            html.Div([
                html.Div([
                    html.H3([
                        html.Span(className='fa fa-twitter icon'),
                         'Random tweets for the selected topic']),
                    html.Button(className='fa fa-refresh refresh',
                                id='refresh-tweets-button')
                ], className='title'),
                html.Div([
                ], id='tweetbox', className='content')
            ], className='box'),

            # Topic Models
            html.Div([
                html.Div([
                    html.H3([
                        html.Span(className='fa fa-newspaper-o icon'),
                         'Identify Topics'])
                ], className='title'),
                html.Div([
                    html.Div([
                        dcc.Dropdown(
                            options=[{'label': i, 'value': i}
                                     for i in self.topics],
                            value='bitcoin',
                            id='topic-collection-dropdown'
                        ),
                        dcc.DatePickerRange(
                            id='topic-date-picker',
                            start_date=datetime.datetime(2018, 1, 1, 0, 0, 0),
                            end_date=datetime.datetime(2018, 2, 1, 0, 0, 0),
                            end_date_placeholder_text='Select a date!'
                        ),
                        dcc.Input(
                            placeholder='No. of Topics...',
                            type='number',
                            value=5,
                            min=2,
                            max=10,
                            inputmode='numeric',
                            id='topic-number-input'
                        ),
                        html.Button(className='fa fa-search',
                                    id='topic-button')
                    ], className='settings-bar'),
                    html.Div([
                        html.Div([html.Span(className='fa fa-arrow-circle-o-up'),
                                  'Make your selection and wait some Minutes!'],
                                 className='topic-placeholder')
                    ], id='topic-results')
                ], id='topicbox', className='content')
            ], className='box'),

            # Footer
            html.Div(
                'Build in 01/2018 by kevhen & dynobo with ❤ and Plotly Dash',
                id='bottom-line'),
            dcc.Interval(id='live-update',
                         interval=1000 * self.update_interval),
        ],  className='container')

        @app.server.route('/static/<path:path>')
        def static_file(path):
            static_folder = os.path.join(os.getcwd(), 'static')
            return send_from_directory(static_folder, path)

        @app.callback(dash.dependencies.Output('tweetbox', 'children'), [
            ddp.Input(component_id='global-topic-checklist',
                      component_property='values'),
            ddp.Input(component_id='refresh-tweets-button',
                      component_property='n_clicks'),
            ddp.Input('tweets-plot', 'relayoutData'),
            ddp.Input('senti-plot', 'relayoutData'),
            ddp.Input('stock-plot', 'relayoutData')
        ], [], [])
        def returnUpdatedTweetbox(topic_values, n_clicks, rd_tweets, rd_senti,
                                  rd_stock):
            timeframe = {}
            if rd_tweets is not None:
                timeframe = rd_tweets
            if rd_senti is not None:
                timeframe = rd_senti
            if rd_stock is not None:
                timeframe = rd_stock
            if 'xaxis.range[0]' in timeframe:
                fromTs = convertDate(timeframe['xaxis.range[0]'])
            else:
                fromTs = 0
            if 'xaxis.range[1]' in timeframe:
                toTs = convertDate(timeframe['xaxis.range[1]'])
            else:
                toTs = 999999999999
            payload = {
                "topics": ','.join(topic_values),
                "amount": 5,
                "from": fromTs,
                "to": toTs
            }
            tweets = []

            response = requests.get('http://*****:*****@app.callback(ddp.Output('tweets-live-plot', 'figure'), [
            ddp.Input(component_id='global-topic-checklist',
                      component_property='values'),
            ddp.Input(component_id='tweets-live-dropdown',
                      component_property='value')
        ], [], [ddp.Event('live-update', 'interval')])
        def update_live_timeseries(topic_values, live_range):
            # Do nothing, if Live Chart is set to "off" (value = 0)
            if (live_range == 0) or (live_range is None):
                return
            return self.plot_live_tweets(topic_values, live_range)

        @app.callback(ddp.Output('hidden-tweet-data', 'children'), [
            ddp.Input(component_id='global-topic-checklist',
                      component_property='values')
        ])
        def clean_tweet_data(topic_values):
            # Query for Data
            df = self.get_agg_data(topic_values, 'score')

            if (df is None) or (len(df) < 1 or
                                ('timestamp_ms' not in df.columns.values)):
                df_empty = pd.DataFrame()
                data = (df_empty.to_json(date_format='iso', orient='split') +
                        "\n") * 3
                return data

            # Group and aggregate
            df = df.groupby(['timestamp_ms', 'collection'])
            df_score = df['score'].mean().unstack('collection').fillna(0)
            df_count = df['count'].sum().unstack('collection').fillna(0)

            # Get Anomalies for count
            df_anoms_count = pd.DataFrame()
            for col in df_count.columns.values:
                df_temp = self.get_anomalies(df_count[col])
                df_anoms_count = pd.concat([df_anoms_count, df_temp], axis=1)

            # Get Anomalies for score
            df_anoms_score = pd.DataFrame()
            for col in df_score.columns.values:
                df_temp = self.get_anomalies(df_score[col])
                df_anoms_score = pd.concat([df_anoms_score, df_temp], axis=1)

            # Jsonfy & concat DFs, then store string in hidden element
            data = df_count.to_json(date_format='iso', orient='split') \
                + "\n" + \
                df_score.to_json(date_format='iso', orient='split') \
                + "\n" + \
                df_anoms_count.to_json(date_format='iso', orient='split') \
                + "\n" + \
                df_anoms_score.to_json(date_format='iso', orient='split') \

            return data

        @app.callback(ddp.Output('hidden-stock-data', 'children'), [
            ddp.Input(component_id='global-topic-checklist',
                      component_property='values')
        ])
        def clean_stock_data(topic_values):
            # Get Data
            currencies = {
                'BTC': 'bitcoin',
                'IOT': 'iota',
                'ETH': 'ethereum',
            }
            currency_codes = []
            for key, val in currencies.items():
                if val in topic_values:
                    currency_codes.append(key)

            if len(currency_codes) > 0:
                df = self.get_agg_data(currency_codes, 'EUR')

                # Replace codes with names
                df['collection'] = df['collection'].replace(currencies)

                # Group and aggregate
                df = df.groupby(['timestamp_ms', 'collection'])
                df = df['EUR'].mean().unstack('collection').fillna(0)
            else:
                df = pd.DataFrame()

            # Get Anomalies for score
            df_anoms = pd.DataFrame()
            for col in df.columns.values:
                df_anoms[col] = self.get_anomalies(df[col])

            # Jsonfy & concat DFs, then store string in hidden element
            data = df.to_json(date_format='iso', orient='split') \
                + "\n" + \
                df_anoms.to_json(date_format='iso', orient='split')

            return data

        axises = ['', '', '']  # Used to store axis scales of the three charts

        @app.callback(ddp.Output('hidden-layout-data', 'children'), [
            ddp.Input('tweets-plot', 'relayoutData'),
            ddp.Input('senti-plot', 'relayoutData'),
            ddp.Input('stock-plot', 'relayoutData')
        ])
        def set_layout_data(rd_tweet, rd_senti, rd_stock):
            new_axises = [rd_tweet, rd_senti, rd_stock]
            for idx, val in enumerate(new_axises):
                if val != axises[idx]:
                    axises[idx] = val
                    return json.dumps(val)
            return json.dumps({})

        @app.callback(ddp.Output('tweets-plot', 'figure'), [
            ddp.Input('hidden-tweet-data', 'children'),
            ddp.Input('hidden-layout-data', 'children'),
            ddp.Input('tweet-anoms-toggle', 'values')
        ])
        def update_timeseries(jsonified_data, rd_data, toggle):
            data = jsonified_data.split('\n')[0]
            df = pd.read_json(data, orient='split')
            if 'anoms' in toggle:
                anoms = jsonified_data.split('\n')[2]
                df_anoms = pd.read_json(anoms, orient='split')
            else:
                df_anoms = None
            x_axis = self.get_x(json.loads(rd_data))
            return self.plot_timeseries('Tweets', df, df_anoms, x_axis)

        @app.callback(ddp.Output('senti-plot', 'figure'), [
            ddp.Input('hidden-tweet-data', 'children'),
            ddp.Input('hidden-layout-data', 'children'),
            ddp.Input('senti-anoms-toggle', 'values')
        ])
        def update_senti(jsonified_data, rd_data, toggle):
            data = jsonified_data.split('\n')[1]
            df = pd.read_json(data, orient='split')
            if 'anoms' in toggle:
                anoms = jsonified_data.split('\n')[3]
                df_anoms = pd.read_json(anoms, orient='split')
            else:
                df_anoms = None
            x_axis = self.get_x(json.loads(rd_data))
            return self.plot_timeseries('Sentiment Score', df, df_anoms,
                                        x_axis)

        @app.callback(ddp.Output('stock-plot', 'figure'), [
            ddp.Input('hidden-stock-data', 'children'),
            ddp.Input('hidden-layout-data', 'children'),
            ddp.Input('stock-anoms-toggle', 'values')
        ])
        def update_plot(jsonified_data, rd_data, toggle):
            data = jsonified_data.split('\n')[0]
            df = pd.read_json(data, orient='split')
            if 'anoms' in toggle:
                anoms = jsonified_data.split('\n')[1]
                df_anoms = pd.read_json(anoms, orient='split')
            else:
                df_anoms = None
            x_axis = self.get_x(json.loads(rd_data))
            return self.plot_timeseries('€ Stock Price', df, df_anoms, x_axis)

        self.app = app

        @app.callback(ddp.Output('topic-results', 'children'),
                      [ddp.Input('topic-button', 'n_clicks')], [
                          ddp.State('topic-collection-dropdown', 'value'),
                          ddp.State('topic-date-picker', 'start_date'),
                          ddp.State('topic-date-picker', 'end_date'),
                          ddp.State('topic-number-input', 'value'),
                      ])
        def update_topics(btn, coll, start_date, end_date, number):
            print(btn)
            placeholder = html.Div([
                html.Span(className='fa fa-arrow-circle-o-up'),
                'Make your selection and wait some Minutes!'
            ],
                                   className='topic-placeholder')

            if not start_date or not end_date \
                    or not number or not coll or not btn:
                logger.warn('Parameter is missing.')
                return placeholder

            if self.topic_btn_clicks == btn:
                return placeholder
            else:
                self.topic_btn_clicks = btn

            start_ms = int(
                time.mktime(time.strptime(start_date[:10], '%Y-%m-%d'))) * 1000
            end_ms = int(time.mktime(time.strptime(end_date[:10],
                                                   '%Y-%m-%d'))) * 1000

            data = self.get_topics(coll, start_ms, end_ms, number)

            if (not data) or ('topics' not in data):
                logger.warn('No data received.')
                return placeholder

            all_topics = [
                html.Div('Topics from {} Tweets'.format(data['tweet_count']),
                         className='topic-header')
            ]
            for topic in data['topics']:
                topic_html = html.Div([
                    html.Div([
                        t,
                        html.Span('{:.3f}'.format(c)[1:],
                                  className='topic-value')
                    ],
                             className='topic-token') for t, c in topic[:15]
                ],
                                      className='topic-row')
                all_topics.append(topic_html)

            return html.Div(all_topics)

        self.app = app
Example #3
0
    df=df.astype('str')
    row = df.iloc[[0]]
    fromcity, tocity, fromtuple, totuple = geoloc.updateLatLong(row, master, geolocator)
    fig = geoloc.plotGeoPlot(m, fromcity, tocity, fromtuple, totuple)
    
    return fig

def serve_layout():
    return html.Div(children=[
        html.Div([
            html.H1("Plotly test with Live update",
                    style={"font-family": "Helvetica", 
                           "border-bottom": "1px #000000 solid"}),
            ], className='banner'),
        html.Div([dcc.Graph(id='plot', figure=gen_plot())],),
        dcc.Interval(id='live-update', interval=interval),
],)

app = dash.Dash()

app.layout = serve_layout

app.callback(
    ddp.Output('plot', 'figure'),
    [],
    [],
    [ddp.Event('live-update', 'interval')])(gen_plot)

if __name__ == '__main__':
    app.run_server(debug=True)
Example #4
0
class VisualizationView:
    _model = None    # type: VisualizationModel

    # https://github.com/plotly/dash/issues/214
    _flask = Flask(__name__)
    _dash = Dash(__name__, server=_flask)

    _axis_styles = dict()
    _plot_styles = dict()
    _dist_axes = None

    length = 0

    _dash.layout = get_layout()

    _iterations = 0

    @staticmethod
    @_flask.route("/init_model", methods=["POST"])
    def init_model():
        data = request.data
        Logger.log(f"initializing {str(data):s}")

        d = json.loads(data)
        axes = d["axes"]

        VisualizationView._dist_axes = {_axis_name for _axis_name, _, _is_dist in axes if _is_dist}
        VisualizationView._axis_styles.clear()
        VisualizationView._plot_styles.clear()
        VisualizationView.length = d.get("length", 0)

        axes_model = tuple((_axis_name, _width) for _axis_name, _width, _ in axes)
        VisualizationView._model = VisualizationModel(axes_model, length=VisualizationView.length)

        VisualizationView._dash.layout = get_layout()
        _iterations = 0

        return jsonify(f"initialized {str(axes):s}, length {VisualizationView.length:d}")

    @staticmethod
    @_flask.route("/style", methods=["POST"])
    def style():
        data = request.data
        Logger.log(f"styling {str(data):s}")

        d = json.loads(data)

        VisualizationView._axis_styles.clear()
        VisualizationView._axis_styles.update(d["axes"])

        VisualizationView._plot_styles.clear()
        VisualizationView._plot_styles.update(d["plots"])

        return jsonify("styling done")

    @staticmethod
    @_flask.route("/data", methods=["POST"])
    def add_data():
        if VisualizationView._model is None:
            raise ValueError("visualization model not initialized")

        data = request.data
        Logger.log(f"adding batch")

        d = json.loads(data)
        batch = d["batch"]
        iteration = d["iteration"]

        VisualizationView._model.add_batch(iteration, batch)

        return jsonify(f"added batch of size {len(batch):d}")

    @staticmethod
    def _get_concentration(_axis_name: str, this_plot_style: Dict[str, Any]) -> Sequence[BasePlotlyType]:
        axis_data = []

        for _j, _plot_name in enumerate(VisualizationView._model.get_plot_names(_axis_name)):
            series = VisualizationView._model.get_plot(_axis_name, _plot_name)
            no_series = len(series)
            half_plus_one = no_series // 2 + 1
            no_bands = no_series - half_plus_one + 1
            alpha = 1. / no_bands

            color = hsv_to_rgb((distribute_circular(_j), .7, .7))
            color_str = ", ".join([f"{int(_x * 255.):d}" for _x in color])
            fillcolor = f"rgba({color_str:s}, {alpha:.2f})"
            plot_properties = this_plot_style.get(_plot_name, {"fillcolor": fillcolor})

            for _i in range(no_bands):
                series_a = series[_i]
                series_b = series[_i + half_plus_one - 1]
                outline = series_a + series_b[::-1]
                range_a = VisualizationView._model.x_range
                each_range = range_a + range_a[::-1]

                data = graph_objs.Scatter(
                    **plot_properties,
                    showlegend=_i == 0,
                    x=each_range,
                    y=outline,
                    name=_plot_name,
                    fill="tozerox",
                    mode="lines",
                    line={
                        "color": f"rgba({color_str:s}, 1)",
                        "width": 0,
                        "shape": "hv",
                        #"shape": "spline",
                    },
                    # line={"color": "rgba(255, 255, 255, 0)"},
                )
                axis_data.append(data)

        return axis_data

    @staticmethod
    def _get_lines(_axis_name: str, this_plot_style: Dict[str, Any]) -> Sequence[BasePlotlyType]:
        axis_data = []

        for _j, _plot_name in enumerate(VisualizationView._model.get_plot_names(_axis_name)):
            color = hsv_to_rgb((distribute_circular(_j), .7, .7))
            color_str = ", ".join([f"{int(_x * 255.):d}" for _x in color])

            plot_properties = this_plot_style.get(_plot_name, dict())

            series = VisualizationView._model.get_plot(_axis_name, _plot_name)

            for each_series in series:
                data = graph_objs.Scatter(
                    **plot_properties,
                    showlegend=True,
                    x=VisualizationView._model.x_range,
                    y=each_series,
                    name=_plot_name,
                    mode="lines",
                    line={
                        "color": f"rgba({color_str:s}, 1)",
                        "width": 1,
                        "shape": "hv",
                        #"shape": "spline",
                    },
                )
                axis_data.append(data)

        return axis_data

    @staticmethod
    @_dash.callback(dependencies.Output("graphs", "children"), events=[dependencies.Event("graph-update", "interval")])
    def __update_graph():
        graphs = []
        if VisualizationView._model is None or len(VisualizationView._model.x_range) < 1:
            return graphs

        if VisualizationView.length < 0:
            x_min = max(0, VisualizationView._model.x_range[-1] + VisualizationView.length)
            x_max = x_min - VisualizationView.length

        elif 0 < VisualizationView.length:
            x_min = 0
            x_max = VisualizationView.length

        else:
            x_min = 0
            x_max = VisualizationView._model.x_range[-1]

        for _axis_name in VisualizationView._model.axes:
            this_plot_style = VisualizationView._plot_styles.get(_axis_name, dict())

            if _axis_name not in VisualizationView._dist_axes:
                axis_data = VisualizationView._get_lines(_axis_name, this_plot_style)

            else:
                axis_data = VisualizationView._get_concentration(_axis_name, this_plot_style)

            axis_properties = VisualizationView._axis_styles.get(_axis_name, dict())

            # todo: get axis, update with default values
            # todo: also set y axis in constructor
            # todo: try axis property "autorange=True"

            layout = graph_objs.Layout(
                **axis_properties,
                xaxis={
                    "range": [x_min, x_max],
                    "title": "iterations",
                },
                yaxis={
                    "title": _axis_name,
                    #"type": "log",
                    "autorange": True   # only works if Graph animate=False, see https://community.plot.ly/t/how-to-enable-automatic-autoscale/5276/9
                },
                legend={
                    "x": 1,
                    "y": 1
                }
            )

            graphs.append(dash_html_components.Div(children=[
                dash_core_components.Graph(
                    id=_axis_name,
                    animate=False,
                    animation_options={
                        "mode": "immediate",
                        #"frame": {
                        #    "duration": 200,
                        #    "redraw": False,
                        #},
                        #"transition": {
                        #    "duration": 0,
                        #}
                    },
                    figure={
                        "data": axis_data,
                        "layout": layout}
                )
            ]))

        return graphs