Bring Drag & Drop to Dash with Dashboard Engine. 💫 Learn how at our next webinar!

Plotting time/dates on a log axis?

Hi all

Is it possible to plot dates or time on a log axis in Plotly?

Trying to achieve something like this:

I have tried the usual:

xaxis= dict(
                type='log', 
            ),

But it’s not plotting anything and my axis values look like this rather than what I’m expecting in my screenshot above.

Thanks

Chris

Hi @Chris369, could you please give an example of code reproducing what you want to do? On a log-axis, if the dates are from 2011 to 2020 then the axis spacing will not be very different from a linear one since their differences are very small compared to their value. On the other hand, for dates spanning more range on a log-axis, I tried the following which works ok

import plotly.graph_objects as go
x = [1000, 2011, 2012, 2013, 2050, 2100]
y = [0.5, 1, 2, 3, 4, 5]
fig = go.Figure(go.Scatter(x=x, y=y))
fig.update_layout(xaxis_type='log')
fig.show()


Please share more code if you cannot find a solution.

Hi Emmanuelle

Thanks for the reply. Your x values are integers that happen to represent years though and I want to use x values that are of type datetime e.g.

2010-09-01 00:00:00

2010-09-02 00:00:00

2010-09-03 00:00:00

2010-09-04 00:00:00

2010-09-05 00:00:00

2019-12-25 00:00:00

2019-12-26 00:00:00

2019-12-27 00:00:00

2019-12-28 00:00:00

2019-12-29 00:00:00

2019-12-30 00:00:00

2019-12-31 00:00:00

With data like this as my x values and a log scale I’m getting weird labels with % (see my second screenshot) and no line is being plotted. If I change back to non-log it plots fine (with a normal looking time series labels and plot line).

Anyone else? Is this possible?

My plot with a non log x-axis works fine e.g.

By changing to 'type=‘log’ I’m wanting my x-axis to squash up like this:

But I’m getting this:

an axis type can be "linear" | "log" | "date" | "category" | "multicategory" (see https://plot.ly/python/reference/#layout-xaxis) but cannot combine date and log. What you can do is transform your dates to numerical values (using for example https://docs.python.org/3/library/datetime.html#datetime.datetime.timestamp) and set ticks manually to format them as dates (https://plot.ly/python/tick-formatting/#tickmode--array).

However, if you really want to squash your axis using a log scale will not be enough, you would need to remove a value close to the initial value for example.

ok thanks - have tried this and my plot is now appearing but my tick labels are 1.3b, 1.32b etc (the float version of the date time), even though I have set tick text as follows:

x2 = [datetime.timestamp(x) for x in x1]
x_tick_text = [datetime.fromtimestamp(x) for x in x2]
x_tick_values = [x for x in x2]
xaxis= dict(
                type='log',
                tickmode = 'array',
                ticktext=x_tick_text,
                tickvals=x_tick_values,

            ),

But you are right - the log scale is not looking as I was after and looks exactly the same as a linear scale. What do you mean by this?

you would need to remove a value close to the initial value for example.

1 Like

Hi Chris,

I’ve followed Emmanuelle’s advice, i.e. “transform your dates to numerical values and set ticks manually to format them as dates” and that did the trick:

The below code is not perfect but does work:

@app.callback(Output('yield-curves-graph', 'figure'),
             [Input('memory-storage', 'data')])
def updateYieldCurvesFigure(selectedYieldCurveNames):

    if selectedYieldCurveNames is None:
        raise PreventUpdate

    rates = dict()

    savedDataframe = pd.read_csv(DATA_PATH.joinpath("yield_curve.csv"))

    for selectedYieldCurveName in selectedYieldCurveNames:
        workingDataframe = savedDataframe.copy()
        workingDataframe = workingDataframe[workingDataframe['y'] == selectedYieldCurveName]
        del workingDataframe["x"]
        del workingDataframe["y"]
        rates[selectedYieldCurveName] = workingDataframe.iloc[0]

    shifts = [
        {'1 month': 30},
        {'3 months': 30 * 3},
        {'6 months': 30 * 6},
        {'1 year': 365},
        {'2 years': 365 * 2},
        {'3 years': 365 * 3},
        {'5 years': 365 * 5},
        {'7 years': 365 * 7},
        {'10 years': 365 * 10},
        {'20 years': 365 * 20},
        {'30 years': 365 * 30}
    ]

    timestamp = 0
    now = datetime.fromtimestamp(timestamp)

    timestamps = list()
    labels = list()

    for shift in shifts:
        key = shift.keys()[0]
        value = shift.values()[0]
        date = now + timedelta(days=value)
        timestamp = time.mktime(date.timetuple())
        timestamps.append(timestamp)
        labels.append(key)

    yieldCurvesFigure = {
        'data': [
            dict(
                x=timestamps,
                y=rates[selectedYieldCurveName],
                type='line',
                name=selectedYieldCurveName,
                orientation='h'
            ) for selectedYieldCurveName in selectedYieldCurveNames
        ],
        'layout': dict(
            plot_bgcolor=settings.colors['background'],
            xaxis=dict(
                type='log',
                title='Expiry',
                tickmode='array',
                tickvals=timestamps,
                ticktext=labels,
            ),
            yaxis=dict(
                type='linear',
                title='Treasury yields (%)'
            ),
            margin={'l': 50, 'b': 60, 't': 10, 'r': 20},
            legend={'x': 1, 'y': 1},
            hovermode='closest'
        )
    }

    return yieldCurvesFigure

Good luck.