Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plotly: How to set custom xticks

From plotly doc:

layout > xaxis > tickvals:

Sets the values at which ticks on this axis appear. Only has an effect if tickmode is set to "array". Used with ticktext.

layout > xaxis > ticktext:

Sets the text displayed at the ticks position via tickvals. Only has an effect if tickmode is set to "array". Used with tickvals.

Example:

import pandas as pd
import numpy as np

np.random.seed(42)
feature = pd.DataFrame({'ds': pd.date_range('20200101', periods=100*24, freq='H'), 
                        'y': np.random.randint(0,20, 100*24) , 
                        'yhat': np.random.randint(0,20, 100*24) , 
                        'price': np.random.choice([6600, 7000, 5500, 7800], 100*24)})


import plotly.graph_objects as go
import plotly.offline as py
import plotly.express as px
from plotly.offline import init_notebook_mode

init_notebook_mode(connected=True)


y = feature.set_index('ds').resample('D')['y'].sum()

fig = go.Figure()
fig.add_trace(go.Scatter(x=y.index, y=y))


x_dates = y.index.to_series().dt.strftime('%Y-%m-%d').sort_values().unique()


layout = dict(
    xaxis=dict(
        tickmode="array",
        tickvals=np.arange(0, x_dates.shape[0],2).astype(int),
        ticktext=x_dates[::2],
        tickformat='%Y-%m-%d',
        tickangle=45,
    )
)

fig.update_layout(layout)
fig.show()

Result:

enter image description here

Since length of x_dates[::2] is 50 , the ticknumber doesn't match at all . How do I sovle it ??

like image 507
Mithril Avatar asked May 18 '20 02:05

Mithril


People also ask

How do you change the y axis values in plotly?

Go to 'Axes', then 'Tick Labels' and depending on the axis you want to change, select X, Y, or 'ALL'.

Is plotly customizable?

Figures made with Plotly Express can be customized in all the same ways as figures made with graph objects, as well as with PX-specific function arguments.


1 Answers

I normally use the approach below. You should know that tickvals is to be regarded as a positional argument and works best (perhaps only) with numerical values and not dates. Use ticktext to display the dates in your preferred format.

Snippet 1:

fig.update_xaxes(tickangle=45,
                 tickmode = 'array',
                 tickvals = df_tips['date'][0::40],
                 ticktext= [d.strftime('%Y-%m-%d') for d in datelist])

Plot 1:

enter image description here

Now you can change tickvals=np.arange(0, y.shape[0]).astype(int)[0::40] to tickvals=np.arange(0, y.shape[0]).astype(int)[0::80] and get:

Plot 2:

plot2

So why didn't this work for you the first time? A number of reasons:

  1. Your resampled pandas series y had dates as indexes, so y.index were set as x-axis values.
  2. y.index returns dates
  3. When you set the tickmark positions through fig.update_xaxes(tickvals), this works better with integer values.

And what did I do to fix it?

  1. I reset the index after resampling so that y.index does not return dates.
  2. Changed y to a dataframe using .to_frame.
  3. Changed to fig.add_trace(go.Scatter(x=y.index, y=y.y)) which otherwise would have failed since this is now a dataframe and not a series.
  4. Your dates are now retrieved as x_dates = y.ds

I know y=y.y looks really weird, but I just left it like that as a friendly reminder to give your pandas series or dataframes more sensible names than a single letter like y that's more likely to be confused with a single, index-free, array or list.

Complete code:

import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.offline as py
import plotly.express as px
from plotly.offline import init_notebook_mode

# data
np.random.seed(42)
feature = pd.DataFrame({'ds': pd.date_range('20200101', periods=100*24, freq='H'), 
                        'y': np.random.randint(0,20, 100*24) , 
                        'yhat': np.random.randint(0,20, 100*24) , 
                        'price': np.random.choice([6600, 7000, 5500, 7800], 100*24)})

# resampling
y = feature.set_index('ds').resample('D')['y'].sum()#.to_frame()
y=y.to_frame()
y.reset_index(inplace=True)

# plotly setup
fig = go.Figure()
fig.add_trace(go.Scatter(x=y.index, y=y.y))

# x-ticks preparations
x_dates = y.ds
tickvals=np.arange(0, y.shape[0]).astype(int)[0::40]
ticktext=x_dates

# update tickmarks
fig.update_xaxes(tickangle=45,
                 tickmode = 'array',
                 tickvals = tickvals,
                 ticktext=[d.strftime('%Y-%m-%d') for d in ticktext])

fig.show()
like image 140
vestland Avatar answered Sep 22 '22 14:09

vestland