Can not put gantt plot to dash - python

I did gantt plot on plotly. But now I would like to put it on dash with dropdown menu. As I'm new in dash,I did generate the dropdown menu, but I'm struggling to put my gannt plot on dash where my input should be value from dropdown menu, and output should be the line (graph) of selected value from dropdown menu.
I would really appreciate your helps. Thanks.

I think you are not being careful enough with several things as imports, variable names and formatting.
First start with the plotly version:
import plotly.offline as py
import plotly.figure_factory as ff
import pandas as pd
df = pd.DataFrame({'ObjectID': ['ITDM-1', 'ITDM-1', 'ITDM-1', 'ITDM-1',
'ITDM-10', 'ITDM-10', 'ITDM-10',
'ITDM-101', 'ITDM-101', 'ITDM-101'],
'Phase': ['phasezero', 'phaseone', 'phasetwo',
'phasethree', 'phasezero', 'phaseone',
'phasetwo', 'phasezero', 'phaseone', 'phasetwo'],
'StartDate': ['2016-12-1', '2017-3-22', '2017-8-21', '2017-9-21',
'2016-12-1', '2016-12-5','2016-12-9', '2017-5-11',
'2017-5-12', '2017-8-17'],
'EndDate': ['2017-5-22', '2017-8-21', '2017-9-21', '2017-12-22',
'2017-2-5', '2017-4-9', '2016-12-13', '2017-5-12',
'2017-8-17', '2017-10-5']})
def gantt_fig(df):
data = []
for row in df.itertuples():
data.append(dict(Task=str(row.Phase), Start=str(row.StartDate), Finish=str(row.EndDate), Resource=str(row.ObjectID)))
colors = ['rgb(0, 102, 204)', 'rgb(204, 0, 0)', 'rgb(0, 153, 0)']
fig = ff.create_gantt(data, index_col='Resource', reverse_colors=True, show_colorbar=True, showgrid_x=True, title='Gantt Chart')
fig['layout'].update( margin=dict(l=310))
return fig
fig = gantt_fig(df)
py.iplot(fig)
From here you should try to translate it to dash (again) being careful about how you name things (compare to your code)
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.figure_factory as ff
import pandas as pd
def gantt_fig(df):
data = []
for row in df.itertuples():
data.append(dict(Task=str(row.Phase), Start=str(row.StartDate),
Finish=str(row.EndDate), Resource=str(row.ObjectID)))
colors = ['rgb(0, 102, 204)', 'rgb(204, 0, 0)', 'rgb(0, 153, 0)']
fig = ff.create_gantt(data, index_col='Resource',
reverse_colors=True, show_colorbar=True,
showgrid_x=True, title='Gantt Chart')
fig['layout'].update( margin=dict(l=310))
return fig
df = pd.DataFrame({'ObjectID': ['ITDM-1', 'ITDM-1', 'ITDM-1', 'ITDM-1',
'ITDM-10', 'ITDM-10', 'ITDM-10',
'ITDM-101', 'ITDM-101', 'ITDM-101'],
'Phase': ['phasezero', 'phaseone', 'phasetwo', 'phasethree',
'phasezero', 'phaseone', 'phasetwo', 'phasezero',
'phaseone', 'phasetwo'],
'StartDate': ['2016-12-1', '2017-3-22', '2017-8-21', '2017-9-21',
'2016-12-1', '2016-12-5', '2016-12-9', '2017-5-11',
'2017-5-12', '2017-8-17'],
'EndDate': ['2017-5-22', '2017-8-21', '2017-9-21', '2017-12-22',
'2017-2-5', '2017-4-9', '2016-12-13', '2017-5-12',
'2017-8-17', '2017-10-5']})
options = df['ObjectID'].unique()
app = dash.Dash()
app.layout = html.Div([html.H1('Gantt table'),
dcc.Dropdown(id='my-dropdown',
options=[{'label': n, 'value': n}
for n in options],
value=options[0]),
dcc.Graph(id='display-selected-value')
]
)
#app.callback(
dash.dependencies.Output('display-selected-value', 'figure'),
[dash.dependencies.Input('my-dropdown', 'value')])
def update_gantt(value):
df2plot = df[df['ObjectID']==value].reset_index(drop=True)
fig = gantt_fig(df2plot)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
As a general suggestion I will first write a function that return the fig you want to plot with plotly. Then moving to dash you can check that your dropdown menu works properly following this and then add the callback for fig.

Related

simple dash app with table with histogram that updates with selected cell

I'm trying to create a dash app that updates a histogram depending on what cell is selected in the 'group' column.
I can get the table to display but having trouble with the histogram.
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
import pandas as pd
import plotly.express as px
import numpy as np
from dash import Dash, dash_table
import json
app = dash.Dash(__name__)
## create data
df_rand = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('ABCD'))
df_rand = pd.melt(df_rand, value_vars=list('ABCD'))
df_rand_summary = df_rand.groupby('variable').describe()
df_rand_summary = df_rand_summary.droplevel(level=0, axis=1)
df_rand_summary.insert(0, 'group', df_rand_summary.index)
app.layout = html.Div(children=[
## add table
dash_table.DataTable(
data=df_rand_summary.to_dict('records'),
columns=[{'id': c, 'name': c, } for c in df_rand_summary]
),
# include histogram
html.Div([
dcc.Graph(
id='hist'
)
])
])
#app.callback(
Output('hist', 'figure'),
Input('table', 'active_cell'),
State('table', 'data'))
def update_hist(active_cell, df_rand):
# subset histogram with selected cell
# from 'group' column
cell = json.dumps(active_cell, indent=2)
row = active_cell['row']
col = active_cell['column_id']
value = df_rand[row][col]
fig = px.histogram(df_rand[df_rand['variable'] == value], x='value')
return fig
if __name__ == '__main__':
app.run_server(debug=True)
When you use df_rand as a parameter to update_hist, you overwrite the df_rand defined outside the update_hist. To solve this problem, define new parameter, instead as follows:
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
import pandas as pd
import plotly.express as px
import numpy as np
from dash import Dash, dash_table
import json
app = dash.Dash(__name__)
## create data
df_rand = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('ABCD'))
df_rand = pd.melt(df_rand, value_vars=list('ABCD'))
df_rand_summary = df_rand.groupby('variable').describe()
df_rand_summary = df_rand_summary.droplevel(level=0, axis=1)
df_rand_summary.insert(0, 'group', df_rand_summary.index)
app.layout = html.Div(children=[
## add table
dash_table.DataTable(id="table",
data=df_rand_summary.to_dict('records'),
columns=[{'id': c, 'name': c, } for c in df_rand_summary]
),
# include histogram
html.Div([
dcc.Graph(
id='hist'
)
])
])
#app.callback(
Output('hist', 'figure'),
Input('table', 'active_cell'),
State('table', 'data'),
prevent_initial_call=True)
def update_hist(active_cell, data_dict): #<------ here we define data_dict instead of df_rand
row = active_cell['row']
col = active_cell['column_id']
value = data_dict[row][col]
fig = px.histogram(df_rand.query("variable == #value"), x='value')
return fig
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=False)
Output:

Plotly Dash - Parallel Selection/Crossfiltering across a Scatterplot and a Timeseries + dropdown/button to switch between datasets shown on plots

I'm trying to create a Dash App that has a scatterplot and timeseries, where the user can select data points on either graph and they highlight on both. This is similar to the "Crossfiltering" example in the Dash documentation (https://dash.plotly.com/interactive-graphing) but one key difference is that I'm looking for the union of each graph's selection rather than the intersection.
To further complicate - I have a second callback linked to a dropdown and "next" button with the intent that both can be used to change the underlying dataset used in the graphs by filtering on the "ID" column in the original dataset. I've set it up to store the filtered dataframe as a JSON object in a DCC.Store called "asset_df" that can then be pulled as an input for the callback that updates the graphs.
In its current state:
App loads and plots the dataset for the first ID in the list - this works as intended
Clicking the "Next" button or selecting a difference ID from the dropdown updates both graphs with the new dataset - this works as intended
Selecting data on either graph highlights those points on both graphs - this is where it breaks
It doesn't return a callback error or any error messages, but the graphs don't get updated with the selected points highlighted. I believe part of the issue is that the callback for updating the graphs seems to be firing twice, with the second firing returning a blank dataset for "selectedData" for both graphs.
Questions I'm hoping the community can help me with:
- Am I collecting/storing/recalling the asset_df correctly using the DCC.Store and my callback inputs/outputs?
- Why is the callback linked to the display_selected_data function getting called twice when a selection is made on either plot?
If you see any other issues with the code (I'm a beginner so no doubt there are many) please let me know, especially if they may be contributing to the issue described above.
Thank you!
dataset available here: SampleData
from jupyter_dash import JupyterDash
from dash import Dash, dcc, html, dash_table, ctx
import numpy as np
import pandas as pd
import json
from dash.dependencies import Input, Output
import plotly.express as px
from base64 import b64encode
import io
import collections
df_raw = pd.read_csv(PATH_TO_DATA)
df_raw.set_index('PCTimeStamp', inplace=True, drop=False)
asset_col = "Asset"
asset_list = df_raw[asset_col].unique().tolist()
X2_col = "X2_Variable"
timestamp_col = "PCTimeStamp"
Y1_col = "Y1_Variable"
app = JupyterDash(__name__)
app.layout = html.Div([
html.Button('Next',
id='next_button',
n_clicks=0),
dcc.Dropdown(asset_list,
value=asset_list[0],
id='dropdown'),
dcc.Graph(id='scatter',
config={'displayModeBar': True}),
dcc.Graph(id='timeseries',
config={'displayModeBar': True}),
dcc.Store(id='asset_df')
])
def get_figure(df, x_col, y_col, asset_col, selectedpoints):
if x_col == 'PCTimeStamp':
fig = px.scatter(df, x=df[x_col], y=df[y_col], text=df.index, color=df[asset_col])
fig.update_traces(selectedpoints=selectedpoints,
customdata=df.index, mode='markers+lines',
line_color='grey',
marker={'color': 'grey', 'size': 5},
unselected={'marker': {'opacity': 0.3, 'color': 'grey'}, 'textfont': {'color': 'grey'}},
selected={'marker': {'opacity': 1.0, 'color': 'yellow'}, 'textfont': {'color': 'yellow'}})
elif x_col == X2_col:
fig = px.scatter(df, x=df[x_col], y=df[y_col], text=df.index, color=df[asset_col])
fig.update_traces(selectedpoints=selectedpoints,
customdata=df.index, mode='markers',
marker={'color': 'grey', 'size': 10},
unselected={'marker': {'opacity': 0.3, 'color': 'grey'}, 'textfont': {'color': 'grey'}},
selected={'marker': {'opacity': 1.0, 'color': 'yellow'}, 'textfont': {'color': 'yellow'}})
else:
print("something's wrong...")
fig.update_layout(margin={'l': 20, 'r': 0, 'b': 15, 't': 5}, dragmode='select', hovermode=False)
return fig
#app.callback(
Output('asset_df', 'data'),
Output('next_button', 'n_clicks'),
Output('dropdown','value'),
Input('dropdown', 'value'),
Input('next_button', 'n_clicks'),
prevent_initial_call=False
)
def create_asset_df(value, n_clicks):
starting_pos=0
if "next_button" == ctx.triggered_id:
new_position = n_clicks
n_clicks = n_clicks
elif "dropdown" == ctx.triggered_id:
new_position = asset_list.index(value)
n_clicks = new_position
else:
new_position = starting_pos
n_clicks = 0
df_asset = df_raw[df_raw[asset_col] == asset_list[new_position]]
df_asset = df_asset[[asset_col, X2_col, Y1_col, timestamp_col]]
df_json = df_asset.to_json()
return df_json, n_clicks, asset_list[new_position]
#app.callback(
Output('scatter', 'figure'),
Output('timeseries', 'figure'),
Input('scatter', 'selectedData'),
Input('timeseries', 'selectedData'),
Input('asset_df', 'data'),
prevent_initial_call=False
)
def display_selected_data(selection1, selection2, df_json):
print("selection1:")
print(selection1)
print("selection2:")
print(selection2)
df_asset = pd.read_json(df_json)
print("df_asset:")
print(df_asset)
for selected_data in [selection1, selection2]:
if selected_data and selected_data['points']:
selectedpoints = np.union1d(selectedpoints,
[p['customdata'] for p in selected_data['points']])
print('selectedpoints:')
print(selectedpoints)
fig1 = get_figure(df_asset, X2_col , Y1_col, asset_col, selectedpoints)
fig2 = get_figure(df_asset, timestamp_col, Y1_col, asset_col, selectedpoints)
return fig1,fig2
if __name__ == '__main__':
app.run_server(port=8081,debug=True)

How to update figure in same window dynamically without opening and redrawing in new tab?

I am creating a 3D scatter plot based off a pandas dataframe, and then I want to re-draw it with slightly updated data whenever the user presses a button in my program. I almost have this functionality working, except the updated figure is drawn via a new opened tab, when really I just want my origin existing figure to be updated.
Here is my code. First I initialize the plot with 'version 1' of the data, then I set up a simple while loop to wait for the user to request an update. Then ideally once they enter input to ask for the update, I just re-draw everything in the same tab that is open. But instead a new tab is opened (which redraws the data correctly at least).
fig = go.Figure(data=[go.Scatter3d(x=df['x'],y=df['y'],z=df['z'],mode='markers', marker=dict(
size=4,
color=df['y'], # set color to an array/list of desired values
colorscale='Viridis', # choose a colorscale
opacity=0.3
))])
# Column max and mins for plotting:
xmax = df_1.max(axis=0)['x']; xmin = df_1.min(axis=0)['x']
ymax = df_1.max(axis=0)['y']; ymin = df_1.min(axis=0)['y']
zmax = df_1.max(axis=0)['z']; zmin = df_1.min(axis=0)['z']
fig.update_layout(
scene = dict(xaxis = dict(nticks=4, range=[xmin,xmax],),
yaxis = dict(nticks=4, range=[ymin,ymax],),
zaxis = dict(nticks=4, range=[zmin,zmax],),))
f2 = go.FigureWidget(fig)
f2.show()
#fig.show()
while True:
choice = input("> ")
choice = choice.lower() #Convert input to "lowercase"
if choice == 'exit':
print("Good bye.")
break
if choice == 'w':
print("W, moving forward")
cube_origin = cube_origin + np.array([0.1,0,0])
df_cube = createCubeMesh(cube_size, cube_density, cube_origin)
new_df = df_scene_orig.copy()
new_df = new_df.append(df_cube)
fig = go.Figure(data=[go.Scatter3d(x=new_df['x'],y=new_df['y'],z=new_df['z'],mode='markers', marker=dict(
size=4,
color=new_df['y'], # set color to an array/list of desired values
colorscale='Viridis', # choose a colorscale
opacity=0.3
))])
f2 = go.FigureWidget(fig)
f2.show()
I based my code on another answer that said to use go.FigureWidget(fig), but it doesn't seem to work as intended.
Edit
Instead of me using f2.show() at the end, I just want a simple thing analogous to f2.update() that redraws.
This is the case you want.
Everywhere in this page that you see fig.show(), you can display the same figure in a Dash application by passing it to the figure argument of the Graph component from the built-in dash_core_components package like this:
import plotly.graph_objects as go
fig = go.Figure(
data=[go.Scatter(
mode="markers+text",
x=[10, 20],
y=[20, 25],
text=["Point A", "Point B"]
)],
layout=dict(height=400, width=400, template="none")
)
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash()
app.layout = html.Div([
dcc.Graph(figure=fig)
])
app.run_server(debug=True, use_reloader=False)
reference: https://plotly.com/python/figure-introspection/
Help you write a code that is closest to your needs:
import plotly as py
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.graph_objects as go
from jupyter_dash import JupyterDash
import pandas as pd
import numpy as np
py.offline.init_notebook_mode(connected=True)
app = JupyterDash('SimpleExample')
app.layout = html.Div([
dcc.Dropdown(id='dropdown', options=[
{'label': 'W', 'value': 'W'},
{'label': 'exit', 'value': 'exit'}],
value='exit'),
dcc.Graph(id='graph-court')
])
def random_data():
# sample dataframe of a wide format
np.random.seed(4)
cols = list('xyz')
X = np.random.randint(50, size=(3, len(cols)))
df = pd.DataFrame(X, columns=cols)
df.iloc[0] = 0
return df
df = random_data()
def create_figure(df):
fig = go.Figure(data=[go.Scatter3d(x=df['x'], y=df['y'], z=df['z'], mode='markers', marker=dict(
size=10,
color=df['y'],
colorscale='Viridis',
opacity=0.3
))])
# Column max and mins for plotting:
xmax = df.max(axis=0)['x']
xmin = df.min(axis=0)['x']
ymax = df.max(axis=0)['y']
ymin = df.min(axis=0)['y']
zmax = df.max(axis=0)['z']
zmin = df.min(axis=0)['z']
fig.update_layout(
scene=dict(xaxis=dict(nticks=4, range=[xmin, xmax], ),
yaxis=dict(nticks=4, range=[ymin, ymax], ),
zaxis=dict(nticks=4, range=[zmin, zmax], ), ))
fig = go.FigureWidget(fig)
return fig
#app.callback(Output('graph-court', 'figure'),
[Input('dropdown', 'value')])
def update_figure(selected_value):
selected_value = selected_value.lower() # Convert input to "lowercase"
if selected_value == 'exit':
print("Good bye.")
new_x, new_y, new_z = [], [], []
else:
print("W, moving forward")
# new data
new_x, new_y, new_z = np.random.randint(10, size=(3, 1))
# ploy
fig = create_figure(df) # Set as global variable or local variable as required
fig.add_trace(go.Scatter3d(x=new_x, y=new_y, z=new_z, marker=dict(size=10, color='green'), mode='markers'))
return fig
app.run_server(debug=False, use_reloader=False)
Estimated that your "tab" is referring to "browser tab" it is basically not possible with the standard renderer.
With the renderer browser it serves a one-shot server on a random port, which is shutting down immediately after the rendering is done. You can check that by reloading the graph in browser.
You can:
generate a static image and serve that yourself in a webapp (e.g. with flask) with f2.write_image("test.svg")
generate a dynamic html content by f2.show(renderer = "iframe") and serve that with e.g. flask
simply use plotly dash, look here for impressions
Try using Plotly for plotting, it has a functionality (Visibility), using that you can update your plot on button click or drop down.
The below example is for dropdown.
import pandas as pd
import numpy as np
import plotly.offline as py_offline
import plotly.graph_objs as go
from plotly import tools
py_offline.init_notebook_mode()
trace = go.Scatter(
x=[1, 2, 3],
y=[4, 5, 6]
)
fig = tools.make_subplots(rows=10, cols=1)
for k in range(10):
fig.append_trace(trace, k+1, 1)
updatemenus=list([
dict(
buttons=[],
direction = 'down',
pad = {'r': 10, 't': 10},
showactive = True,
x = 0,
xanchor = 'left',
y = 1.2,
yanchor = 'top'
),
])
lister = []
for k in range(11):
lister.append(dict(
args=['visible', [True for k in range(10)] if k == 0 else [True if (i+1) == k else False for i in range(10)]],
label='Show Trace ' + str( 'All' if k == 0 else k),
method='restyle'
))
updatemenus[0]['buttons'] = lister
fig['layout']['updatemenus'] = updatemenus
fig['layout'].update(title='subplots')
py_offline.iplot(fig, filename='simple-subplot')

How to add values from selectedData input to a list?

I build a Plotly Dash web app to display sensor data. I want to have a map where I can select the stations and therefore I can see the time series chart.
This is my callback right now:
#app.callback(
Output('time_series1', 'figure'),
Input('map_sensors', 'selectedData'))
def display_selected_data(selectedData):
if selectedData is None: # Plot whole Dataframe if nothing is selected.
fig = px.line(data_frame=df, x='date.utc', y='value', color='location')
return fig
else:
selectedData['points'][0]['customdata'][0] # This line shows me the name of the location and I want to add this to a list
return
I can show the location in the selected data. Now my question is, how can I add this to a list?
My goal ist to filter the dataframe like this dff2 = df[df.location.isin(selected_locations)] so that I only plot the selected locations.
My full app right now:
from jupyter_dash import JupyterDash
import plotly.graph_objs as go
from dash import Dash, dcc, html, Input, Output, State
import pandas as pd
import plotly.express as px
import json
loc = pd.read_csv('location_sensors.csv')
df = pd.read_csv('measurement.csv')
style = {'width': '50%', 'height': '500px', 'float': 'left'}
# Build small example app.
app = dash.Dash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
fig_map = px.scatter_mapbox(loc, lat="lat", lon="lon", hover_name="location",
hover_data={'location':True, 'lat':False, 'lon':False}, zoom=3, height=600,
color='location', mapbox_style="open-street-map")
fig_map.update_layout(clickmode='event+select')
app.layout = html.Div([
dcc.Graph(id='map_sensors', figure=fig_map , className='six columns'),
html.Div([dcc.Graph(
id='time_series1',
style={'height': 400}
),
])
])
#app.callback(
Output('time_series1', 'figure'),
Input('map_sensors', 'selectedData'))
def display_selected_data(selectedData):
if selectedData is None:
fig = px.line(data_frame=df, x='date.utc', y='value', color='location')
return fig
else:
# Here I want to filter the dataframe to the selected locations.
return
if __name__ == '__main__':
app.run_server()
Locations csv data:
lat,lon,location
51.20966,4.43182,BETR801
48.83722,2.3939,FR04014
51.49467,-0.13193,London Westminster
Time series data:
https://github.com/pandas-dev/pandas/blob/master/doc/data/air_quality_long.csv
For your #app.callback decorator, I think you want your input to be clickData instead of selectionData. If you look at the first example in the documentation here, once you click a location on the map and it is greyed out, when you click it again at a later time, clickData will input a dictionary with marker information, while selectionData will input null (this means that dash will have trouble knowing when you click on a point again after it's been greyed out if you use selectionData instead of clickData)
You can then have a dynamic list that changes depending on locations the user selects and deselects. Also a very minor point, but I changed your DataFrame variable name from loc to locs since .loc is a pandas DataFrame method.
from jupyter_dash import JupyterDash
import plotly.graph_objs as go
import dash
from dash import Dash, dcc, html, Input, Output, State
import pandas as pd
import plotly.express as px
import json
locs = pd.read_csv('location_sensors.csv')
df = pd.read_csv('https://raw.githubusercontent.com/pandas-dev/pandas/master/doc/data/air_quality_long.csv')
style = {'width': '50%', 'height': '500px', 'float': 'left'}
# Build small example app.
app = dash.Dash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
fig_map = px.scatter_mapbox(locs, lat="lat", lon="lon", hover_name="location",
hover_data={'location':True, 'lat':False, 'lon':False}, zoom=3, height=600,
color='location', mapbox_style="open-street-map")
fig_map.update_layout(clickmode='event+select')
app.layout = html.Div([
dcc.Graph(id='map_sensors', figure=fig_map , className='six columns'),
html.Div([dcc.Graph(
id='time_series1',
style={'height': 400}
),
])
])
## define a list that will hold the columns of the dataframe
## this will be used to modify the px.line chart
selected_locations = list(locs['location'])
#app.callback(
Output('time_series1', 'figure'),
Input('map_sensors', 'clickData'))
def display_selected_data(clickData):
## when the app initializes
if clickData is None:
fig = px.line(data_frame=df, x='date.utc', y='value', color='location')
## when the user clicks on one of the loc points
else:
selection = clickData['points'][0]['customdata'][0]
if selection in selected_locations:
selected_locations.remove(selection)
else:
selected_locations.append(selection)
fig = px.line(data_frame=df[df.location.isin(selected_locations)], x='date.utc', y='value', color='location')
return fig
if __name__ == '__main__':
app.run_server(debug=True)

Interactive plot with Slider using Plotly

How do I recreate the following interactive plot in Python using Plotly?
My simple example draws a bar chart with one column x and another 1-x.
GIF from Mathematica:
Slider allows for a varying x between 0 and 1.
Mathematica code:
Manipulate[BarChart[{x, 1 - x}, PlotRange -> {0, 1}],
{{x, 0.3, "Level"}, 0, 1, Appearance -> "Open"}]
UPDATE
Here is a solution which I don't like:
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected=True)
import ipywidgets as widgets
Plotting:
def update_plot(x):
data = [go.Bar(
x=['1', '2'],
y=[x, 1-x]
)]
iplot(data, show_link=False)
x = widgets.FloatSlider(min=0, max=1, value=0.3)
widgets.interactive(update_plot, x=x)
Problems with this:
The plot twinkles when the slider is moved
The slider is misplaced
The increment is not granular enough
I cannot specify a precise value myself
Code below creates an interactive plot in plotly and Dash. It takes two inputs: slider and text box. When the code below saved as a '.py' and the file is run in terminal, it should run a local server in the terminal. Next, copy the * Running on http:// address from this server and paste it in browser to open the plot. Most likely it would be http://127.0.0.1:8050/. Resources: 1, 2, 3 . (Python 3.6.6)
Important: Please note that for the slider to work, the text box value has to be reset to '0' (zero).
Import libraries
import numpy as np
import pandas as pd
from plotly import __version__
import plotly.offline as pyo
import plotly.graph_objs as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
Create Dash app
app = dash.Dash()
app.layout = html.Div(
html.Div([
html.Div([html.H5("Level"),
dcc.Slider(id='slider_input',
min=0,
max=1,
step=0.005,
value=0.1,
)],style={'width': '200'}
),
html.Div(style={'height': '10'}),
html.Div(dcc.Input( id='text_input',
placeholder='Enter a value...',
type='text',
value=0.0
),style={'width': '50'}),
dcc.Graph(id='example',
figure={'data':[{'x':[1,2],
'y':[0,1],
'type':'bar',
'marker':dict(color='#ffbf00')
}],
'layout': go.Layout(title='Plot',
#xaxis = list(range = c(2, 5)),
yaxis=dict(range=[0, 1])
)
})
], style={'width':'500', 'height':'200','display':'inline-block'})
)
# callback - 1 (from slider)
#app.callback(Output('example', 'figure'),
[Input('slider_input', 'value'),
Input('text_input', 'value')])
def update_plot(slider_input, text_input):
if (float(text_input)==0.0):
q = float(slider_input)
else:
q = float(text_input)
figure = {'data': [go.Bar(x=[1,2],
y=[q, 1-q],
marker=dict(color='#ffbf00'),
width=0.5
)],
'layout': go.Layout(title='plot',
#xaxis = list(range = c(2, 5)),
yaxis=dict(range=[0, 1])
)
}
return figure
Run server
if __name__ == '__main__':
app.run_server()
Output
Edit - 1 .............................
Plot with slider only
The code below uses plotly without dash. The plot is interactive with a slider. Note that this code does not have a text input to change the plot (as above). However, the plot below should update with slider without the need to 'release' the slider to see the update. In this plot, individual traces were created for plotting.
Import libraries
import pandas as pd
import numpy as np
from plotly import __version__
%matplotlib inline
import json
import plotly.offline as pyo
import plotly.graph_objs as go
from plotly.tools import FigureFactory as FF
import cufflinks as cf
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
init_notebook_mode(connected=True)
init_notebook_mode(connected=True)
cf.go_offline()
Create traces
traces = []
q = np.linspace(0,1, 100)
for i in range(0,len(q)):
trace = dict(
type = 'bar',
visible = False,
x=[1, 2],
y=[q[i], 1 - q[i]],
marker=dict(color='#ffbf00'),
width=0.5
)
traces.append(trace)
traces[0]['visible'] = 'True'
Create slider
steps=[]
for i in range(len(traces)):
step = dict(
method = 'restyle',
args = ['visible', [False] * len(traces)],
label=""
)
step['args'][1][i] = True # Toggle i'th trace to "visible"
steps.append(step)
sliders = [dict(
active = 10,
currentvalue = {"prefix": "Level: "},
#pad = {"t": 50},
steps = steps
)]
Create layout
layout = go.Layout(
width=500,
height=500,
autosize=False,
yaxis=dict(range=[0, 1])
)
layout['sliders'] = sliders
Plot figure
fig = go.Figure(data=traces, layout=layout)
#pyo.iplot(fig, show_link=False) # run this line to view inline in Jupyter Notebook
pyo.plot(fig, show_link=False) # run this line to view in browser
Starting from Plotly 3.0 this can be achieved as follows (in JupyterLab):
import plotly.graph_objects as go
from ipywidgets import interact
fig = go.FigureWidget()
bar = fig.add_bar(x=['x', '1-x'])
fig.layout = dict(yaxis=dict(range=[0,1]), height=600)
#interact(x=(0, 1, 0.01))
def update(x=0.3):
with fig.batch_update():
bar.y=[x, 1-x]
fig
Update:
From Plotly 4.0 you need to specify fig.data[0].y instead of bar.y.

Categories