How to create subplots with Plotly? - python

I had created the subplots in the seaborn. but not able to create same to same plots using plotly.
y1 = [-51.04464896560272, -50.891166658544364, -50.82896235500738,-47.93693115514636, -48.93693115514636, -50.2337317810911, -50.580211311328924, -49.63778008455918, -50.55143905012876, -47.18028476096273, -49.45950323726963, -52.759450409024325, -46.94239220924591, -49.34719404199133, -48.592737888881025, -50.39057938285388,-50.33666292445022,-49.689436282011854,-49.86872483079463, -49.47463251418676,-51.542982170986264, -50.650742675143576, -46.498494705109124, -69.232249295994,-65.83208484345344,-56.624359510655715, -64.65663405050996, -63.385051075806444, -61.4890501679952, -64.5215014815885]
y2 = [-49.22994660618851, -49.93693115514636,-47.48816812312157, -47.642008385846054, -49.24556971152835, -49.003594660143946, -49.92614593515235, -48.79589239042106, -49.90953636053393, -49.84547212502676, -48.83995760926475, -50.399185030856515, -47.98870212151289, -49.68206139796429, -48.82322978146867, -49.76209077328067, -48.3489893943433, -49.7807786904155, -51.025277583740525, -46.11152498485985, -17.51108674058229, -6.141613959880809, -107.74424733083552, 24.898229249313353, -27.273007692798586, -26.553484680185544, -38.6166124915005, -29.34043563361383, 31.648897538128374, 52.881233935942774]
t = [50.0,51.0,52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,59.0,59.0,60.0,61.0, 59.0,63.0,64.0, 65.0, 66.0,67.0, 68.0,69.0, 70.0,71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0]
dd= ['0','50','79','80','88','95','0','50','79','80','88','95','0','50','79','80','88','95','88','95','79','80','50','79','95','0','50','88','88','95']
df = pd.DataFrame({'y1':y1,'y2':y2,'t':t,'dd':dd})
fig, axes = plt.subplots(2,1, sharex=True, figsize=(17,10))
sns.lineplot(ax=axes[0],hue='dd',x='t', y=y1, data=df, legend='full', ci=None)
sns.lineplot(ax=axes[1],hue='dd',x='t', y=y2, data=df, legend='full', ci=None)
plt.show();
I want same graph in plotly.
I tried
import plotly.graph_objects as go
fig = px.line(rmc, y='y1', x='t',color=df['dd'],title='plot')
fig = px.line(rmc, y='y2', x='t', title='plot', color=df['dd'])
fig.show();
thank you in advance!!

Based on the example I commented on, I created a code with an updated data frame. I have specified 6 colors from the plotly default color set so that each graph has a common line color. The second is hidden because it is automatically assigned a legend. I have also added subtitle and main title settings.
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import plotly.express as px
colors = px.colors.qualitative.Plotly[:6]
print(colors)
fig = make_subplots(
rows=2, cols=1,
subplot_titles=("Ttitle 1", "Title 2"))
for d,c in zip(df['dd'].unique(), colors):
dff = df.query('dd == #d')
fig.add_trace(go.Scatter(x=dff['t'], y=dff['y1'], mode='lines', line_color=c, name=d), row=1, col=1)
fig.add_trace(go.Scatter(x=dff['t'], y=dff['y2'], mode='lines', line_color=c, name=d, showlegend=False), row=2, col=1)
fig.update_layout(title_text="Multiple Subplots with Titles")
fig.show()

Plotly express handles this beautifully with px.line if you include the facet_row argument to produce a trellis or facet plot. Both of which are practically just other terms for a subplot. If you're willing to perform a slight manipulation of your dataset so that y1 and y2 appear in the same column like this:
pd.melt(df, id_vars= ['t', 'dd'], value_vars = ['y1', 'y2'])
...then all you have to do in order to produce the plot below is:
px.line(df2, y='value', x='t', title='plot', color = 'dd', facet_row = 'variable')
Plot
Complete snippet
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
y1 = [-51.04464896560272, -50.891166658544364, -50.82896235500738,-47.93693115514636, -48.93693115514636, -50.2337317810911, -50.580211311328924, -49.63778008455918, -50.55143905012876, -47.18028476096273, -49.45950323726963, -52.759450409024325, -46.94239220924591, -49.34719404199133, -48.592737888881025, -50.39057938285388,-50.33666292445022,-49.689436282011854,-49.86872483079463, -49.47463251418676,-51.542982170986264, -50.650742675143576, -46.498494705109124, -69.232249295994,-65.83208484345344,-56.624359510655715, -64.65663405050996, -63.385051075806444, -61.4890501679952, -64.5215014815885]
y2 = [-49.22994660618851, -49.93693115514636,-47.48816812312157, -47.642008385846054, -49.24556971152835, -49.003594660143946, -49.92614593515235, -48.79589239042106, -49.90953636053393, -49.84547212502676, -48.83995760926475, -50.399185030856515, -47.98870212151289, -49.68206139796429, -48.82322978146867, -49.76209077328067, -48.3489893943433, -49.7807786904155, -51.025277583740525, -46.11152498485985, -17.51108674058229, -6.141613959880809, -107.74424733083552, 24.898229249313353, -27.273007692798586, -26.553484680185544, -38.6166124915005, -29.34043563361383, 31.648897538128374, 52.881233935942774]
t = [50.0,51.0,52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,59.0,59.0,60.0,61.0, 59.0,63.0,64.0, 65.0, 66.0,67.0, 68.0,69.0, 70.0,71.0, 72.0, 73.0, 74.0, 75.0, 76.0, 77.0]
dd= ['0','50','79','80','88','95','0','50','79','80','88','95','0','50','79','80','88','95','88','95','79','80','50','79','95','0','50','88','88','95']
df = pd.DataFrame({'y1':y1,'y2':y2,'t':t,'dd':dd})
df2 = pd.melt(df, id_vars= ['t', 'dd'], value_vars = ['y1', 'y2'])
fig = px.line(df2, y='value', x='t', title='Trellis / Facet plot', color = 'dd', facet_row = 'variable')
fig.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])

Draw multiple CSV files in a HTML page using Plotly

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()

stacked barplot in plotly

My input:
names_col = ['Count','Percentage']
dat = [['Matching', 63],['Mismatching', 37]]
plot_df = pd.DataFrame(data=dat,columns=names_col)
I just trying plot within plotly simple bar char where stacked.
my code:
fig = px.bar(p_df, x='Count', y='Percentage', color='Count' ,title='My plot', barmode='stack')
fig.show();
And what I get:
That not what I expected. I want something like this:
Here code within seaborn:
p=p_df.set_index('Count').T.plot(kind='bar', stacked=True, figsize=(12,8),rot=0)
p.set_title('BBPS.2')
for x in p.containers:
p.bar_label(x, label_type='edge', weight='bold')
p.bar_label(x, label_type='center', weight='bold', color='white')
plt.show();
By setting the x axis to 'Count' you are defining the bars to not be stacked.
You could either find a different parameter for the x axis or add a dummy column with the same value for both rows so they have the same x value:
import pandas as pd
import plotly.express as px
names_col = ['Count','Percentage', 'dummy']
dat = [['Matching', 63, 0],['Mismatching', 37, 0]]
plot_df = pd.DataFrame(data=dat,columns=names_col)
fig = px.bar(plot_df, x='dummy', y='Percentage', color='Count' ,title='My plot')
fig.show()
The result:
You need to set the base to the first bar in order to stack them. Right now you have merely defined two separate bars. Take a look at this code from a dev.to post:
fig3 = go.Figure(
data=[
go.Bar(
name="Original",
x=data["labels"],
y=data["original"],
offsetgroup=0,
),
go.Bar(
name="Model 1",
x=data["labels"],
y=data["model_1"],
offsetgroup=1,
),
go.Bar(
name="Model 2",
x=data["labels"],
y=data["model_2"],
offsetgroup=1,
base=data["model_1"],
)
],
layout=go.Layout(
title="Issue Types - Original and Models",
yaxis_title="Number of Issues"
)
)
fig3.show()
That resulted in a plot that looks like this:

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')

Plotly: How to add volume to a candlestick chart

code:
from plotly.offline import init_notebook_mode, iplot, iplot_mpl
def plot_train_test(train, test, date_split):
data = [Candlestick(x=train.index, open=train['open'], high=train['high'], low=train['low'], close=train['close'],name='train'),
Candlestick(x=test.index, open=test['open'], high=test['high'], low=test['low'], close=test['close'],name='test')
]
layout = {
'shapes': [
{'x0': date_split, 'x1': date_split, 'y0': 0, 'y1': 1, 'xref': 'x', 'yref': 'paper',
'line': {'color': 'rgb(0,0,0)', 'width': 1}}],
'annotations': [{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'left','text': ' test data'},
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'right', 'text': 'train data '}] }
figure = Figure(data=data, layout=layout)
iplot(figure)
The above code is ok.But now I want to 'volume' in this candlestick chart
code:
from plotly.offline import init_notebook_mode, iplot, iplot_mpl
def plot_train_test(train, test, date_split):
data = [Candlestick(x=train.index, open=train['open'], high=train['high'], low=train['low'], close=train['close'],volume=train['volume'],name='train'),
Candlestick(x=test.index, open=test['open'], high=test['high'], low=test['low'],close=test['close'],volume=test['volume'],name='test')]
layout = {
'shapes': [
{'x0': date_split, 'x1': date_split, 'y0': 0, 'y1': 1, 'xref': 'x', 'yref': 'paper',
'line': {'color': 'rgb(0,0,0)', 'width': 1}}
],
'annotations': [
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'left',
'text': ' test data'},
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'right',
'text': 'train data '}
]
}
figure = Figure(data=data, layout=layout)
iplot(figure)
error:
ValueError: Invalid property specified for object of type
plotly.graph_objs.Candlestick: 'volume'
If you looking add smaller subplot of volume just below OHLC chart, you can use:
rows and cols to specify the grid for subplots.
shared_xaxes=True for same zoom and filtering
row_width=[0.2, 0.7] to change height ratio of charts. ie. smaller volume chart than OHLC
Plot:
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# data
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
# Create subplots and mention plot grid size
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
vertical_spacing=0.03, subplot_titles=('OHLC', 'Volume'),
row_width=[0.2, 0.7])
# Plot OHLC on 1st row
fig.add_trace(go.Candlestick(x=df["Date"], open=df["AAPL.Open"], high=df["AAPL.High"],
low=df["AAPL.Low"], close=df["AAPL.Close"], name="OHLC"),
row=1, col=1
)
# Bar trace for volumes on 2nd row without legend
fig.add_trace(go.Bar(x=df['Date'], y=df['AAPL.Volume'], showlegend=False), row=2, col=1)
# Do not show OHLC's rangeslider plot
fig.update(layout_xaxis_rangeslider_visible=False)
fig.show()
You haven't provided a complete code snippet with a data sample, so I'm going to have to suggest a solution that builds on an example here.
In any case, you're getting that error message simply because go.Candlestick does not have a Volume attribute. And it might not seem so at first, but you can easily set up go.Candlestick as an individual trace, and then include an individual go.Bar() trace for Volumes using:
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_traces(go.Candlestick(...), secondary_y=True)
fig.add_traces(go.Bar(...), secondary_y=False)
Plot:
Complete code:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
# data
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# include candlestick with rangeselector
fig.add_trace(go.Candlestick(x=df['Date'],
open=df['AAPL.Open'], high=df['AAPL.High'],
low=df['AAPL.Low'], close=df['AAPL.Close']),
secondary_y=True)
# include a go.Bar trace for volumes
fig.add_trace(go.Bar(x=df['Date'], y=df['AAPL.Volume']),
secondary_y=False)
fig.layout.yaxis2.showgrid=False
fig.show()
Here is my improvement implementation based on the previous answer by Vestland, with some labelling and colouring improvements.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
candlesticks = go.Candlestick(
x=candles.index,
open=candles['open'],
high=candles['high'],
low=candles['low'],
close=candles['close'],
showlegend=False
)
volume_bars = go.Bar(
x=candles.index,
y=candles['volume'],
showlegend=False,
marker={
"color": "rgba(128,128,128,0.5)",
}
)
fig = go.Figure(candlesticks)
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(candlesticks, secondary_y=True)
fig.add_trace(volume_bars, secondary_y=False)
fig.update_layout(title="ETH/USDC pool after Uniswap v3 deployment", height=800)
fig.update_yaxes(title="Price $", secondary_y=True, showgrid=True)
fig.update_yaxes(title="Volume $", secondary_y=False, showgrid=False)
fig.show()
You can find the full source code in this open-source notebook.
If you want to add different colors for buy/sell isay 'green'/'red', you can use some libs (e.g. mplfinance) which do these automatically however the plots are non-interactive. To get interactive plot with plotly with separate colors for buy/sell colors, one needs to add trace for each data point. Here is code:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
# Create subplots and mention plot grid size
title=df.symbol.unique()[0]
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
vertical_spacing=0.02,
row_width=[0.25, 0.75])
# Plot OHLC on 1st row
fig.add_trace(go.Candlestick(x=df.index,
open=df['open'], high=df['high'],
low=df['low'], close=df['close'],showlegend=False),row=1, col=1,)
# Bar trace for volumes on 2nd row without legend
# fig.add_trace(go.Bar(x=df.index, y=df['volume'], showlegend=False), row=2, col=1)
df['color']=''
df['color']=['red' if (x>y) else t for x,y,t in zip(df['open'],df['close'],df['color'])]
df['color']=['green' if (x<y) else t for x,y,t in zip(df['open'],df['close'],df['color'])]
colors=df.color.tolist()
df['prev_color']=[colors[0]]+colors[:(len(colors)-1)]
df.loc[((df.open==df.close) & (df.color=='')),'color']=[z for x,y,z,t in zip(df['open'],df['close'],df['prev_color'],df['color']) if (x==y and t=='')]
colors=df.color.tolist()
df['prev_color']=[colors[0]]+colors[:(len(colors)-1)]
df.loc[((df.open==df.close) & (df.color=='')),'color']=[z for x,y,z,t in zip(df['open'],df['close'],df['prev_color'],df['color']) if (x==y and t=='')]
markers=['green','red']
for t in markers:
df_tmp=df.loc[~(df.color==t)] ## somehow the color it takes is opposite so take negation to
fig.add_trace(go.Bar(x=df_tmp.index, y=df_tmp['volume'], showlegend=False), row=2, col=1)
# Do not show OHLC's rangeslider plot
fig.update(layout_xaxis_rangeslider_visible=False)
fig.layout.yaxis2.showgrid=False
fig.update_layout(title_text=title,title_x=0.45)
fig.show()
My two cents on Plotting Volume in a different subplot with colors, it is just making #user6397960 response shorter without hacks to get the right color, just use marker_color. Think about it, what makes a candle green? The fact of having Close price above the Open price, and what about red candle? well, having a close price below the open price, so with this basics:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Create a Figure with 2 subplots, one will contain the candles
# the other will contain the Volume bars
figure = make_subplots(rows=2, cols=1, shared_xaxes=True, row_heights=[0.7, 0.3])
# Plot the candles in the first subplot
figure.add_trace(go.Candlestick(x=df.index, open=df.open, high=df.high, low=df.low, close=df.close, name='price',
increasing_line_color='#26a69a', decreasing_line_color='#ef5350'),
row=1, col=1)
# From our Dataframe take only the rows where the Close > Open
# save it in different Dataframe, these should be green
green_volume_df = df[df['close'] > df['open']]
# Same for Close < Open, these are red candles/bars
red_volume_df = df[df['close'] < df['open']]
# Plot the red bars and green bars in the second subplot
figure.add_trace(go.Bar(x=red_volume_df.index, y=red_volume_df.volume, showlegend=False, marker_color='#ef5350'), row=2,
col=1)
figure.add_trace(go.Bar(x=green_volume_df.index, y=green_volume_df.volume, showlegend=False, marker_color='#26a69a'),
row=2, col=1)
# Hide the Range Slider
figure.update(layout_xaxis_rangeslider_visible=False)
figure.update_layout(title=f'BTC/USDT', yaxis_title=f'Price')
figure.update_yaxes(title_text=f'Volume', row=2, col=1)
figure.update_xaxes(title_text='Date', row=2)
References
https://plotly.com/python/subplots/
https://plotly.com/python/candlestick-charts/

Categories