Is it possible to align two Y-axis by two different values? I would like to align my yaxis1 at zero with my yaxis2 at 1, like in the picture
picture
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
df = pd.DataFrame(dict(months=['jan','feb','mar','apr','may','jun'],
assets = [60,20,-25,-35,20,80],
liabilities = [70,75,80,90,70,50]))
# calculate ratio
df['ratio'] = df['assets'] / df['liabilities']
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(go.Bar(x=df['months'], y=df['assets'], marker_color='green'))
fig.add_trace(go.Bar(x=df['months'], y=df['liabilities'], marker_color='red'))
fig.add_trace(go.Scatter(x=df['months'], y=df['ratio'], marker_color='orange'), secondary_y=True)
fig.update_yaxes(showgrid=False, secondary_y=True)
fig.show()
To set the range of the 2nd y-axis, set the range in the layout. The manual adjustment of the second y-axis affected the scale of the first y-axis, which was corrected at the same time. If it is not the intended scale, you are responsible for correcting it.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
df = pd.DataFrame(dict(months=['jan','feb','mar','apr','may','jun'],
assets = [60,20,-25,-35,20,80],
liabilities = [70,75,80,90,70,50]))
# calculate ratio
df['ratio'] = df['assets'] / df['liabilities']
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(go.Bar(x=df['months'], y=df['assets'], marker_color='green',name='assets'))
fig.add_trace(go.Bar(x=df['months'], y=df['liabilities'], marker_color='red',name='liabilities'))
fig.add_trace(go.Scatter(x=df['months'], y=df['ratio'], marker_color='orange',name='ratio'), secondary_y=True)
fig.update_yaxes(showgrid=False, secondary_y=True),
fig.update_layout(autosize=True, yaxis=dict(range=[-50,150]), yaxis2=dict(range=[0,4]))#height=600,
fig.show()
Related
I am trying to plot closing price with positive and negative sentiment. I was able to plot it as the picture below; however, the colors are not showing properly for the bar chart. Any ideas how to change them?
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig2 = make_subplots(specs=[[{"secondary_y": True}]])
fig2.add_trace(go.Scatter(x=data.index,y=data['close'],name='Price'),secondary_y=False)
fig2.add_trace(go.Bar(x=data.index,y=data['pos'],name='Positive'),secondary_y=True)
fig2.add_trace(go.Bar(x=data.index,y=data['neg'],name='Negative'),secondary_y=True)
fig2.show()
have implied you dataframe structure from your code and used plotly finance sample data set as starting point
two things to look at wrt to layout
make Close trace the primary trace at front
review bargroup parameter and reduce bargap to zero
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import pandas as pd
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv"
)
# make plotly dataset compatible with OP implied structure
data = df.set_index(pd.date_range("1-Jan-2022", freq="5Min", periods=len(df))).rename(
columns={"AAPL.Close": "close", "dn": "neg", "up": "pos"}
)
fig2 = make_subplots(specs=[[{"secondary_y": True}]])
fig2.add_trace(
go.Scatter(x=data.index, y=data["close"], name="Price"), secondary_y=False
)
fig2.add_trace(go.Bar(x=data.index, y=data["pos"], name="Positive"), secondary_y=True)
fig2.add_trace(go.Bar(x=data.index, y=data["neg"], name="Negative"), secondary_y=True)
# a few changes to make layout work better
# 1. put close at front
# 2. reduce "whitespace" in bars
fig2.update_layout(
yaxis={"overlaying": "y2"}, yaxis2={"overlaying": None}, barmode="overlay", bargap=0
)
Given grouped bins , is there a way of having a larger gap between the bins? in
I.e, in the desired output, every bar/bar group has a predefined space around it.
# Change the default stacking
import plotly.express as px
df = px.data.tips()
fig = px.bar(df, x="sex", y="total_bill",
color='smoker', barmode='group',
height=400)
fig.show()
After building a figure you can adjust the gap between the bars like this:
fig.layout.bargap = 0.8
I've used 0.8 just to clearly illustrate the effects, but that number can be set to any int or float in the interval [0, 1]
Complete code:
import plotly.express as px
df = px.data.tips()
fig = px.bar(df, x="sex", y="total_bill",
color='smoker', barmode='group',
height=400)
f = fig.full_figure_for_development(warn=False)
fig.layout.bargap = 0.8
fig.show()
I noticed that plotting different time scales causes the opacity of my overlaid bar chart to fade. How do I correct this? In the first image, I plotted over a range of 2 years and in the second I plotted a 1 year time range. Notice that the former has a significantly faded bar chart, I would expect that these two charts to be the same regardless of range.
Sidenote: I am "hacking" the chart to center on the primary axis, if anyone can help me figure out how to directly set the y-axis range of the secondary axis that would be very helpful as well.
import plotly.graph_objects as go
from plotly.subplots import make_subplots
filtered = df[(df['date'] > '2017-1-24') & (df['date'] <= '2018-1-24')]
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Bar(
x=filtered['date'],
y=filtered['divergence'],
opacity=0.5
)
)
fig.add_trace(
go.Scatter(
x=filtered['date'],
y=filtered['price'],
mode="lines"
),
secondary_y=True
)
fig.update_layout(yaxis_range=[-9, 9])
fig.show()
Opacity lower than expected:
Opacity normal:
Short answer:
This has nothing to do with opacity. For some more details take a look below at the complete answer. To obtain consisteny between a figures with many and few observations, you'll have to set the width of the bar line to zero, and set bargap to zero like in the next code snippet. Using a color like rgba(0,0,250,0) you can also select any opacity you'd like through the last digit.
fig.update_traces(marker_color = 'rgba(0,0,250, 0.5)',
marker_line_width = 0,
selector=dict(type="bar"))
fig.update_layout(bargap=0,
bargroupgap = 0,
)
Plot 1a - Few observations
Plot 1b - Many observations
The details:
This has nothing to do with opacity. You're asking plotly to build a bar-plot, and apparently barplots according to plotly must have a space between the bars. So for a few observations you'll get this:
And for many observations, as you have demonstrated, you'll get this:
The color of the bars has not changed, but it seems like it since plolty squeezes in a bit of space for many more observations.
I initially thought this would be amendable through:
fig.update_layout(bargap=0,
bargroupgap = 0,
)
But no:
In order to increase consistency between smaller and larger selectoins, you'll have to select the same color for the bar fill as for the line color of the bar, like blue.
fig.update_traces(marker_color='blue',
marker_line_color='blue',
selector=dict(type="bar"))
But there's still a little color difference between the bars if you zoom in:
And this becomes clearer for lighter colors:
But the best solution turned out to be setting marker_line_width = 0 like described at the beginning of the answer.
End result:
Complete code:
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
import datetime
from plotly.subplots import make_subplots
pd.set_option('display.max_rows', None)
# data sample
nperiods = 50
np.random.seed(123)
df = pd.DataFrame(np.random.randint(-10, 12, size=(nperiods, 2)),
columns=['price', 'divergence'])
datelist = pd.date_range(datetime.datetime(2017, 1, 1).strftime('%Y-%m-%d'),periods=nperiods).tolist()
df['date'] = datelist
df = df.set_index(['date'])
df.index = pd.to_datetime(df.index)
# df.iloc[0] =1000
# df = df.cumsum().reset_index()
df.reset_index(inplace=True)
df['price'] = df['price'].cumsum()
df['divergence'] = df['divergence'].cumsum()
filtered = df[(df['date'] > '2017-1-24') & (df['date'] <= '2018-1-24')]
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(
go.Bar(
x=filtered['date'],
y=filtered['divergence'],
#opacity=0.5
)
)
fig.add_trace(
go.Scatter(
x=filtered['date'],
y=filtered['price'],
mode="lines"
),
secondary_y=True
)
fig.update_traces(marker_color = 'rgba(0,0,250, 0.5)',
marker_line_width = 0,
selector=dict(type="bar"))
fig.update_layout(bargap=0,
bargroupgap = 0,
)
fig.show()
It is not changing opacity, but it is trying to plot large number of bars in given plot area. try zooming in and see the difference. also try changing width of the plot with :
fig.update_layout(width=2500)
to change secondary axis range use :
fig.update_layout(yaxis2_range=[lower_range,upper_range])
How do I utilize plotly.express to plot multiple lines on two yaxis out of one Pandas dataframe?
I find this very useful to plot all columns containing a specific substring:
fig = px.line(df, y=df.filter(regex="Linear").columns, render_mode="webgl")
as I don't want to loop over all my filtered columns and use something like:
fig.add_trace(go.Scattergl(x=df["Time"], y=df["Linear-"]))
in each iteration.
It took me some time to fiddle this out, but I feel this could be useful to some people.
# import some stuff
import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
# create some data
df = pd.DataFrame()
n = 50
df["Time"] = np.arange(n)
df["Linear-"] = np.arange(n)+np.random.rand(n)
df["Linear+"] = np.arange(n)+np.random.rand(n)
df["Log-"] = np.arange(n)+np.random.rand(n)
df["Log+"] = np.arange(n)+np.random.rand(n)
df.set_index("Time", inplace=True)
subfig = make_subplots(specs=[[{"secondary_y": True}]])
# create two independent figures with px.line each containing data from multiple columns
fig = px.line(df, y=df.filter(regex="Linear").columns, render_mode="webgl",)
fig2 = px.line(df, y=df.filter(regex="Log").columns, render_mode="webgl",)
fig2.update_traces(yaxis="y2")
subfig.add_traces(fig.data + fig2.data)
subfig.layout.xaxis.title="Time"
subfig.layout.yaxis.title="Linear Y"
subfig.layout.yaxis2.type="log"
subfig.layout.yaxis2.title="Log Y"
# recoloring is necessary otherwise lines from fig und fig2 would share each color
# e.g. Linear-, Log- = blue; Linear+, Log+ = red... we don't want this
subfig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
subfig.show()
The trick with
subfig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
I got from nicolaskruchten here: https://stackoverflow.com/a/60031260
Thank you derflo and vestland! I really wanted to use Plotly Express as opposed to Graph Objects with dual axis to more easily handle DataFrames with lots of columns. I dropped this into a function. Data1/2 works well as a DataFrame or Series.
import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd
def plotly_dual_axis(data1,data2, title="", y1="", y2=""):
# Create subplot with secondary axis
subplot_fig = make_subplots(specs=[[{"secondary_y": True}]])
#Put Dataframe in fig1 and fig2
fig1 = px.line(data1)
fig2 = px.line(data2)
#Change the axis for fig2
fig2.update_traces(yaxis="y2")
#Add the figs to the subplot figure
subplot_fig.add_traces(fig1.data + fig2.data)
#FORMAT subplot figure
subplot_fig.update_layout(title=title, yaxis=dict(title=y1), yaxis2=dict(title=y2))
#RECOLOR so as not to have overlapping colors
subplot_fig.for_each_trace(lambda t: t.update(line=dict(color=t.marker.color)))
return subplot_fig
I have a plotly-dash dashboard and I can't seem to rescale my secondary y-axis. Is there a way of doing this?
I've tried messing with the domain parameter and the range parameter in the go.Layout.
I need the volume bar chart to be scaled down and occupy maybe 10% of the height of the plot so it doesn't overlap with my candlesticks.
Thank you very much.
Any help is appreciated.
import pandas as pd
import pandas_datareader.data as web
import plotly.offline as pyo
import plotly.graph_objs as go
stock_ticker='AAPL'
start_date='2019-04-01'
end_date='2019-05-22'
data=[]
hist_stock_df = web.DataReader(stock_ticker,'iex',start_date, end_date)
data.append(go.Candlestick(x=hist_stock_df.index,
open=hist_stock_df['open'],
high=hist_stock_df['high'],
low=hist_stock_df['low'],
close=hist_stock_df['close'],
name='AAPL'))
data.append(go.Bar(x=hist_stock_df.index,
y=hist_stock_df['volume'].values,
yaxis='y2'))
#y0=1000000
layout=go.Layout(title= 'Candestick Chart of AAPL',
xaxis=dict(title='Date',rangeslider=dict(visible=False)),
yaxis=dict(title='Price'),
plot_bgcolor='#9b9b9b',
paper_bgcolor='#9b9b9b',
font=dict(color='#c4c4c4'),
yaxis2=dict(title='Volume',
overlaying='y',
side='right'))
#scaleanchor='y'))
#scaleratio=0.00000001,
#rangemode='tozero',
#constraintoward='bottom',
#domain=[0,0.1]))
fig = go.Figure(data=data, layout=layout)
pyo.iplot(fig)
I have tried messing with the commented parameters
UPDATE
With this combination of layout parameters I managed to rescale the bars, but now there are two x-axis, been trying to figure out how to bring the middle x-axis down.
layout=go.Layout(title= 'Candestick Chart of AAPL',
xaxis=dict(title='Date',rangeslider=dict(visible=False)),
yaxis=dict(title='Price'),
plot_bgcolor='#9b9b9b',
paper_bgcolor='#9b9b9b',
font=dict(color='#c4c4c4'),
yaxis2=dict(title='Volume',
overlaying='y',
side='right',
scaleanchor='y',
scaleratio=0.0000001))
Use secondary_y=True or secondary_y=False within fig.update_yaxes() to specify which axis to adjust.
Plot 1: Without manual adjustments
Plot 2: With manual adjustments
Code:
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import datetime
# data
np.random.seed(1234)
numdays=20
dates = pd.date_range('1/1/2020', periods=numdays)
A = (np.random.randint(low=-10, high=10, size=numdays).cumsum()+100).tolist()
B = (np.random.randint(low=0, high=100, size=numdays).tolist())
df = pd.DataFrame({'A': A,'B':B}, index=dates)
# plotly figure setup
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.add_trace(go.Scatter(name='A', x=df.index, y=df['A'].values))
fig.add_trace(go.Bar(name='B', x=df.index, y=df['B'].values), secondary_y=True)
# plotly manual axis adjustments
fig.update_yaxes(range=[50,160], secondary_y=False)
fig.update_yaxes(range=[-10,200], secondary_y=True)
fig.show()