Plotly: How to style a plotly figure so that it doesn't display gaps for missing dates?
Asked Answered
Z

4

14

I have a plotly graph of the EUR/JPY exchange rate across a few months in 15 minute time intervals, so as a result, there is no data from friday evenings to sunday evenings.

Here is a portion of the data, note the skip in the index (type: DatetimeIndex) over the weekend: enter image description here

Plotting this data in plotly results in a gap over the missing dates Using the dataframe above:

import plotly.graph_objs as go
candlesticks = go.Candlestick(x=data.index, open=data['Open'], high=data['High'],
                   low=data['Low'], close=data['Close'])
fig = go.Figure(layout=cf_layout)
fig.add_trace(trace=candlesticks)
fig.show()

Ouput:

enter image description here

As you can see, there are gaps where the missing dates are. One solution I've found online is to change the index to text using:

data.index = data.index.strftime("%d-%m-%Y %H:%M:%S")

and plotting it again, which admittedly does work, but has it's own problem. The x-axis labels look atrocious:

enter image description here

I would like to produce a graph that plots a graph like in the second plot where there are no gaps, but the x-axis is displayed like as it is on the first graph. Or at least displayed in a much more concise and responsive format, as close to the first graph as possible.

Thank you in advance for any help!

Zoba answered 21/4, 2020 at 14:33 Comment(0)
P
15

Even if some dates are missing in your dataset, plotly interprets your dates as date values, and shows even missing dates on your timeline. One solution is to grab the first and last dates, build a complete timeline, find out which dates are missing in your original dataset, and include those dates in:

fig.update_xaxes(rangebreaks=[dict(values=dt_breaks)])

This will turn this figure:

enter image description here

Into this:

enter image description here

Complete code:

import plotly.graph_objects as go
from datetime import datetime
import pandas as pd
import numpy as np

# sample data
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')

# remove some dates to build a similar case as in the question
df = df.drop(df.index[75:110])
df = df.drop(df.index[210:250])
df = df.drop(df.index[460:480])

# build complete timepline from start date to end date
dt_all = pd.date_range(start=df['Date'].iloc[0],end=df['Date'].iloc[-1])

# retrieve the dates that ARE in the original datset
dt_obs = [d.strftime("%Y-%m-%d") for d in pd.to_datetime(df['Date'])]

# define dates with missing values
dt_breaks = [d for d in dt_all.strftime("%Y-%m-%d").tolist() if not d in dt_obs]

# make fiuge
fig = go.Figure(data=[go.Candlestick(x=df['Date'],
                open=df['AAPL.Open'], high=df['AAPL.High'],
                low=df['AAPL.Low'], close=df['AAPL.Close'])
                      ])

# hide dates with no values
fig.update_xaxes(rangebreaks=[dict(values=dt_breaks)])

fig.update_layout(yaxis_title='AAPL Stock')

fig.show()
Pyrolysis answered 23/6, 2020 at 9:40 Comment(6)
Using rangebreaks(as in accepted answer) in large volume of data resulted in slow loading of the candlestick graph. Below code worked for me very well. fig.update_layout(xaxis = dict(type="category"))Operant
@Prasanna Man Rajbanshi Are you content with the side effects of doing this?Pyrolysis
No, what are they? @PyrolysisOperant
This works! For hourly index there is an additional key "dvalue" that needs to be filled in, where dvalue = 60 * 60 * 1000 which means 60min * 60sec/min * 1000msec/sec. The update line becomes fig.update_xaxes(rangebreaks=[dict(values=dt_breaks, dvalue=dvalue)]). Refer to here community.plotly.com/t/…Gayden
@KevinZhu Nice addition!Pyrolysis
@PrasannaManRajbanshi's solution worked great for me!Debauched
D
12

Just in case someone here wants to remove gaps for outside trading hours and weekends, As shown below, using rangebreaks is the way to do it.

    fig = go.Figure(data=[go.Candlestick(x=df['date'], open=df['Open'], high=df['High'], low=df['Low'], close=df['Close'])])
    fig.update_xaxes(
        rangeslider_visible=True,
        rangebreaks=[
            # NOTE: Below values are bound (not single values), ie. hide x to y
            dict(bounds=["sat", "mon"]),  # hide weekends, eg. hide sat to before mon
            dict(bounds=[16, 9.5], pattern="hour"),  # hide hours outside of 9.30am-4pm
            # dict(values=["2020-12-25", "2021-01-01"])  # hide holidays (Christmas and New Year's, etc)
        ]
    )
    fig.update_layout(
        title='Stock Analysis',
        yaxis_title=f'{symbol} Stock'
    )

    fig.show()

here's Plotly's doc.

Damle answered 8/1, 2021 at 16:37 Comment(2)
This is more suitable esp. when it comes to stock prices with known holidays and market hours.Gerrygerrymander
@Gerrygerrymander Sure! As long as your missing dates are limited to known holidays.Pyrolysis
S
1

To fix problem with intraday data, you can use the dvalue parameter of rangebreak with the right ms value. For example, 1 hour = 3.6e6 ms, so use dvalue with this value.

Documentation here : https://plotly.com/python/reference/layout/xaxis/

fig.update_xaxes(rangebreaks=[dict(values=dt_breaks, dvalue=3.6e6)])

Syllabus answered 5/2, 2022 at 20:23 Comment(0)
I
0

thanks for the amazing sample! works on daily data but with intraday / 5min data rangebreaks only leave one day on chart

    # build complete timepline 
    dt_all = pd.date_range(start=df.index[0],end=df.index[-1], freq="5T")
    # retrieve the dates that ARE in the original datset
    dt_obs = [d.strftime("%Y-%m-%d %H:%M:%S") for d in pd.to_datetime(df.index, format="%Y-%m-%d %H:%M:%S")]
    # define dates with missing values
    dt_breaks = [d for d in dt_all.strftime("%Y-%m-%d %H:%M:%S").tolist() if not d in dt_obs]
Inferential answered 10/12, 2020 at 17:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.