Create a wrapper function for Plotly plotting functions - python

I am working on Jupyter notebook, and I am trying to create a wrapper function for the regular Plotly Scatter3d() function, with my own layout settings, so that I can call this directly every time I need to plot something, and save screen space.
BUT, this is not working. Nothing is getting displayed on the screen. Does anyone know why?
My code:
def BSplot3dPlotly(xyz):
xyz = np.reshape(xyz, (int(xyz.size/3), 3))
trace1 = go.Scatter3d(
x=xyz[:,0],
y=xyz[:,1],
z=xyz[:,2],
mode = 'markers', # lines+markers',
#marker=Marker(color=Y, colorscale='Portland')
marker=dict(
size=12,
line=dict(
color='rgba(217, 217, 217, 0.14)',
width=0.5
),
opacity=0.8
)
)
data = go.Data([trace1]) #[trace1]
layout = go.Layout(
margin=dict(
l=0,
r=0,
b=0,
t=0
)
)
fig = go.Figure(data=data, layout=layout)
py.iplot(fig, filename=name)
Here the imput xyzis just a list containing x,y,z coordinates for some points.

You are defining a function BSplot3dPlotly but it doesn't return anything which might be the reason why you don't see anything.
Having line in the marker dict does not do anything. You would need to set mode to markers+lines to get both markers and lines and then use a separate line dict.
import numpy as np
import plotly.graph_objs as go
import plotly.plotly as py
import plotly.offline as offline
def scatter3d_wrapper(xyz):
trace = go.Scatter3d(
x=xyz[:,0],
y=xyz[:,1],
z=xyz[:,2],
mode = 'markers+lines',
marker=dict(
color='rgb(255,0,0)',
size=12
),
line=dict(
color='rgb(0, 0, 255)',
width=10
)
)
return trace
xyz = np.random.random((20, 3))
trace1 = scatter3d_wrapper(xyz)
data = go.Data([trace1])
fig = go.Figure(data=data)
offline.plot(fig, filename='wrapper.html')

For matplotlib, you have to run the following before you can see charts:
%matplotlib inline
Try that.

Related

how can I export this interactive plot to view in a browser without jupyter?

I have this interactive plot in python:
import ipywidgets as widgets
import plotly.graph_objects as go
from numpy import linspace
def leaf_plot(sense, spec):
fig = go.Figure()
x = linspace(0,1,101)
x[0] += 1e-16
x[-1] -= 1e-16
positive = sense*x/(sense*x + (1-spec)*(1-x))
#probability a person is infected, given a positive test result,
#P(p|pr) = P(pr|p)*P(p)/P(pr)
# = P(pr|p)*P(p)/(P(pr|p)*P(p) + P(pr|n)*P(n))
# = sense*P(p)/( sense*P(p) +(1-spec)*P(n))
negative = 1-spec*(1-x)/((1-sense)*x + spec*(1-x))
fig.add_trace(
go.Scatter(x=x, y = positive, name="Positive",marker=dict( color='red'))
)
fig.add_trace(
go.Scatter(x=x, y = negative,
name="Negative",
mode = 'lines+markers',
marker=dict( color='green'))
)
fig.update_xaxes(title_text = "Base Rate")
fig.update_yaxes(title_text = "Post-test Probability")
fig.show()
sense_ = widgets.FloatSlider(
value=0.5,
min=0,
max=1.0,
step=0.01,
description='Sensitivity:',
disabled=False,
continuous_update=False,
orientation='horizontal',
readout=True,
readout_format='.2f',
)
spec_ = widgets.FloatSlider(
value=0.5,
min=0,
max=1.0,
step=0.01,
description='Specificity:',
disabled=False,
continuous_update=False,
orientation='horizontal',
readout=True,
readout_format='.2f',
)
ui = widgets.VBox([sense_, spec_])
out = widgets.interactive_output(leaf_plot, {'sense': sense_, 'spec': spec_})
display(ui, out)
How can I export this so that it can be viewed as a standalone web page in a browser, say as HTML, while retaining the interactivity, as e.g. in https://gabgoh.github.io/COVID/index.html ?
Using plotly's fig.write_html() option I get a standalone web page, but this way I lose the sliders.
With some modification, plotly allows at most for a single slider (the ipywidgets are not included in the plotly figure object).
Plus, in plotly, the said slider basically controls the visibility of pre-calculated traces (see e.g. https://plotly.com/python/sliders/), which restricts the interactivity (sometimes the parameter space is huge).
What's the best way to go?
(I don't necessarily need to stick with plotly/ipywidgets)
you need to rework things a bit, but you can achieve what you want with dash and Heroku.
first you need to modify leaf_plot() to return a figure object.
from numpy import linspace
def leaf_plot(sense, spec):
fig = go.Figure()
x = linspace(0,1,101)
x[0] += 1e-16
x[-1] -= 1e-16
positive = sense*x/(sense*x + (1-spec)*(1-x))
negative = 1-spec*(1-x)/((1-sense)*x + spec*(1-x))
fig.add_trace(
go.Scatter(x=x, y = positive, name="Positive",marker=dict( color='red'))
)
fig.add_trace(
go.Scatter(x=x, y = negative,
name="Negative",
mode = 'lines+markers',
marker=dict( color='green'))
)
fig.update_layout(
xaxis_title="Base rate",
yaxis_title="After-test probability",
)
return fig
Then write the dash app:
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
# Build App
app = JupyterDash(__name__)
app.layout = html.Div([
html.H1("Interpreting Test Results"),
dcc.Graph(id='graph'),
html.Label([
"sensitivity",
dcc.Slider(
id='sensitivity-slider',
min=0,
max=1,
step=0.01,
value=0.5,
marks = {i: '{:5.2f}'.format(i) for i in linspace(1e-16,1-1e-16,11)}
),
]),
html.Label([
"specificity",
dcc.Slider(
id='specificity-slider',
min=0,
max=1,
step=0.01,
value=0.5,
marks = {i: '{:5.2f}'.format(i) for i in linspace(1e-16,1-1e-16,11)}
),
]),
])
# Define callback to update graph
#app.callback(
Output('graph', 'figure'),
Input("sensitivity-slider", "value"),
Input("specificity-slider", "value")
)
def update_figure(sense, spec):
return leaf_plot(sense, spec)
# Run app and display result inline in the notebook
app.run_server()
If you execute this in a jupyter notebook, you will only be able to access your app locally.
If you want to publish, you can try Heroku
With plotly, after creating the figure, save it:
fig.write_html("path/to/file.html")
Also try this parameter in the function:
animation_opts: dict or None (default None)
dict of custom animation parameters to be passed to the function
Plotly.animate in Plotly.js. See
https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js
for available options. Has no effect if the figure does not contain
frames, or auto_play is False.
Otherwise, check here for some suggestions: https://community.plotly.com/t/export-plotly-and-ipywidgets-as-an-html-file/18579

Why am i getting an extra line in my plotly plot?

I have a dataframe tx_user_type_revenue:
I create a plot using plotly but for some reason it shows me an extra line. This code works fine for other data.
import plotly.plotly as py
import plotly.offline as pyoff
import plotly.graph_objs as go
#filtering the dates and plot the result
tx_user_type_revenue = tx_user_type_revenue.query("InvoiceYearMonth > 201601 and InvoiceYearMonth < 201901")
plot_data = [
go.Scatter(
x=tx_user_type_revenue.query("UserType == 'Existing'")['InvoiceYearMonth'],
y=tx_user_type_revenue.query("UserType == 'Existing'")['Revenue'],
name = 'Existing'
),
go.Scatter(
x=tx_user_type_revenue.query("UserType == 'New'")['InvoiceYearMonth'],
y=tx_user_type_revenue.query("UserType == 'New'")['Revenue'],
name = 'New'
)
]
plot_layout = go.Layout(
xaxis={"type": "category"},
title='New vs Existing Customers Revenue'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)

Plotting polygons on mapbox with plotly

I am trying to plot geojson geometries with plotly using scattermapbox.
This piece of code converts data successfully from geopandas for plotly to work with:
from plotly.offline import download_plotlyjs, init_notebook_mode,
plot, iplot
import plotly.graph_objs as go
mapbox_access_token = 'mykey'
import json
from_json = geopandas_gdf.to_json()
geoJSON = json.loads(from_json)
pts=[]#list of points defining boundaries of polygons
for feature in geoJSON['features']:
if feature['geometry']['type']=='Polygon':
pts.extend(feature['geometry']['coordinates'][0])
pts.append([None, None])#mark the end of a polygon
elif feature['geometry']['type']=='MultiPolygon':
for polyg in feature['geometry']['coordinates']:
pts.extend(polyg[0])
pts.append([None, None])#end of polygon
else: raise ValueError("geometry type irrelevant for map")
X, Y=zip(*pts)
I am able to plot this data on blanc figure with the following code:
axis_style=dict(showline=False,
mirror=False,
showgrid=False,
zeroline=False,
ticks='',
showticklabels=False)
layout=dict(title='map',
width=700, height=700,
autosize=False,
xaxis=axis_style,
yaxis=axis_style,
hovermode='closest')
fig=dict(data=data, layout=layout)
plot(fig, filename='map')
But I can not plot this on scattermapbox. Trying like this:
data = [
go.Scattermapbox(
lat=X,
lon=Y,
line = go.scattermapbox.Line(width=5,
color='red'))
]
layout = go.Layout(
autosize=True,
hovermode='closest',
mapbox=go.layout.Mapbox(
accesstoken=mapbox_access_token,
bearing=0,
center=go.layout.mapbox.Center(
lat=53,
lon=0
),
pitch=0,
zoom=5
),
)
fig = go.Figure(data=data, layout=layout)
plot(fig, filename='Montreal Mapbox')
thank you!
I have managed to do this with the following:
layout = go.Layout(
height=1500,
autosize=True,
hovermode='closest',
mapbox=dict(
layers=[
dict(
sourcetype = 'geojson',
source = geoJSON,
type = 'fill',
color = 'rgba(163,22,19,0.8)'
)
],
accesstoken=mapbox_access_token,
bearing=0,
center=dict(
lat=53,
lon=0
),
pitch=0,
zoom=5.2,
style='light'
),
)
But then the other question arises: how to provide data from json to hover?
Answer to your secondary question
Provide Data from JSON to hover by using customdata attribute inside data that is passed to the plot.
Additionally: Could you please route a general json dataset, so that others can easily run your code blocks please?
Link to customdata attribute: https://plot.ly/python/reference/#scatter-customdata
Else, you could use text and mode='markers + text' to display data from text attribute on hover.

How to show only one trace when plotly updatemenus load on Jupyter Notebook?

I have two graphs that I want to show using plotly's updatemenus feature. I am able to populate and display the data using the updatemenus feature. However, when the plot loads, both the graphs are displayed initially. Is there a way to show only one graph when the plot loads initially?
I went through the documentation for updatemenus on plotly but could not find any attribute that will help me in achieving this.
trace28 = go.Bar(x=for1.head()['Name'],
y=for1.head()['G'],
name='Goals',
opacity=0.8
)
trace29 = go.Bar(x=for1.head()['Name'],
y=for1.head()['A'],
name='Assists',
opacity=0.8
)
trace30 = go.Bar(x=for2.head()['Name'],
y=for2.head()['G'],
name='Goals',
opacity=0.8
)
trace31 = go.Bar(x=for2.head()['Name'],
y=for2.head()['A'],
name='Assists',
opacity=0.8
)
updatemenus = list([dict(active=-1,
type='buttons',
buttons=list([dict(label='2011/12',
method='update',
args=[dict(visible=[True, True, False, False]),
dict(title='<b>Forward Stats 2011/12</b>')
]
),
dict(label='2012/13',
method='update',
args=[{'visible':[False, False, True, True]},
{'title':'<b>Forward Stats 2012/13</b>'}
]
),
])
),
])
layout = go.Layout(title='<b>Forward Stats</b>',
xaxis=dict(title='<b><i>Player Name</b></i>'),
yaxis=dict(title='<b><i>Goals/Assists</b></i>'),
updatemenus=updatemenus,
showlegend=False,
barmode='group'
)
data = [trace28, trace29, trace30, trace31]
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)
I want to display only trace28 and trace29 when the plot loads. Right now, all the traces are being shown when the plot loads.
While making the trace, you can set visible = "legendonly". Then you can toggle the trace by clicking on the line in the legend. Does that do what you want?
So you would change trace30 and trace31
trace30 = go.Bar(x=for2.head()['Name'],
y=for2.head()['G'],
name='Goals',
opacity=0.8,
visible = "legendonly"
)
trace31 = go.Bar(x=for2.head()['Name'],
y=for2.head()['A'],
name='Assists',
opacity=0.8,
visible = "legendonly"
)
Does that get you your desired functionality?

Jupyter Notebook not ploting output using plotly

I am working on choropleth using plotly in Jupyter Notebook.I want to plot choropleth but its showing me empty output.I am working with offline plotly.In html its genrated chart successfuly but when i tried offline it shows me empty output.please tell me how i solve this error.
here is my code
from plotly.graph_objs import *
from plotly.offline import download_plotlyjs, init_notebook_mode, iplot
from plotly.offline.offline import _plot_html
init_notebook_mode(connected=True)
for col in state_df.columns:
state_df[col] = state_df[col].astype(str)
scl = [[0.0, 'rgb(242,240,247)'],[0.2, 'rgb(218,218,235)'],[0.4, 'rgb(188,189,220)'],\
[0.6, 'rgb(158,154,200)'],[0.8, 'rgb(117,107,177)'],[1.0, 'rgb(84,39,143)']]
state_df['text'] = state_df['StateCode'] + '<br>' +'TotalPlans '+state_df['TotalPlans']
data = [ dict(
type='choropleth',
colorscale = scl,
autocolorscale = False,
locations = state_df['StateCode'],
z = state_df['TotalPlans'].astype(float),
locationmode = 'USA-states',
text = state_df['text'],
marker = dict(
line = dict (
color = 'rgb(255,255,255)',
width = 2
)
),
colorbar = dict(
title = "Millions USD"
)
) ]
layout = dict(
title = 'Plan by States',
geo = dict(
scope='usa',
projection=dict( type='albers usa' ),
showlakes = True,
lakecolor = 'rgb(255, 255, 255)',
),
)
fig = dict(data=data, layout=layout)
plotly.offline.iplot(fig)
You are passing a dictionary to iplot which in contradiction to the documentation can handle only Figure objects and not dictionaries.
Try
fig = Figure(data=[data], layout=layout)
and it should work.

Categories

Resources