Can you alter a subplot title location in plotly? - python

When adding a subplot_title to my subplots in plotly my title overlaps with my axes. Can I alter the location of the subplot title like matplotlib's ax.set_title('title', y=1.5)?
Here is my plot, as you can see danceability overlaps:
Here is my code so far:
from plotly.subplots import make_subplots
categories = ['key', 'acousticness', 'danceability', 'energy', 'loudness',
'speechiness', 'tempo','key']
fig = make_subplots(rows=1, cols=2, specs=[[{"type":"polar"}, {"type":"polar"}]],
subplot_titles=('Clustering Into 8 Playlists', 'Clustering Into 11 Playlists'))
fig.add_trace(go.Scatterpolar(
r=x,
theta=categories,
fill='toself',
name='Cluster 1',
visible='legendonly'
), row=1, col=1)
fig.add_trace(go.Scatterpolar(
r=y,
theta=categories,
fill='toself',
name='Cluster 2',
visible='legendonly'
), row=1, col=2)
fig.update_layout(height=600, width=1400, title_text='Radar Plot of All Clusters (Fig.4)')
fig.show()

I gave a partial code answer, but you can do it with fig['layout']['annotations']. From the official reference here.I also referred to SO's answer.
fig.update_layout(title_text='Radar Plot of All Clusters (Fig.4)') # height=600, width=1400,
for annotation in fig['layout']['annotations']:
annotation['yanchor']='bottom'
annotation['y']=1.1
annotation['yref']='paper'
fig.show()

Related

easiest way to put several Python Plotly Express figures on one html file

I want to keep the figures in the exact same way, for example, having different data source, subplot title and respective legends near EACH figure.
currently the code is sth. like
fig1 = px.line(df_crude_spot_long, x="Date", y="$/bbl", color='type', title='Benchmark Crude Spot Prices', color_discrete_sequence=px.colors.qualitative.Bold)
fig1.update_layout(
xaxis_title="",
title={
# 'text': "Plot Title",
# 'y':0.9,
'x':0.5},
legend_title="Benchmark",
font=dict(
family="Courier New, monospace",
size=40,
color="navy"),
legend=dict(
yanchor="top",
y=0.99,
xanchor="left",
x=0.01
)
)
fig2 = px.line(df_crude_futures, x="contract month", y='Price', color='futures', title='Latest Crude Oil Futures', color_discrete_sequence=px.colors.qualitative.Bold)
fig2.update_layout(
title={
# 'text': "Plot Title",
# 'y':0.9,
'x':0.5},
legend_title="Futures",
font=dict(
family="Courier New, monospace",
size=40,
color="navy"),
legend=dict(
yanchor="top",
y=0.99,
xanchor="left",
x=0.8
)
)
fig3
fig4
....
As you can see, the data source for different figures are not from the same dataframe.
I tried the 2nd approach in this post, by combining make_subplots and plotly express with code like this
Is it possible to create a subplot with Plotly Express?
fig = make_subplots(
rows=2, cols=2,
subplot_titles=("BenchmarkPrices", "Latest Oil Futures", "Bunker Prices", "Fuel Futures"))
for d in fig1.data:
fig.add_trace((go.Scatter(x=d['x'], y=d['y'], name = d['name'])), row=1, col=1)
for d in fig2.data:
fig.add_trace((go.Scatter(x=d['x'], y=d['y'], name = d['name'])), row=2, col=1)
for d in fig3.data:
fig.add_trace((go.Scatter(x=d['x'], y=d['y'], name = d['name'])), row=2, col=1)
for d in fig4.data:
fig.add_trace((go.Scatter(x=d['x'], y=d['y'], name = d['name'])), row=2, col=2)
but the result has some of the figures not shown properly and all the legends put together on the right side.
I mentioned Html file in the title because I generally save my figure like below
offline.plot({'data':fig},filename='charts.html',auto_open=False)
Update 1
The comment section suggested the method in this post
Plotly saving multiple plots into a single html
it puts several figures under 1 html but doesn't solve my problem because 1.I need to produce a 2 x 4 charts(2 charts per row and 4 rows in total), with this way it only put 1 chart per row. 2. when I download png from the html, it only shows the 1st figure, even on the html we see the 4

Plotting Python Plotly ECDF subplots with marginal plots

I would like to plot several plots in a subplot, specifically ecdf plots which are found under plotly express. Unfortunately I cannot get it to work because it appears subplot expects a graph objects plotly plot. The error says it receives invalid data, specifically:
"Invalid element(s) received for the 'data' property"
Obviously that means that of the following, ecdf is not included:
['bar', 'barpolar', 'box', 'candlestick',
'carpet', 'choropleth', 'choroplethmapbox',
'cone', 'contour', 'contourcarpet',
'densitymapbox', 'funnel', 'funnelarea',
'heatmap', 'heatmapgl', 'histogram',
'histogram2d', 'histogram2dcontour', 'icicle',
'image', 'indicator', 'isosurface', 'mesh3d',
'ohlc', 'parcats', 'parcoords', 'pie',
'pointcloud', 'sankey', 'scatter',
'scatter3d', 'scattercarpet', 'scattergeo',
'scattergl', 'scattermapbox', 'scatterpolar',
'scatterpolargl', 'scatterternary', 'splom',
'streamtube', 'sunburst', 'surface', 'table',
'treemap', 'violin', 'volume', 'waterfall']
Great, now, is there a work around that will allow me to plot a few of these guys next to each other?
Here's the code for a simple ecdf plot as from the documentation.
import plotly.express as px
df = px.data.tips()
fig = px.ecdf(df, x="total_bill", color="sex", markers=True, lines=False, marginal="histogram")
fig.show()
If I wanted to plot two of this same plot together for example, I would expect the following code (basically copied from the documentation) to work, probably, (if it accepted ecdf) but I cannot get it to work for the aforementioned reasons.
from plotly.subplots import make_subplots
import plotly.graph_objects as go
df = px.data.tips()
fig = make_subplots(rows=1, cols=2)
fig.add_trace(
px.ecdf(df, x="total_bill", color="sex", markers=True, lines=False, marginal="histogram"),
row=1, col=1
)
fig.add_trace(
px.ecdf(df, x="total_bill", color="sex", markers=True, lines=False, marginal="histogram"),
row=1, col=2
)
fig.update_layout(height=600, width=800, title_text="Side By Side Subplots")
fig.show()
Is there a work around for px.ecdf subplots?
Thank you in advance!
ECDF plots follow the Plotly Express pattern of having face_col parameter https://plotly.com/python-api-reference/generated/plotly.express.ecdf.html
simplest way to achieve this is to prepare the dataframe for this capability. In this example have created two copies of the data with each copy having a column for this capability
alternative is far more complex, both make_subplots() and px.ecdf() create multiple x and y axis. It would be necessary to manage all of these yourself
import plotly.express as px
import pandas as pd
df = px.data.tips()
df = pd.concat([px.data.tips().assign(col=c) for c in ["left","right"] ])
fig = px.ecdf(df, x="total_bill", color="sex", markers=True, lines=False, marginal="histogram", facet_col="col")
fig.update_layout(height=600, width=800, title_text="Side By Side Subplots")

Plotly subplots with nested shared xaxis

I want to generate a plotly plot with two subplots with a shared nested xaxis. Unfortunately I have the problem that
either the separators for the nested xaxis are also shown in the first plot
or the vertical grid lines of the two subplots don't match.
How can I either remove the separators in case 1 or match the grids between the subplots in case 2?
Case 1: Some weird long group separators in the row=1, col=1 subplot
Case 2: The vertical grid lines of both plots don't match
The only difference between both plots is that I commented out the x=xlabels, line for df_one in the following MWE:
# MWE
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# generate data
idx_one = ["A", "B"]
idx_two = ["long text A", "long text B"]
df_one = pd.DataFrame(
data=np.random.rand(4,1),
columns=["df_one"],
index=pd.MultiIndex.from_product([idx_one, idx_two]),
)
df_two = pd.DataFrame(
data=np.random.rand(4,1),
columns=["df_two"],
index=pd.MultiIndex.from_product([idx_one, idx_two]),
)
xlabels = [
df_one.index.get_level_values(0).tolist(),
df_one.index.get_level_values(1).tolist(),
]
# plotly
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, y_title="some shared y-title")
fig.append_trace(
go.Bar(
y=df_one["df_one"],
x=xlabels,
name="df_one",
showlegend=False,
text=df_one["df_one"],
textposition='auto',
textangle=0,
texttemplate='%{text:+.1f}',
),
row=1, col=1,
)
fig.append_trace(
go.Bar(
y=df_two["df_two"],
x=xlabels,
name="df_two",
showlegend=False,
text=df_two["df_two"],
textposition='auto',
textangle=0,
texttemplate='%{text:+.1f}',
),
row=2, col=1,
)
fig.show()
Okay, I found a bit unintuitive answer by setting the x values in the first bar plot and offsetting the bars with the offset option and later changing the range with update_xaxes.
Result:
Solution:
# MWE
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# generate data
idx_one = ["A", "B"]
idx_two = ["long text A", "long text B"]
df_one = pd.DataFrame(
data=np.random.rand(4,1),
columns=["df_one"],
index=pd.MultiIndex.from_product([idx_one, idx_two]),
)
df_two = pd.DataFrame(
data=np.random.rand(4,1),
columns=["df_two"],
index=pd.MultiIndex.from_product([idx_one, idx_two]),
)
xlabels = [
df_one.index.get_level_values(0).tolist(),
df_one.index.get_level_values(1).tolist(),
]
# plotly
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, y_title="some shared y-title")
fig.append_trace(
go.Bar(
y=df_one["df_one"],
x=[*range(len(df_one["df_one"]))],
name="df_one",
showlegend=False,
text=df_one["df_one"],
textposition='auto',
textangle=0,
texttemplate='%{text:+.1f}',
offset=-0.9,
),
row=1, col=1,
)
fig.append_trace(
go.Bar(
y=df_two["df_two"],
x=xlabels,
name="df_two",
showlegend=False,
text=df_two["df_two"],
textposition='auto',
textangle=0,
texttemplate='%{text:+.1f}',
),
row=2, col=1,
)
fig.update_xaxes(
row=1, col=1,
tickmode = "array",
tickvals = [*range(len(df_one["df_one"]))],
range=[
-1,
len(df_one["df_one"])-1,
]
)
fig.show()

Adding a secondary axis in Plotly Python

I'm working with a Dash graph object and I'm fairly new to it. I'm attempting to pass in a graph that has 2 scatter charts and a bar chart on the same figure but I'd like the bar chart (green) to be on it's own secondary y axis so it looks better than it does here:
Now from what I understand about Dash, I have to pass a go.Figure() object so I have a function which defines the data and the layout. I saw in the plotly documentation that you can use plotly express add secondary axis but I'm not sure how to do that within my frame work here. Any help would be greatly appreciated!
Here's my code:
def update_running_graph(n_intervals):
df = pd.read_csv(filename)
trace1 = go.Scatter(x=df['Timestamp'],
y=df['CLE'],
name='Crude',
mode='lines+markers')
trace2 = go.Scatter(x=df['Timestamp'],
y=df['y_pred'],
name='Model',
mode='lines+markers')
trace3 = go.Bar(x=df['Timestamp'],
y=df['ModelDiff'],
name='Diff',
)
data = [trace1, trace2,trace3]
layout = go.Layout(title='CLE vs Model')
return go.Figure(data=data, layout=layout)
To add a secondary y-axis in dash you could do the following:
def update_running_graph(n_intervals):
df = pd.read_csv(filename)
trace1 = go.Scatter(x=df['Timestamp'],
y=df['CLE'],
name='Crude',
mode='lines+markers',
yaxis='y1')
trace2 = go.Scatter(x=df['Timestamp'],
y=df['y_pred'],
name='Model',
mode='lines+markers',
yaxis='y1')
trace3 = go.Bar(x=df['Timestamp'],
y=df['ModelDiff'],
name='Diff',
yaxis='y2'
)
data = [trace1, trace2,trace3]
layout = go.Layout(title='CLE vs Model',
yaxis=dict(title='Crude and Model'),
yaxis2=dict(title='Moddel Difference',
overlaying='y',
side='right'))
return go.Figure(data=data, layout=layout)
you can add more y-axis they always need to have the form of yi with i the i-th axis. Then in the layout you can specify the layout of the i-th axis with yaxisi=dict(...).
This documentation page should be of use. Just modify to fit your code, since trace1 and trace2 appear to be on the same scale, just set trace3 to the secondary axis scale and you should be set. Below is an example with just only 2 but adding a third should not be too difficult.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add traces
fig.add_trace(
go.Scatter(x=[1, 2, 3], y=[40, 50, 60], name="yaxis data"),
secondary_y=False,
)
fig.add_trace(
go.Scatter(x=[2, 3, 4], y=[4, 5, 6], name="yaxis2 data"),
secondary_y=True,
)
# Add figure title
fig.update_layout(
title_text="Double Y Axis Example"
)
# Set x-axis title
fig.update_xaxes(title_text="xaxis title")
# Set y-axes titles
fig.update_yaxes(title_text="<b>primary</b> yaxis title", secondary_y=False)
fig.update_yaxes(title_text="<b>secondary</b> yaxis title", secondary_y=True)
fig.show()
Cheers!

How to change annotation orientation in plotly?

Say I have the following figure:
import numpy as np
import plotly.graph_objs as go
z=np.random.randint(1000, 11000, size=20)
trace=dict(type='scatter',
x=3+np.random.rand(20),
y=-2+3*np.random.rand(20),
mode='markers',
marker=dict(color= z,
colorscale='RdBu', size=14, colorbar=dict(thickness=20)))
axis_style=dict(zeroline=False, showline=True, mirror=True)
layout=dict(width=550, height=500,
xaxis=axis_style,
yaxis=axis_style,
hovermode='closest',
)
fig=go.FigureWidget(data=[trace], layout=layout)
fig
Now say I want the colorbar to have a title. Since plotly does not currently have a direct way to do that, if I understand correctly, I am doing this through annotations as shown here:
layout.update(
annotations=[dict(
x=1.12,
y=1.05,
align="right",
valign="top",
text='Colorbar Title',
showarrow=False,
xref="paper",
yref="paper",
xanchor="center",
yanchor="top"
)
]
)
As we can see, the colorbar title appears:
fig=go.FigureWidget(data=[trace], layout=layout)
fig
However, now say I want to place the colorbar title sideways, along the colorbar, like so:
How do I do this?
Parameter textangle do it for you. Example from plotly docs. Setting textangle=-90 rotate annotation how you want.
Code:
# import necessaries libraries
import numpy as np
import plotly.offline as py
import plotly.graph_objs as go
z = np.random.randint(1000, 11000, size=20)
# Create a trace
trace = dict(type='scatter',
x=3+np.random.rand(20),
y=-2+3*np.random.rand(20),
mode='markers',
marker=dict(color=z, colorscale='RdBu',
size=14, colorbar=dict(thickness=20)))
# Define axis_style
axis_style = dict(zeroline=False, showline=True, mirror=True)
# Specify layout style
layout = dict(width=550, height=500,
xaxis=axis_style,
yaxis=axis_style,
hovermode='closest',
)
# Update layout with annotation
layout.update(
annotations=[dict(
# Don't specify y position,because yanchor="middle" do it for you
x=1.22,
align="right",
valign="top",
text='Colorbar Title',
showarrow=False,
xref="paper",
yref="paper",
xanchor="right",
yanchor="middle",
# Parameter textangle allow you to rotate annotation how you want
textangle=-90
)
]
)
# Create FigureWidget
fig = go.FigureWidget(data=[trace], layout=layout)
# Plot fig
py.plot(fig)
Output:
For anyone who may have found this question now, there is (now?) a very easy way of adding a title to a colorbar, and to make it oriented sideways along the colorbar using the colorbar title property.
In this case, we could just update trace like so:
# Create a trace
trace = dict(type='scatter',
x=3+np.random.rand(20),
y=-2+3*np.random.rand(20),
mode='markers',
marker=dict(color=z, colorscale='RdBu', size=14,
colorbar=dict(thickness=20,
title=dict(text="Colorbar title", orient="right"))))
Documentation here: https://plotly.com/python/reference/scatter/#scatter-marker-colorbar

Categories

Resources