The code below makes candlestick plots with a range slider. If I make the slider narrow, I want to zoom on the vertical scale. How is this done? I expect some kind of setting for it, but I can not find it. At the moment the result can look like the screenshot; obviously not optimal. A large part of the vertical scale remains unused. How to fix that?
import sys
import pandas as pd
import plotly.graph_objects as go
from datetime import datetime
from Downloader import CDownloader
# import matplotlib.dates as mdates # Styling dates
class CGraphs:
def Candlestick(self, aSymbolName:str):
# Warning, this function reads from disk, so it is slow.
print(sys._getframe().f_code.co_name, ": Started. aSymbolName ", aSymbolName)
downloader : CDownloader = CDownloader()
df_ohlc : pd.DataFrame = downloader.GetHistoricalData(aSymbolName)
print("df_ohlc", df_ohlc)
graph_candlestick = go.Figure()
candle = go.Candlestick(x = df_ohlc['Date'],
open = df_ohlc['Open'],
high = df_ohlc['High'],
low = df_ohlc['Low'],
close = df_ohlc['Close'],
name = "Candlestick " + aSymbolName)
graph_candlestick.add_trace(candle)
graph_candlestick.update_xaxes(title="Date", rangeslider_visible=True)
graph_candlestick.update_yaxes(title="Price", autorange=True)
graph_candlestick.update_layout(
title = aSymbolName,
height = 600,
width = 900,
showlegend = True)
graph_candlestick.update_layout(xaxis_rangebreaks = [ dict(bounds=["sat", "mon"]) ])
graph_candlestick.show()
print(sys._getframe().f_code.co_name, ": Finished. aSymbolName ", aSymbolName)
graphs:CGraphs = CGraphs()
graphs.Candlestick("MSFT")
This feature isn't available in plotly-python
, and it's currently an open issue for the Plotly team.
I think you could build this functionality out in plotly-dash
since this library supports callbacks. For example, using a server-side implementation (with a lot of help from @kkollsg's answers on this forum):
import dash
from dash import Output, Input, State, dcc, html
import plotly.graph_objs as go
import numpy as np
import pandas as pd
import datetime
class CGraphs:
def makeCandlestick(self, aSymbolName:str):
# Warning, this function reads from disk, so it is slow.
# print(sys._getframe().f_code.co_name, ": Started. aSymbolName ", aSymbolName)
# downloader : CDownloader = CDownloader()
# df_ohlc : pd.DataFrame = downloader.GetHistoricalData(aSymbolName)
## load some similar stock data
df_ohlc = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
df_ohlc.rename(columns=dict(zip(['AAPL.Open', 'AAPL.High', 'AAPL.Low', 'AAPL.Close'],['Open','High','Low','Close'])), inplace=True)
# print("loading data")
# print("df_ohlc", df_ohlc)
graph_candlestick = go.Figure()
candle = go.Candlestick(x = df_ohlc['Date'],
open = df_ohlc['Open'],
high = df_ohlc['High'],
low = df_ohlc['Low'],
close = df_ohlc['Close'],
name = "Candlestick " + aSymbolName)
graph_candlestick.add_trace(candle)
graph_candlestick.update_xaxes(title="Date", rangeslider_visible=True)
graph_candlestick.update_yaxes(title="Price", autorange=True)
graph_candlestick.update_layout(
title = aSymbolName,
height = 600,
width = 900,
showlegend = True)
graph_candlestick.update_layout(xaxis_rangebreaks = [ dict(bounds=["sat", "mon"]) ])
app = dash.Dash()
app.layout = html.Div(
html.Div([
dcc.Graph(id='graph_candlestick',figure=graph_candlestick)
])
)
#Server side implementation (slow)
@app.callback(
Output('graph_candlestick','figure'),
[Input('graph_candlestick','relayoutData')],[State('graph_candlestick', 'figure')]
)
def update_result(relOut,Fig):
if relOut == None:
return Fig
## if you don't use the rangeslider to adjust the plot, then relOut.keys() won't include the key xaxis.range
elif "xaxis.range" not in relOut.keys():
newLayout = go.Layout(
title=aSymbolName,
height=600,
width=800,
showlegend=True,
yaxis=dict(autorange=True),
template="plotly"
)
Fig['layout']=newLayout
return Fig
else:
ymin = df_ohlc.loc[df_ohlc['Date'].between(relOut['xaxis.range'][0], relOut['xaxis.range'][1]),'Low'].min()
ymax = df_ohlc.loc[df_ohlc['Date'].between(relOut['xaxis.range'][0], relOut['xaxis.range'][1]),'High'].max()
newLayout = go.Layout(
title=aSymbolName,
height=600,
width=800,
showlegend=True,
xaxis=dict(
rangeslider_visible=True,
range=relOut['xaxis.range']
),
yaxis=dict(range=[ymin,ymax]),
template="plotly"
)
Fig['layout']=newLayout
return Fig
app.run_server(debug=True)
graphs:CGraphs = CGraphs()
graphs.makeCandlestick("MSFT")