I would like to display multi bullet charts and icons using dash and plotly in separate rows. I would like them to display something like the image below. I've already implemented the multi bullet chart on one row. I'm having trouble placing another multi bullet chart beside this one with icons because of the domain x and y positioning. Here's the code that I have so far. Once I get this I would be adding a drop down to display this information.
app = dash.Dash(__name__)
fig = go.Figure()
fig.add_trace(go.Indicator(
mode = "number+gauge+delta", value = 180,
delta = {'reference': 200},
domain = {'x': [0.25, 1], 'y': [0.08, 0.25]},
title = {'text': "SV 3"},
gauge = {'shape': "bullet"}))
fig.add_trace(go.Indicator(
mode = "number+gauge+delta", value = 35,
delta = {'reference': 200},
domain = {'x': [0.25, 1], 'y': [0.4, 0.6]},
title = {'text': "SV 2"},
gauge = {'shape': "bullet"}))
fig.add_trace(go.Indicator(
mode = "number+gauge+delta", value = 220,
delta = {'reference': 200},
domain = {'x': [0.25, 1], 'y': [0.7, 0.9]},
title = {'text' :"SV 1"},
gauge= {'shape': "bullet"}))
fig.update_layout(height = 400 , margin = {'t':0, 'b':0, 'l':0})
fig.show()
app.run_server(debug=True, use_reloader=True)
I would recommend you to work with dash-bootstrap-components!
layout = html.Div(
[
dbc.Row(
dbc.Col
(html.Div("A single, half-width column"), width=6)),
dbc.Row(
[
dbc.Col(fig, width=3),
dbc.Col(html.Div("Some space in the middle")),
dbc.Col(html.Div("One of your other elements"), width=3),
]
),
]
)
Related
I have a dashboard built on plotly dash. It is very similar to this dashboard--
import datetime
import dash
from dash import dcc, html
import plotly
from dash.dependencies import Input, Output
# pip install pyorbital
from pyorbital.orbital import Orbital
satellite = Orbital('TERRA')
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
html.Div([
html.H4('TERRA Satellite Live Feed'),
html.Div(id='live-update-text'),
dcc.Graph(id='live-update-graph'),
dcc.Interval(
id='interval-component',
interval=1*1000, # in milliseconds
n_intervals=0
)
])
)
#app.callback(Output('live-update-text', 'children'),
Input('interval-component', 'n_intervals'))
def update_metrics(n):
lon, lat, alt = satellite.get_lonlatalt(datetime.datetime.now())
style = {'padding': '5px', 'fontSize': '16px'}
return [
html.Span('Longitude: {0:.2f}'.format(lon), style=style),
html.Span('Latitude: {0:.2f}'.format(lat), style=style),
html.Span('Altitude: {0:0.2f}'.format(alt), style=style)
]
# Multiple components can update everytime interval gets fired.
#app.callback(Output('live-update-graph', 'figure'),
Input('interval-component', 'n_intervals'))
def update_graph_live(n):
satellite = Orbital('TERRA')
data = {
'time': [],
'Latitude': [],
'Longitude': [],
'Altitude': []
}
# Collect some data
for i in range(180):
time = datetime.datetime.now() - datetime.timedelta(seconds=i*20)
lon, lat, alt = satellite.get_lonlatalt(
time
)
data['Longitude'].append(lon)
data['Latitude'].append(lat)
data['Altitude'].append(alt)
data['time'].append(time)
# 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']['legend'] = {'x': 0, 'y': 1, 'xanchor': 'left'}
fig.append_trace({
'x': data['time'],
'y': data['Altitude'],
'name': 'Altitude',
'mode': 'lines+markers',
'type': 'scatter'
}, 1, 1)
fig.append_trace({
'x': data['Longitude'],
'y': data['Latitude'],
'text': data['time'],
'name': 'Longitude vs Latitude',
'mode': 'lines+markers',
'type': 'scatter'
}, 2, 1)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
The difference is that, in my dashboard, there are about twenty different time series and every one of those time series gets updated every two seconds. Right now, my dashboard runs sequentially and without any parallelization, but it ends up being pretty slow both because there are a lot of time series to update and there is a lot of data.
I am on a windows machine and I set up waitress using this command: waitress.serve(app.server, threads = 16)
What do I need to change about my script to take advantage of parallelization? I was thinking about making a different callback for every time series and having them all update the figure independently of one another.
I have a plotly dashboard built with dash. Some of the chart elements are set to refresh every couple of seconds. Instead of just refreshing that individual dashboard, the entire webpage refreshes and it rebuilds every element.
This is an example of how the code is written that updates the charts-
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
html.Div([
dcc.Graph(id='live-update-graph'),
dcc.Interval(
id='interval-component',
interval=1*1000, # in milliseconds
n_intervals=0
)
])
)
#app.callback(Output('live-update-graph', 'figure'),
Input('interval-component', 'n_intervals'))
def update_graph_live(n):
satellite = Orbital('TERRA')
data = {
'time': [],
'Latitude': [],
'Longitude': [],
'Altitude': []
}
# Collect some data
for i in range(180):
time = datetime.datetime.now() - datetime.timedelta(seconds=i*20)
lon, lat, alt = satellite.get_lonlatalt(
time
)
data['Longitude'].append(lon)
data['Latitude'].append(lat)
data['Altitude'].append(alt)
data['time'].append(time)
# 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']['legend'] = {'x': 0, 'y': 1, 'xanchor': 'left'}
fig.append_trace({
'x': data['time'],
'y': data['Altitude'],
'name': 'Altitude',
'mode': 'lines+markers',
'type': 'scatter'
}, 1, 1)
return fig
My desired outcome is that just the plot element refreshes but not the entire webpage.
Following code creates two subplots and updating it each second in browser window.
I can zoom it and hide some lines in plot, but each second all data updates and set zoom and all lines visibility to default
How I can keep settings for zoom and selected lines while updating?
import datetime
import random
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from plotly.subplots import make_subplots
# https://dash.plotly.com/live-updates
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
html.Div([
html.H4('Two random plots'),
dcc.Graph(id='live-update-graph'),
dcc.Interval(
id='interval-component',
interval=1 * 1000, # in milliseconds
n_intervals=0
)
])
)
DATA = {
'time': [],
'val0': [],
'val1_1': [],
'val1_2': []
}
def update_data():
DATA['val0'].append(random.randint(0, 50))
DATA['val1_1'].append(random.randint(0, 50))
DATA['val1_2'].append(random.randint(0, 50))
DATA['time'].append(datetime.datetime.now())
#app.callback(Output('live-update-graph', 'figure'),
Input('interval-component', 'n_intervals'))
def update_graph_live(n):
update_data()
# Create the graph with subplots
fig = make_subplots(rows=2, cols=1, vertical_spacing=0.2)
fig['layout']['margin'] = {'l': 30, 'r': 10, 'b': 30, 't': 10}
fig['layout']['legend'] = {'x': 0, 'y': 1, 'xanchor': 'left'}
fig.append_trace({
'x': DATA['time'],
'y': DATA['val0'],
'name': 'val 0',
'mode': 'lines+markers',
'type': 'scatter'
}, 1, 1)
fig.append_trace({
'x': DATA['time'],
'y': DATA['val1_1'],
'text': DATA['time'],
'name': 'val 1.1',
'mode': 'lines+markers',
'type': 'scatter'
}, 2, 1)
fig.append_trace({
'x': DATA['time'],
'y': DATA['val1_2'],
'text': DATA['time'],
'name': 'val 1.2',
'mode': 'lines+markers',
'type': 'scatter'
}, 2, 1)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
Since November 2018, there is a solution as posted on the Plotly Community Forum. The layout property of the figure property of dcc.Graph has a property uirevision, for which the post says:
uirevision is where the magic happens. This key is tracked internally by dcc.Graph, when it changes from one update to the next, it resets all of the user-driven interactions (like zooming, panning, clicking on legend items). If it remains the same, then that user-driven UI state doesn’t change.
So if you never want to reset the zoom settings, no matter how much the underlying data changes, just set uirevision to a constant, like so:
fig['layout']['uirevision'] = 'some-constant'
before returning the figure in your update function.
And there is more:
There are also cases where you want more control. Say the x and y data for a plot can be changed separately. Perhaps x is always time, but y can change between price and volume. You might want to preserve x zoom while resetting y zoom. There are lots of uirevision attributes, that normally all inherit from layout.uirevision but you can set them separately if you want. In this case set a constant xaxis.uirevision = 'time' but let yaxis.revision change between 'price' and 'volume'. Be sure to still set layout.uirevision to preserve other items like trace visibility and modebar buttons!
I'm using Plotly gauge charts in my Django project. I need to show two thresholds for the upper and lower boundary of some parameter which is being projected in the chart.
here is my chart in views.py:
gauge_do = go.Figure(go.Indicator(
mode = "gauge+number",
value = 1.7,
domain = {'x': [0, 1], 'y': [0, 1]},
title = {'text': "Oxygen [mg/L]"},
gauge = {'axis': {'range': [0, 10]},
'bar': {'color': "salmon"},
'threshold' : {'line': {'color': "red", 'width': 4}, 'thickness': 0.75, 'value': 2}
}
)
)
gauge_do.update_layout(font = {'color': "black", 'family': "Arial"}, margin = dict(t=0, b=0, l=5, r=5,), height=230)
div_do = opy.plot(gauge_do, auto_open=False, config=config, output_type='div')
Here, there is one threshold with value of 'value': 2.
In my case, I want to show the minimum acceptable value and maximum acceptable value by two indicators ( exactly as threshold ), say min=2 and max=8.
the plotly doesnt accept using two 'threshold's.
any ideas?
From the documentation, it seems like they intend steps to do this. Something like:
gauge_do = go.Figure(
go.Indicator(
mode = "gauge+number",
value = 1.7,
domain = {'x': [0, 1], 'y': [0, 1]},
title = {'text': "Oxygen [mg/L]"},
gauge = {'axis': {'range': [0, 10]},
'bar': {'color': "salmon"},
'steps' : [{
'color': 'white',
'line': {'color': "red", 'width': 4},
'thickness': 0.75,
'range': [2,8]}]
}
)
)
My function to create figures looks as follows:
def bar_plot_plotly(self, frame=None):
md = self.get_book()
plotly.offline.init_notebook_mode(connected=True)
fig = go.Figure()
if md:
for step in range(2):
fig.add_trace(go.Indicator(
mode = "number+gauge+delta", value = md.qasks[step],
delta = {'reference': md.qasks[step]},
domain = {'x': [0, 0.4], 'y': [0.2*step, 0.2*step+0.1]},
title = {'text': str(md.asks[step])},
gauge = {
'shape': "bullet",
'axis': {'range': [min(md.qasks), max(md.qasks)]},
'threshold': {
'line': {'color': "red", 'width': 2},
'thickness': 0.75,
'value': md.qasks[step]},
'bar': {'color': "red"}}))
fig.add_trace(go.Indicator(
mode = "number+gauge+delta", value = md.qbids[step],
delta = {'reference': md.qbids[step]},
domain = {'x': [0.6, 1], 'y': [0.2*step, 0.2*step+0.1]},
title = {'text': str(md.bids[step])},
gauge = {
'shape': "bullet",
'axis': {'range': [min(md.qbids), max(md.qbids)]},
'threshold': {
'line': {'color': "green", 'width': 2},
'thickness': 0.75,
'value': md.qbids[step]},
'bar': {'color': "green"}}))
So at each iteration, it creates a figure, my goal would be to iterate on each of those figures in order to create an animation. The idea would be to do the same as in the documentation https://plot.ly/python/animations/#animated-bar-charts-with-plotly-express, but in there they use a pandas DataFrame, I would like to do it per figure basically.
I used to use Funcanimation on matplotlib, I was thus wondering if it was possible to use the above code to do the same? Any advice is more than welcome!
Thanks