Draw multiple CSV files in a HTML page using Plotly - python

I want to draw multiple CSV files on an HTML page with fig = make_subplots(rows=.., cols=..).
df1 = pd.read_csv('first_input.csv')
fig1 = px.scatter(df, x="...", y="...", color="..")
df2 = pd.read_csv('first_input.csv')
fig2 = px.scatter(df, x="...", y="...", color="..")

Unfortunately plotly subplots do not directly support plotly.express figures as explained in the documentation here.
However, when you create a plotly.express figure using fig1 = px.scatter(df, x="...", y="...", color=".."), you are actually creating a figure where fig1.data is a tuple of go.Scatter traces. You can access each trace in fig1.data and add it to your subplots object.
If you have multiple px.scatter figures, you can iterate through them, and add each trace from px.scatter figure to your subplots object at the appropriate row and column. Then we can add the axes titles from each px.scatter figure to the subplots object layout.
I'll use the tips sample dataset to demonstrate:
import plotly.express as px
from plotly.subplots import make_subplots
df = px.data.tips()
fig1 = px.scatter(df, x="total_bill", y="tip", color="smoker")
fig2 = px.scatter(df, x="total_bill", y="tip", color="day")
fig_subplots = make_subplots(rows=2, cols=1)
for trace in fig1.data:
fig_subplots.add_trace(
trace,
row=1, col=1
)
for trace in fig2.data:
fig_subplots.add_trace(
trace,
row=2, col=1
)
## x and y axies in fig_subplots["layout"] are called xaxis, xaxis2, ..., yaxis, yaxis2, ...
## here we are making the assumption you are stacking your plots vertically
def modify_axis_titles(fig_subplots, px_fig, nrow):
xaxis_name, yaxis_name = f"xaxis{nrow}", f"yaxis{nrow}"
fig_subplots['layout'][xaxis_name]['title'] = px_fig.layout['xaxis']['title']
fig_subplots['layout'][yaxis_name]['title'] = px_fig.layout['yaxis']['title']
for px_fig, nrow in zip([fig1, fig2],[1,2]):
modify_axis_titles(fig_subplots, px_fig, nrow)
fig_subplots.show()

Related

Make subplots using plotly express with values coming from a dataframe

Assuming I have a toy model df which lists the model of the car and customer rating of one car showroom.
CustomerID Model Cust_rating
1 Corolla A
2 Corolla B
3 Forester A
4 GLC C
5 Xterra A
6 GLC A
Using plotly express, I created pie charts of percentage of cars by model and by Cust_rating, respectively as two separate graphs:
import plotly.express as px
px.pie(df,names='Model',title='Proportion Of each Model')
px.pie(df,names='Cust_rating',title='Proportion Of each Rating')
Now, I want to create subplots, and all the ways of doing it using the documentation are throwing up errors:
ValueError: Trace type 'pie' is not compatible with subplot type 'xy'
at grid position (1, 1)
This is what I tried:
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig = make_subplots(rows=1, cols=2)
fig.add_trace(go.Pie(values=df['Model']), row=1, col=1)
fig.add_trace(go.Pie(values=df['Cust_rating']), row=1, col=2)
fig.update_layout(height=700, showlegend=False)
fig.show()
A pie chart in a graph object requires a pair of labels and values. You must also specify the plot type in the subplot. See this for an example of a subplot type.
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig = make_subplots(rows=1, cols=2, subplot_titles=("Model", "Rating"), specs=[[{'type': 'domain'},{'type': 'domain'}]])
fig.add_trace(go.Pie(labels=df['Model'].value_counts().index,
values=df['Model'].value_counts(),
legendgroup='model',
legendgrouptitle=dict(text='Model'),
),
row=1, col=1)
fig.add_trace(go.Pie(labels=df['Cust_rating'].value_counts().index,
values=df['Cust_rating'].value_counts(),
legendgroup='rating',
legendgrouptitle=dict(text='Rating')),
row=1, col=2)
fig.update_layout(height=400, width=600, showlegend=True)
fig.show()
Use matplotlib and seaborn:
import matplotlib.pyplot as plt
import seaborn as sns
if you want two and more plot use
fig, ax = plt.subplots(2,2, figsize=(20, 15))
And use ax=ax[0,1], row and col,
sns.boxplot(x = 'bedrooms', y = 'price', data = dataset_df, ax=ax[0,1])
sns.boxplot(x = 'floor, y = 'price', data = dataset_df, ax=ax[0,2])

Plotly Express how to show legend?

I have code below as, but I cant seem to show legend even by trying a few things manually by showing legend parameter, is there anyway to show legend? Thanks!
subfig = make_subplots(specs=[[{"secondary_y": True}]])
# create two independent figures with px.line each containing data from multiple columns
fig = px.line(dfa, y="revenue", template=template_style,markers=True)
fig2 = px.line(dfa, y="pdt_chg", template=template_style,markers=True)
fig2.update_traces(yaxis="y2")
subfig.add_traces(fig.data + fig2.data)
subfig.layout.title="Sales"
subfig.layout.xaxis.title="Year"
subfig.layout.yaxis.title="$"
subfig.layout.yaxis2.title="%"
subfig.update_layout(
xaxis = dict(
tickmode = 'linear',
tick0 = 0,
dtick = 0),title_x= 0.47,template=template_style)
subfig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
subfig.show()
When px.line is prompted to produce a figure with a single line, the default behavior is to drop the legend. This is presumably intended to reduce redundant information since it's easy to include the data description in the main title and/or the axis title. In order to override this, just include:
fig.for_each_trace(lambda t: t.update(name = <a name>))
fig.update_traces(showlegend = True)
In your case, you'll have to do so for both your initial figures before they are joined in subfig. Here's and exampe with the gapminder dataset:
Plot:
Complete code:
import plotly.express as px
from plotly.subplots import make_subplots
subfig = make_subplots(specs=[[{"secondary_y": True}]])
df1 = px.data.gapminder().query("country=='Canada'")
fig1 = px.line(df1, x="year", y="lifeExp", title='Life expectancy in Canada')
fig1.for_each_trace(lambda t: t.update(name = 'Canada'))
fig1.update_traces(showlegend = True)
df2 = px.data.gapminder().query("country=='Germany'")
fig2 = px.line(df2, x="year", y="lifeExp", title='Life expectancy in Germany')
fig2.for_each_trace(lambda t: t.update(name = 'Germany'))
fig2.update_traces(showlegend = True)
subfig.add_traces(fig1.data + fig2.data)
subfig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
subfig.show()

How to get bar colors of multiple traces from bar chart?

I created a bar chart with multiple traces using a loop. The colors of each trace are assigned by plotly automatically. Now chart is done, how to get colors of all traces? I needed to assign these same colors to another scatter plot inside subplots to make color consistent. Thank you so much for your help.
for i in range (10):
fig.add_trace(
go.Bar(
x=weights_df_best.index,
y=weights_df_best[col].values,
name = col,
text=col,
hoverinfo='text',
legendgroup = '1',
offsetgroup=0,
),
row=1,
col=1,
)
If you'd like to put the colors in a list after you've produced a figure, just run:
colors = []
fig.for_each_trace(lambda t: colors.append(t.marker.color))
If you use that approach in the complete snippet below, you'll get
['#636efa', '#EF553B', '#00cc96']
Plot
Complete code:
import plotly.express as px
df = px.data.medals_long()
fig = px.bar(df, x="medal", y="count", color="nation", text_auto=True)
colors = []
fig.for_each_trace(lambda t: colors.append(t.marker.color))
colors

How to format plotly legend when using marker color?

I want to follow up on this post: Plotly: How to colorcode plotly graph objects bar chart using Python?.
When using plotly express, and specifying 'color', the legend is correctly produced as seen in the post by vestland.
This is my plotly express code:
data = {'x_data': np.random.random_sample((5,)),
'y_data': ['A', 'B', 'C', 'D', 'E'],
'c_data': np.random.randint(1, 100, size=5)
}
df = pd.DataFrame(data=data)
fig = px.bar(df,
x='x_data',
y='y_data',
orientation='h',
color='c_data',
color_continuous_scale='YlOrRd'
)
fig.show()
But when using go.Bar, the legend is incorrectly displayed as illustrated here:
This is my code using graph objects:
bar_trace = go.Bar(name='bar_trace',
x=df['x_data'],
y=df['y_data'],
marker={'color': df['c_data'], 'colorscale': 'YlOrRd'},
orientation='h'
)
layout = go.Layout(showlegend=True)
fig = go.FigureWidget(data=[bar_trace], layout=layout)
fig.show()
I'm learning how to use FigureWidget and it seems it can't use plotly express so I have to learn how to use graph objects to plot. How do I link the legend to the data such that it works like the plotly express example in vestland's post.
This really comes down to understanding what a high level API (plotly express) does. When you specify color in px if it is categorical it creates a trace per value of categorical. Hence the below two ways of creating a figure are mostly equivalent. The legend shows an item for each trace, not for each color.
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
df = pd.DataFrame({"x":np.linspace(0,10,10), "y":np.linspace(5,15,10), "color":np.random.choice(list("ABCD"),10)})
px.bar(df, x="x", y="y", color="color", orientation="h").show()
fig = go.Figure()
for g in df.groupby("color"):
fig.add_trace(go.Bar(x=g[1]["x"], y=g[1]["y"], name=g[0], orientation="h"))
fig
supplementary based on comments
you do not have to use graph objects if you are using FigureWidget() as demonstrated by second figure, create with plotly express and then generate FigureWidget()
for continuous data normal pattern is to use a single trace and a colorbar (also demonstrated in second figure). However if you want a discrete legend, create a trace per value in c_data and use https://plotly.com/python-api-reference/generated/plotly.colors.html sample_colorscale()
import plotly.express as px
import plotly.colors
import plotly.graph_objects as go
import numpy as np
import pandas as pd
# simulate data frame...
df = pd.DataFrame(
{
"x_data": np.linspace(0, 10, 10),
"y_data": np.linspace(5, 15, 10),
"c_data": np.random.randint(0, 4, 10),
}
)
# build a trace per value in c_data using graph objects ... correct legend !!??
bar_traces = [
go.Bar(
name="bar_trace",
x=d["x_data"],
y=d["y_data"],
marker={
"color": plotly.colors.sample_colorscale(
"YlOrRd",
d["c_data"] / df["c_data"].max(),
)
},
orientation="h",
)
for c, d in df.groupby("c_data")
]
layout = go.Layout(showlegend=True)
fig = go.FigureWidget(data=bar_traces, layout=layout)
fig.show()
fig = px.bar(
df,
x="x_data",
y="y_data",
color="c_data",
orientation="h",
color_continuous_scale="YlOrRd",
)
fig = go.FigureWidget(data=fig.data, layout=fig.layout)
fig.show()

How do I combine two plots into one figure using Plotly?

I have 2 csv files, my codes are as below.
df = pd.read_csv("test.csv",
sep='\t',skiprows=range(9),names=['A', 'B', 'C','D'])
df2 = pd.read_csv("LoadMatch_Limit.csv",skiprows=range(1),names=['X','Y'])
fig = px.line([df,df2], x=['A','X'] , y=['D','Y'])
I would like my line chart, x-axis to take from (columns 'A' and 'X') and my y-axis to take from (columns 'D' and 'Y').
Is there anyway I can plot these 2 charts as one figure?
You could create the two plots and combine them with plotly graph objects
import plotly.express as px
import plotly.graph_objects as go
fig1 = px.line(df, x='A', y='D')
fig2 = px.line(df2, x='X', y='Y')
fig = go.Figure(data = fig1.data + fig2.data)
fig.show()
Plotly.offline has no attribute line. You need to use the graph object to plot two graphs in a single figure. A simple example is shown below(run the code below and see the output graph)
import numpy as np
import pandas as pd
import plotly.offline as py
import plotly.graph_objs as go
from plotly import tools
df1 = pd.DataFrame({"X":np.linspace(0,30,10), "Y":np.random.rand(10)})
df2 = pd.DataFrame({"A":np.linspace(0,40,10), "B":np.random.rand(10)})
# plotting the graphs...
# 'rgb(128, 0, 128)'
# color=sns.color_palette()
def scatter_chart(x, y, color, name):
trace = go.Scatter(
x=x.values,
y=y.values,
name=name,
marker=dict(
color=color,
line=dict(
color=color,
width=1)
),
)
return trace
trace1 = scatter_chart(df2["A"], df2["B"], 'rgb(128, 0, 128)', "df2")
trace2 = scatter_chart(df1["X"], df1["Y"], 'rgba(50, 171, 96, 0.6)', "df1")
fig = tools.make_subplots(rows=1,cols=1, vertical_spacing=0.5)
fig.add_trace(trace1)
fig.add_trace(trace2)
fig.update_layout(
title="df2 and df1 plot",
height=600,
width=600,
# annotations=annotations,
xaxis=dict(tickangle=-45),
legend=dict(x=0.029, y=1.038, font_size=10),
margin=dict(l=100, r=20, t=70, b=70),
paper_bgcolor='rgb(248, 248, 255)',
plot_bgcolor='rgb(248, 248, 255)',)
py.iplot(fig, filename='pageviews_plots_4')

Categories