Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interactive plot with Slider using Plotly

Tags:

python

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:

enter image description here

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
like image 766
Sandu Ursu Avatar asked Sep 15 '25 16:09

Sandu Ursu


2 Answers

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

enter image description here


Update:

From Plotly 4.0 you need to specify fig.data[0].y instead of bar.y.

like image 86
Sandu Ursu Avatar answered Sep 18 '25 06:09

Sandu Ursu


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

enter image description here

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 

enter image description here

like image 42
Nilesh Ingle Avatar answered Sep 18 '25 06:09

Nilesh Ingle