Related
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)
I'm plotting datasets with plotly express as sunburst charts.
One thing I'm trying to achieve is the possibility to select the values to be plotted so that the plot gets updated if the values change meaning that a different column in the dataframe is selected.
I've created an example based on this sunburst example in the official docs
https://plotly.com/python/sunburst-charts/#sunburst-of-a-rectangular-dataframe-with-plotlyexpress
There the column 'total_bill' is selected for plotting and that works. I can recreate the plot in that example.
Now I would like to use updatemenus to switch that to the 'tip' column that also holds floats and should be usable.
The example code I've tried:
import plotly.express as px
df = px.data.tips()
updatemenus = [{'buttons': [{'method': 'update',
'label': 'total_bill',
'args': [{'values': 'total_bill'}]
},
{'method': 'update',
'label': 'tip',
'args': [{'values': 'tip'}]
}],
'direction': 'down',
'showactive': True,}]
fig = px.sunburst(df, path=['day', 'time', 'sex'], values='total_bill')
fig.update_layout(updatemenus=updatemenus)
fig.show()
Now this will successfully plot the same plot as in the example, but when I select back and forth between the two updatemenu options, it doesn't behave properly.
I've also tried to use Series everywhere, but the results is the same.
I've also looked at this example, which has a similar focus
Plotly: How to select graph source using dropdown?
but the answers there didn't solve my problem either, since the sunburst in some way seems to behave differently from the scatter plot?
Any idea how to get this working?
similar to solution you arrived at. Use Plotly Express to build all the figures, collect into a dict
menu can now be built with dict comprehension
import plotly.express as px
df = px.data.tips()
# construct figures for all columns that can provide values
figs = {
c: px.sunburst(df, path=["day", "time", "sex"], values=c)
for c in ["total_bill", "tip"]
}
# choose a column that becomes the figure
fig = figs["total_bill"]
# now build menus, that use parameters that have been pre-built using plotly express
fig.update_layout(
updatemenus=[
{
"buttons": [
{
"label": c,
"method": "restyle",
"args": [
{
"values": [figs[c].data[0].values],
"hovertemplate": figs[c].data[0].hovertemplate,
}
],
}
for c in figs.keys()
]
}
]
)
Ok, I found one solution that works, but maybe someone could point me towards a "cleaner" solution, if possible.
I stumbled across this question that is actually unrelated:
Plotly: How to create sunburst subplot using graph_objects?
There, one solution was to save the figure data of a plotly express figure and reuse it in a graph objects figure.
This gave me an idea, that I could maybe save the data of each figure and then reuse (and update/modify) it in a third figure.
And, as it turns out, this works!
So here is the working example:
import plotly.express as px
df = px.data.tips()
# create two figures based on the same data, but with different values
fig1 = px.sunburst(df, path=['day', 'time', 'sex'], values='total_bill')
fig2 = px.sunburst(df, path=['day', 'time', 'sex'], values='tip')
# save the data of each figure so we can reuse that later on
ids1 = fig1['data'][0]['ids']
labels1 = fig1['data'][0]['labels']
parents1 = fig1['data'][0]['parents']
values1 = fig1['data'][0]['values']
ids2 = fig2['data'][0]['ids']
labels2 = fig2['data'][0]['labels']
parents2 = fig2['data'][0]['parents']
values2 = fig2['data'][0]['values']
# create updatemenu dict that changes the figure contents
updatemenus = [{'buttons': [{'method': 'update',
'label': 'total_bill',
'args': [{
'names': [labels1],
'parents': [parents1],
'ids': [ids1],
'values': [values1]
}]
},
{'method': 'update',
'label': 'tip',
'args': [{
'names': [labels2],
'parents': [parents2],
'ids': [ids2],
'values': [values2]
}]
}],
'direction': 'down',
'showactive': True}]
# create the actual figure to be shown and modified
fig = px.sunburst(values=values1, parents=parents1, ids=ids1, names=labels1, branchvalues='total')
fig.update_layout(updatemenus=updatemenus)
fig.show()
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()
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
I'm trying to embed multiple, selectable graphs in a single figure using Plotly, using a dropdown figure. I followed the dropdown example from Plotly, but they only show how to change graph characteristics (like visible, or type), not the underlying data. In my situation, I have a static X-axis and want to change the Y-values. Here's a minimal working example that can be run in a jupyter notebook:
import plotly
from plotly import graph_objs as go, offline as po, tools
po.init_notebook_mode()
import numpy as np
import json
x = list(np.linspace(-np.pi, np.pi, 100))
values_1 = list(np.sin(x))
values_2 = list(np.tan(x))
line = go.Scatter(
x=x,
y=values_1
)
updatemenus = [
{
'buttons': [
{
'method': 'restyle',
'label': 'Val 1',
'args': [
{'y': json.dumps(values_1)},
]
},
{
'method': 'restyle',
'label': 'Val 2',
'args': [
{'y': json.dumps(values_2)},
]
}
],
'direction': 'down',
'showactive': True,
}
]
layout = go.Layout(
updatemenus=updatemenus,
)
figure = go.Figure(data=[line], layout=layout)
po.iplot(figure)
However, while the approach seems to work like advertised for general graph attributes (like 'visible'), when I use 'y', it produces a straight line, where y goes from 0 to len(y), instead of the actual data I gave it. Here are images of the initial render, and then what happens when I select the dropdown item for the Tan(X) graph, then go back to the Sin(X):
How do I embed the data for multiple graphs into a single figure so that the user can select which one they want to view?
Updated answer using graph_objects:
As of version 4, you don't have to worry about offline versus online functionality. So drop the from plotly import graph_objs as go, offline as po and po.init_notebook_mode(), and just use import plotly.graph_objects as go. I've updated my original answer with a complete code snippet that shows the whole approach with multiple traces using plotly.graph_objects at the end. The solution to the question as it still stands will still be the same, namely:
'y' in updatemenus does not take a single list as an argument, but rather a list of lists like in 'y' = [values_1] where values_1 is a list in itself. So just replace your lines
{'y': json.dumps(values_1)}, and {'y': json.dumps(values_2)},
with
{'y': [values_1]}, and {'y': [values_2]},
to get these plots for the different options Val 1 and Val 2:
Some Details:
Values_1 is, unsurprisingly, a list of length 100 where each element is of type numpy.float. Replacing json.dumps(values_1) with values_1, and json.dumps(values_2) with values_2 will render the same plots as in your question. The reason why these plots are just straight lines, seems to be that it's the length of your lists that are being plotted, and not the values contained in that list. Or something to that effect.
Setting 'y' = values_1 is the same thing as assigning a single list to 'y'. But 'y' in updatemenus does not take a single list as an argument, but rather a list of lists like in 'y' = [values_1]. Why? Because you might want to plot multiple lists in the same figure like 'y' = [values_1, values_1b]. Have a look:
Plot for dropdown option Var 1:
Plot for dropdown option Var 2
Complete original code:
import plotly
from plotly import graph_objs as go, offline as po, tools
po.init_notebook_mode()
import numpy as np
import json
x = list(np.linspace(-np.pi, np.pi, 100))
values_1 = list(np.sin(x))
values_1b = [elem*-1 for elem in values_1]
values_2 = list(np.tan(x))
values_2b = [elem*-1 for elem in values_2]
line = go.Scatter(
x=x,
y=values_1
)
line2 = go.Scatter(
x=x,
y=values_1b
)
updatemenus = [
{
'buttons': [
{
'method': 'restyle',
'label': 'Val 1',
'args': [
{'y': [values_1, values_1b]},
]
},
{
'method': 'restyle',
'label': 'Val 2',
'args': [
{'y': [values_2, values_2b]},
]
}
],
'direction': 'down',
'showactive': True,
}
]
layout = go.Layout(
updatemenus=updatemenus,
)
figure = go.Figure(data=[line, line2], layout=layout)
po.iplot(figure)
Complete updated code:
# imports
import plotly.graph_objects as go
import numpy as np
# data
x = list(np.linspace(-np.pi, np.pi, 100))
values_1 = list(np.sin(x))
values_1b = [elem*-1 for elem in values_1]
values_2 = list(np.tan(x))
values_2b = [elem*-1 for elem in values_2]
# plotly setup]
fig = go.Figure()
# Add one ore more traces
fig.add_traces(go.Scatter(x=x, y=values_1))
fig.add_traces(go.Scatter(x=x, y=values_1b))
# construct menus
updatemenus = [{'buttons': [{'method': 'update',
'label': 'Val 1',
'args': [{'y': [values_1, values_1b]},]
},
{'method': 'update',
'label': 'Val 2',
'args': [{'y': [values_2, values_2b]},]}],
'direction': 'down',
'showactive': True,}]
# update layout with buttons, and show the figure
fig.update_layout(updatemenus=updatemenus)
fig.show()
Plot with version 4 default layout: