Plotly: How to inspect and make changes to a plotly figure? - python

Related questions have already been asked and before e.g.
How can I search for the options for a particular property of a plotly figure?
Plotly: How to inspect the basic figure structure (version 4)
But the answers to these questions have been limited by the fact that not all parameters have been available through Python, meaning that the real answers were buried somewhere in JavaScript. But for newer versions of plotly, how can you inspect and edit a plotly figure? How could you, for example, find out what the background color of a figure is? And then change it? From the second link above you can see that fig.show and print(fig) will reveal some details about the figure structure. But certainly not all of it. The code snippet below will produce the following plot:
Plot:
Code:
import plotly.graph_objects as go
import plotly.express as px
df = px.data.gapminder().query("country=='Canada'")
fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada')
fig.show()
Running fig.show will now partly reveal the structure of the figure in the form of a dict:
<bound method BaseFigure.show of Figure({
'data': [{'hovertemplate': 'year=%{x}<br>lifeExp=%{y}<extra></extra>',
'legendgroup': '',
'line': {'color': '#636efa', 'dash': 'solid'},
'mode': 'lines',
'name': '',
'orientation': 'v',
'showlegend': False,
'type': 'scatter',
'x': array([1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, 2002, 2007],
dtype=int64),
'xaxis': 'x',
'y': array([68.75 , 69.96 , 71.3 , 72.13 , 72.88 , 74.21 , 75.76 , 76.86 , 77.95 ,
78.61 , 79.77 , 80.653]),
'yaxis': 'y'}],
'layout': {'legend': {'tracegroupgap': 0},
'template': '...',
'title': {'text': 'Life expectancy in Canada'},
'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'title': {'text': 'year'}},
'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': 'lifeExp'}}}
})
But as you can see for yourself, there are a lot of details missing. So how can you peform a more complete figure introspection?

As of version 4.10, the plotly developers have introduced the awesome fig.full_figure_for_development() function which they talk about here. There you'll see that:
fig.full_figure_for_development() function will return a new go.Figure
object, prepopulated with the same values you provided, as well as all
the default values computed by Plotly.js, to allow you to learn more
about what attributes control every detail of your figure and how you
can customize them. This function is named “for development” because
it’s not necessary to use it to produce figures, but it can be really
handy to explore figures while you’re figuring out how to build them.
So building on the example in the question, the following snippet will produce an output of about 180 lines containing, among a plethora of other details, this part about the figure layout:
'margin': {'autoexpand': True, 'b': 80, 'l': 80, 'pad': 0, 'r': 80, 't': 100},
'modebar': {'activecolor': 'rgba(68, 68, 68, 0.7)',
'bgcolor': 'rgba(255, 255, 255, 0.5)',
'color': 'rgba(68, 68, 68, 0.3)',
'orientation': 'h'},
'newshape': {'drawdirection': 'diagonal',
'fillcolor': 'rgba(0,0,0,0)',
'fillrule': 'evenodd',
'layer': 'above',
'line': {'color': '#444', 'dash': 'solid', 'width': 4},
'opacity': 1},
'paper_bgcolor': 'white',
'plot_bgcolor': '#E5ECF6',
'separators': '.,',
'showlegend': False,
'spikedistance': 20,
And there you can also see the background color of the plot as 'plot_bgcolor': '#E5ECF6'. And you probably know that you can set the background color using to for example 'grey' using fig.update_layout(plot_bgcolor='grey'). But now you know how to get it as well:
# In:
fig.layout.plot_bgcolor
# Out:
'#E5ECF6'
And in knowing how to do this, you know how to get and set almost any attribute of a plotly figure. And it doesn't matter if you've built the figure using plotly.graph_objects or plotly.express

Related

Remove zero from ternary plot

I have the following plot and I want to remove the 0 in the origins.
import plotly.graph_objects as go
import plotly.express as px
fig = go.Figure(go.Scatterternary({
'mode': 'markers', 'a': [0.3],'b': [0.5], 'c': [0.6],
'marker': {'color': 'AliceBlue','size': 14,'line': {'width': 2} },
}))
fig.update_layout({
'ternary': {
'sum': 100,
'aaxis': {'nticks':1, 'ticks':""},
'baxis': {'nticks':1},
'caxis': {'nticks':1} }})
fig.update_traces( hovertemplate = "<b>CatA: %{a:.0f}<br>CatB: %{b:.0f}<br>CatC: %{c:.0f}<extra></extra>")
fig.show()
I am surprised because documentation here says the minimum of nticks is 1, not 0 (which does not work). How can I remove the 0 from the corners?
as u mentioned doc says ntick specifies the maximum number of ticks for the particular axis.
So its true, cannot be zero.
fig.update_ternaries(aaxis_showticklabels=False)
fig.update_ternaries(baxis_showticklabels=False)
fig.update_ternaries(caxis_showticklabels=False)

Plotly make marker overlay add_trace

I have the following Scatterternary plot below. Whenever I add_trace, the marker remains under it (so you cannot even hover it). How can I make the marker circle above the red area? [In implementation, I will have several areas and the marker may move around]
I tried adding fig.update_ternaries(aaxis_layer="above traces",baxis_layer="above traces", caxis_layer="above traces") as shown in the documentation without success. There is also another explanation for the boxplots with the same issue but I don't know how to implement it in this case.
import plotly.graph_objects as go
fig = go.Figure(go.Scatterternary({
'mode': 'markers', 'a': [0.3],'b': [0.5], 'c': [0.6],
'marker': {'color': 'AliceBlue','size': 14,'line': {'width': 2} },}))
fig.update_layout({
'ternary': {
'sum': 100,
'aaxis': {'nticks':1, 'ticks':""},
'baxis': {'nticks':1},
'caxis': {'nticks':1} }})
fig.add_trace(go.Scatterternary(name='RedArea',a=[0.1,0.1,0.6],b=[0.7,0.4,0.5],c=[0.2,0.6,0.8],mode='lines',opacity=0.35,fill='toself',
fillcolor='red'))
fig.update_traces( hovertemplate = "<b>CatA: %{a:.0f}<br>CatB: %{b:.0f}<br>CatC: %{c:.0f}<extra></extra>")
fig.show()
In this case, the markers can be displayed by swapping the drawing order. plotly does not provide the ability to control the drawing order, so changing the order of the code is the solution. However, it is not clear if this technique is possible for all graphs.
import plotly.graph_objects as go
fig = go.Figure()
fig.update_layout({
'ternary': {
'sum': 100,
'aaxis': {'nticks':1, 'ticks':""},
'baxis': {'nticks':1},
'caxis': {'nticks':1} }})
fig.add_trace(go.Scatterternary(
name='RedArea',
a=[0.1,0.1,0.6],
b=[0.7,0.4,0.5],
c=[0.2,0.6,0.8],
mode='lines',
opacity=0.35,
fill='toself',
fillcolor='red')
)
fig.add_trace(go.Scatterternary({
'mode': 'markers', 'a': [0.3],'b': [0.5], 'c': [0.6],
'marker': {'color': 'AliceBlue','size': 14,'line': {'width': 2} },}))
fig.update_traces( hovertemplate = "<b>CatA: %{a:.0f}<br>CatB: %{b:.0f}<br>CatC: %{c:.0f}<extra></extra>")
fig.show()

Creating chord diagram in Python

I want to create a Chord diagram for the following dataset where I have the first two columns as physical locations and a third column showing how many people visited both.
Place1 Place2 Count
US UK 200
FR US 450
UK US 200
NL FR 150
IT FR 500
I tried using Holoviews but I couldn't make it work
nodes = hv.Dataset(df, 'Place1', 'Place2')
chord = hv.Chord((df, nodes), ['Place1', 'Place2'], ['Count'])
graph = chord.select(selection_mode='nodes')
But I get the following error: DataError: None of the available storage backends were able to support the supplied data format.
How can I use this dataframe to create a Chord diagram?
A possible solution to this is the following. Remember that your shared data is not very large and the resulting chord diagram is pretty uggly.
import holoviews as hv
chords = chord.groupby(by=["Place1", "Place2"]).sum()[["Count"]].reset_index()
chords = chords.sort_values(by="Count", ascending=False)
CChord = hv.Chord(chords)
print(CChord)
hv.extension("bokeh")
CChord
The last part hv.extension("bokeh") is essential for the visualization. You could even add label using something like this:
cities = list(set(chords["Place1"].unique().tolist() + chords["Place2"].unique().tolist()))
cities_dataset = hv.Dataset(pd.DataFrame(cities, columns=["City"]))
The D3Blocks library can help create Chord charts and easily adjust the colors, weights, opacity, Font size. Let me illustrate it for your case:
Create your dataset:
import pandas as pd
import numpy as np
source=['US','FR','UK','NL','IT']
target=['UK','US','US','FR','FR']
weights=[200,450,200,150,500]
df = pd.DataFrame(data=np.c_[source, target, weights], columns=['source','target','weight'])
Now we can create the Chord chart:
pip install d3blocks
# Import library
from d3blocks import D3Blocks
# Initialize
d3 = D3Blocks(frame=False)
d3.chord(df, color='source', opacity='source', cmap='Set2')
We can also make adjustments:
# Edit any of the properties you want in the dataframe:
d3.node_properties
d3.node_properties.get('NL')['color']='#000000'
# {'US': {'id': 0, 'label': 'US', 'color': '#1f77b4', 'opacity': 0.8},
# 'UK': {'id': 1, 'label': 'UK', 'color': '#98df8a', 'opacity': 0.8},
# 'FR': {'id': 2, 'label': 'FR', 'color': '#8c564b', 'opacity': 0.8},
# 'NL': {'id': 3, 'label': 'NL', 'color': '#000000', 'opacity': 0.8},
# 'IT': {'id': 4, 'label': 'IT', 'color': '#9edae5', 'opacity': 0.8}}
d3.edge_properties
d3.edge_properties[('FR', 'US')]['color']='#000000'
# {('FR', 'US'): {'source': 'FR',
# 'target': 'US',
# 'weight': 450.0,
# 'opacity': 0.8,
# 'color': '#8c564b'},
# ('IT', 'FR'): {'source': 'IT',
# 'target': 'FR',
# 'weight': 500.0,
# 'opacity': 0.8,
# ...
# ...
# Plot again
d3.show()

Plotly: How to show legend in single-trace scatterplot with plotly express?

Sorry beforehand for the long post. I'm new to python and to plotly, so please bear with me.
I'm trying to make a scatterplot with a trendline to show me the legend of the plot including the regression parameters but for some reason I can't understand why px.scatter doesn't show me the legend of my trace. Here is my code
fig1 = px.scatter(data_frame = dataframe,
x="xdata",
y="ydata",
trendline = 'ols')
fig1.layout.showlegend = True
fig1.show()
This displays the scatterplot and the trendline, but no legend even when I tried to override it.
I used pio.write_json(fig1, "fig1.plotly") to export it to jupyterlab plotly chart studio and add manually the legend, but even though I enabled it, it won't show either in the chart studio.
I printed the variable with print(fig1) to see what's happening, this is (part of) the result
(Scatter({
'hovertemplate': '%co=%{x}<br>RPM=%{y}<extra></extra>',
'legendgroup': '',
'marker': {'color': '#636efa', 'symbol': 'circle'},
'mode': 'markers',
'name': '',
'showlegend': False,
'x': array([*** some x data ***]),
'xaxis': 'x',
'y': array([*** some y data ***]),
'yaxis': 'y'
}), Scatter({
'hovertemplate': ('<b>OLS trendline</b><br>RPM = ' ... ' <b>(trend)</b><extra></extra>'),
'legendgroup': '',
'marker': {'color': '#636efa', 'symbol': 'circle'},
'mode': 'lines',
'name': '',
'showlegend': False,
'x': array([*** some x data ***]),
'xaxis': 'x',
'y': array([ *** some y data ***]),
'yaxis': 'y'
}))
As we can see, creating a figure with px.scatter by default hides the legend when there's a single trace (I experimented adding a color property to px.scatter and it showed the legend), and searching the px.scatter documentation I can't find something related to override the legend setting.
I went back to the exported file (fig1.plotly.json) and manually changed the showlegend entries to True and then I could see the legend in the chart studio, but there has to be some way to do it directly from the command.
Here's the question:
Does anyone know a way to customize px.express graphic objects?
Another workaround I see is to use low level plotly graph object creation, but then I don't know how to add a trendline.
Thank you again for reading through all of this.
You must specify that you'd like to display a legend and provide a legend name like this:
fig['data'][0]['showlegend']=True
fig['data'][0]['name']='Sepal length'
Plot:
Complete code:
import plotly.express as px
df = px.data.iris() # iris is a pandas DataFrame
fig = px.scatter(df, x="sepal_width", y="sepal_length",
trendline='ols',
trendline_color_override='red')
fig['data'][0]['showlegend']=True
fig['data'][0]['name']='Sepal length'
fig.show()
Complete code:

Plotly: How to inspect the basic figure structure (version 4)

For older versions of plotly, for example in Jupyterlab, you could simply run figure to inspect the basics of your figure like this:
Ouput:
{'data': [{'marker': {'color': 'red', 'size': '10', 'symbol': 104},
'mode': 'markers+lines',
'name': '1st Trace',
'text': ['one', 'two', 'three'],
'type': 'scatter',
'x': [1, 2, 3],
'y': [4, 5, 6]}],
'layout': {'title': 'First Plot',
'xaxis': {'title': 'x1'},
'yaxis': {'title': 'x2'}}}
Code for versions prior to V4:
import plotly.plotly as py
import plotly.graph_objs as go
trace1 = go.Scatter(x=[1,2,3], y=[4,5,6], marker={'color': 'red', 'symbol': 104, 'size': "10"},
mode="markers+lines", text=["one","two","three"], name='1st Trace')
data=go.Data([trace1])
layout=go.Layout(title="First Plot", xaxis={'title':'x1'}, yaxis={'title':'x2'})
figure=go.Figure(data=data,layout=layout)
#py.iplot(figure, filename='pyguide_1')
figure
If you do the same thing now with a similar setup, the same approach will not produce the figure basics, but rather plot the figure itself:
Code:
import pandas as pd
import plotly.graph_objects as go
trace1 = go.Scatter(x=[1,2,3], y=[4,5,6], marker={'color': 'red', 'symbol': 104},
mode="markers+lines", text=["one","two","three"], name='1st Trace')
figure = go.Figure(data=trace1)
figure
Output:
In many ways this is similar to how you for example would build and plot a figure with ggplot in R. And since plotly is available for both R and Python I thinks this makes sense after all. But I'd really like to know how to access that basic setup.
What I've tried:
I think this change is due to the fact that figure is now a plotly.graph_objs._figure.Figure and used to be a dictionary(?). So figure['data'] and figure['layout'] are still dicts with necessary and interesting content:
Output from figure['data']
(Scatter({
'marker': {'color': 'red', 'symbol': 104},
'mode': 'markers+lines',
'name': '1st Trace',
'text': [one, two, three],
'x': [1, 2, 3],
'y': [4, 5, 6]
}),)
Output from figure['layout']
Layout({
'template': '...'
})
And of course options such as help(figure) and dir(figure) are helpful, but produces a very different output.
I just found out that 'forgetting' the brackets for figure.show() will give me exactly what I'm looking for. So with a setup similar to the code in the question and with plotly V4, simply running figure.show will give you this:
Output:
<bound method BaseFigure.show of Figure({
'data': [{'marker': {'color': 'red', 'symbol': 104},
'mode': 'markers+lines',
'name': '1st Trace',
'text': [one, two, three],
'type': 'scatter',
'x': [1, 2, 3],
'y': [4, 5, 6]}],
'layout': {'template': '...'}
})>
Code:
import pandas as pd
import plotly.graph_objects as go
trace1 = go.Scatter(x=[1,2,3], y=[4,5,6], marker={'color': 'red', 'symbol': 104},
mode="markers+lines", text=["one","two","three"], name='1st Trace')
figure = go.Figure(data=trace1)
figure.show

Categories

Resources