I am using the below code to generate a pie chart.
How does one capture name = "female" that appears when you click over a sector into a variable. ?
import plotly.express as px
df = px.data.tips()
fig = px.sunburst(df, path=['day', 'sex'], values='total_bill')
fig.show()
From what I have found so far there is a on_click callback. For testing when I do
a print statement, it does not show any thing. I need to open a explorer path based
on what user clicks. What's the possible way to do so ?
import plotly.graph_objects as go
import numpy as np
np.random.seed(1)
x = np.random.rand(100)
y = np.random.rand(100)
f = go.FigureWidget([go.Scatter(x=x, y=y, mode='markers')])
scatter = f.data[0]
# create our callback function
def update_point(trace, points, selector):
print(trace, points, selector)
subprocess.Popen(['explorer', 'path_build_after_user_clicks_on_a_sector'])
scatter.on_click(update_point)
f
Related
I want to mix Plotly with a dropdown widget, the idea being to make some scatter plots and modify the x axis through the widget. Let's say that my dataset is the following :
import sea born as sns
import plotly.graph_objects as go
import pandas as pd
import ipywidgets as widgets
import seaborn as sns
df = sns.load_dataset('diamonds')
And my target is the column carat. What I tried so far is to create the scatters, include them into the widget and display it :
predictors = df.columns.tolist()
predictors.remove("carat")
target = df["carat"]
data = []
for predictor in predictors:
chart = go.Scatter(x = df[predictor],
y = target,
mode="markers")
fig = go.Figure(data=chart)
data.append((predictor,fig))
widgets.Dropdown(options = [item[0] for item in data],
value = [item[0] for item in data][0],
description = "Select :",
disabled=False)
Yet, I am new to ipywidgets/plotly and don't understand what is not working here, since it displays the widget but not the charts even when I change its value. How can I modify the code so that it finally displays the charts when selecting a predictor ?
You can use interact to read the values from the DropDown and plot your graph:
import plotly.graph_objects as go
import pandas as pd
import seaborn as sns
from ipywidgets import widgets
from ipywidgets import interact
import plotly.express as px
df = sns.load_dataset('diamonds')
predictors = df.columns.tolist()
predictors.remove("carat")
target = df["carat"]
#interact
def read_values(
predictor=widgets.Dropdown(
description="Select :", value="clarity", options=predictors
)
):
fig = px.scatter(df, x = predictor, y = target)
go.FigureWidget(fig.to_dict()).show()
I am trying to create an interactive boxplot with ipywidgets and Plotly.
I started by looking at this example
While this is fine, I'd like to change the groupings of the boxplot based on a dropdown input.
With interact I can do this:
import datetime
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from ipywidgets import widgets
df = pd.read_csv(
'https://raw.githubusercontent.com/yankev/testing/master/datasets/nycflights.csv')
df = df.drop(df.columns[[0]], axis=1)
from ipywidgets import interact
def view_image(col):
fig = go.FigureWidget()
for val in df[col].unique():
groupData = df.query(f'{col} == "{val}"')
fig.add_trace(
go.Box(y = groupData['distance'],
name = val)
)
fig.show()
interact(view_image, col = ['origin', 'carrier'])
And the result is that I can change the column based on which the data is grouped.
However, I would like to have more control on the widgets, like in the official example.
This is what I am trying (and failing):
# Assign an empty figure widget with two traces
gdata = []
for origin in df.origin.unique():
groupData = df.query(f'origin == "{origin}"')
gdata.append(
go.Box(y = groupData['distance'],
name = origin)
)
g = go.FigureWidget(data=gdata,
layout=go.Layout(
title=dict(
text='NYC FlightDatabase'
),
barmode='overlay'
))
def response_box(change):
col = column.value
with g.batch_update():
gdata = []
for val in df[col].unique():
groupData = df.query(f'{col} == "{val}"')
gdata.append(
go.Box(y = groupData['distance'],
name = val)
)
g.data = gdata
column = widgets.Dropdown(
options=['origin','carrier']
)
column.observe(response_box, 'value')
container2 = widgets.HBox([column])
widgets.VBox([container2,
g])
Note that since I have new groupings, I cannot just go into g.data[index].y and change per index, but I have to re-generate the figure as in the interact function.
This particular iteration gives me a "you cannot update data directly" error. I tried in a few different ways, but I don't seem to find one that works.
Any idea?
it's not clear how you want to interact with the dimensions of data. So I've gone with defining x and color of figure, plus filtering by origin, dest, carrier
box plots are far simpler to create using Plotly Express so have used that
it then really simplifies to passing parameters. Have used https://ipywidgets.readthedocs.io/en/latest/examples/Using%20Interact.html with decorator
import datetime
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
from ipywidgets import widgets
from ipywidgets import interact
df = pd.read_csv(
"https://raw.githubusercontent.com/yankev/testing/master/datasets/nycflights.csv"
)
df = df.drop(df.columns[[0]], axis=1)
#interact
def view_image(
col=widgets.Dropdown(
description="Plot:", value="carrier", options=["origin", "carrier"]
),
filtercol=widgets.Dropdown(
description="Filter by:", value="carrier", options=["origin", "dest", "carrier"]
),
filter=widgets.Text(
description="Filter:", value=""
),
):
# check if filter results in any rows... if not all data...
if df[filtercol].eq(filter).any():
dfp = df.loc[df[filtercol].eq(filter)]
else:
dfp = df
fig = px.box(dfp, x=col, y="distance", color=col)
go.FigureWidget(fig.to_dict()).show()
Is there is a way to hide all other lines on a figure, when I am hovering a single one?
Example:
import numpy as np
import plotly.express as px
np.random.seed(42)
data = np.random.randint(0, 10, (5, 10))
fig = px.line(data_frame=pd.DataFrame(data))
fig.show()
will produce:
and I want this, when I hover particular line (but without manually switching off all other lines and keeping X, Y axes dims):
UPD: inside jupyter notebook
The following suggestion draws from the posts Plotly Dash: How to reset the "n_clicks" attribute of a dash-html.button? and Plotly-Dash: How to code interactive callbacks for hover functions in plotly dash and will let you display a single trace by hovering on any point or part of the line. The rest of the traces aren't completely hidden though, but are made grey and transparent in the background so that you can more easily make another selection.
To reset the figure and make all traces fully visible at the same time, just click Clear Selection. I understand that you would prefer a "plain" Jupyter approach to obtain this functionality, but you'd be missing out on the true power of plotly which reveals itself to the full extent only through Dash and JupyterDash. With this suggestion, you won't see any difference between Dash and "plain" Jupyter since the figure, or app, is displayed inline with app.run_server(mode='inline')
Plot 1 - Upon launch. Or after clicking Clear selection
Plot 2 - Selection = trace a
Plot 3 - Selection = trace b
Complete code
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
# pandas and plotly settings
pd.options.plotting.backend = "plotly"
# app info
app = JupyterDash(__name__)
# sample data and figure setup
df = pd.DataFrame(np.random.randint(-1,2,size=(200, 12)), columns=list('abcdefghijkl'))
df = df.cumsum()#.reset_index()
fig = df.plot(title = 'Selected traces = all', template='plotly_dark')#.update_traces(line_color = 'rgba(50,50,50,0.5)')
set_fig = go.Figure(fig)
colors = {d.name:d.line.color for i, d in enumerate(set_fig.data)}
# jupyterdash app
app.layout = html.Div([html.Button('Clear selection', id='clearit', n_clicks=0),
dcc.Graph(id='hoverfig',figure=fig,#clear_on_unhover = True
),])
colors = {d.name:d.line.color for i, d in enumerate(set_fig.data)}
# callbacks
#app.callback(
Output('hoverfig', 'figure'),
[Input('hoverfig', 'hoverData'), Input('clearit', 'n_clicks')])
def display_hover_data(hoverData, resetHover):
changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0]
if 'clearit' in changed_id:
return set_fig
else:
try:
fig2 = fig.update_layout(title = 'Selected trace = ' + fig.data[hoverData['points'][0]['curveNumber']].name)
fig2.for_each_trace(lambda t: t.update(line_color = 'rgba(50,50,50,0.5)',line_width = 1) if t.name != fig.data[hoverData['points'][0]['curveNumber']].name else t.update(line_color = colors[t.name], line_width = 2))
return fig2
except:
return fig
app.run_server(mode='inline', port = 8070, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
import plotly.graph_objects as go
import numpy as np
import pandas as pd
# callback function for on_hover
def hide_traces_on_hover(trace, points, selector):
if len(points.point_inds)==1: # identify hover
i = points.trace_index # get the index of the hovered trace
f.data[i].visible = True # keep the hovered trace visible
# create a list of traces you want to hide
hide_traces = [l_trace for idx, l_trace in enumerate(f.data) if idx != i]
for l_trace in hide_traces: # iterate over hide_traces
l_trace.visible = 'legendonly' # hide all remaining traces
# callback function to unhide traces on click
def unhide_traces_on_click(trace, points, selector):
for l_trace in f.data:
l_trace.visible = True
# your sample data frame
np.random.seed(42)
data = np.random.randint(0, 10, (5, 10))
df = pd.DataFrame(data)
f = go.FigureWidget() # create figure widget
f.update_yaxes(autorange=False) # set auto range to false
# define the range of the y-axis using min and max functions
f.update_layout(yaxis_range=[df.values.min()-1, df.values.max()+1])
# create your traces from the data frame
for col in df.columns:
trace = go.Scatter(x=df.index, y=df[col], mode='lines+markers')
f.add_trace(trace)
# assign your functions to each trace
for trace in f.data:
trace.on_hover(hide_traces_on_hover)
trace.on_click(unhide_traces_on_click)
f
If you are running into issues, here is the jupyter notebook support documentation for using FigureWidget and here is the jupyter lab support documentation. Make sure you have the ipywidgets package installed. Also, just as a FYI, here is the FigureWidget documentation.
When you hover over a marker in the graph.
When you click on any marker of the visible trace all the hidden traces will become visible again.
Trying to plot a very simple 3d scatter plot with x,y,z axes all equal in length. It is not working.
Code:
'''
from mpl_toolkits import mplot3d
import pandas
from pandas import DataFrame
pt_num = 100
x = np.random.uniform(-10,10,size=(pt_num,2))
model = np.array([2,2]).reshape(-1,1)
y = np.dot(x,model)
data = np.hstack((x,y))
dats = {'x':data[:,0].squeeze(),'w':data[:,1].squeeze(),'y':data[:,2].squeeze()}
df = DataFrame(data=dats)
import plotly.express as px
fig = px.scatter_3d(df, x='x', y='w', z='y',width=1200, height=1200)
fig.update_layout(scene=dict(xaxis=dict(range=[-10,10]),yaxis=dict(range=[-10,10]),zaxis=dict(range=[-10,10])))
fig['layout'].update(width=1500, height=1500, autosize=False)
fig.show()
'''
Thank you for any help.
Asked too soon out of frustration. The answer is to add 'aspectmode="cube"' to the scene dict for fig.update_layout:
fig.update_layout(scene=dict(xaxis=dict(range=view_range),yaxis=dict(range=view_range),zaxis=dict(range=view_range),aspectmode="cube"))
If I create a horizontal bar graph using plotly, the labels for each bar are right up against the graph. I'd like to add some space/pad/margin between the label and the graph. How can I do this?
Example:
import plotly.offline as py
import plotly.graph_objs as go
labels = ['Alice','Bob','Carl']
vals = [2,5,4]
data = [go.Bar(x=vals, y=labels, orientation='h')]
fig = go.Figure(data)
py.iplot(fig)
Just use parameter pad in margin. Check example from docs here.
Code:
import plotly.offline as py
import plotly.graph_objs as go
labels = ['Alice','Bob','Carl']
vals = [2,5,4]
data = [go.Bar(x=vals, y=labels, orientation='h')]
layout = go.Layout(
margin=dict(
pad=20
),
title = 'hbar',
)
fig = go.Figure(data=data,layout=layout)
py.plot(fig, filename='horizontal-bar.html')
And plot should be looks something like that:
Shorter solution:
fig.update_layout(margin_pad=10)
I think you could add some code like this.
import plotly.offline as py
import plotly.graph_objs as go
labels = ['Alice','Bob','Carl']
vals = [2,5,4]
data = [go.Bar(x=vals, y=labels, orientation='h')]
layout = dict(yaxis=dict(ticksuffix=" "))
fig = go.Figure(data=data,layout=layout)
py.iplot(fig)
add a suffix will fix this problem easily. I have checked the reference plotly ref, it also have more suitable key named tickformat, but it hard to use so I didn't use it.