3

I'm trying to display a horizontal bar chart with dates on the x-axis, but can't seem a way to do that although the x-values are dates of type string. As you can see below, the numbers that occur as ticklabels have to be a summation of some sort, but I'm not sure exactly what. How can you change the example below to get dates as ticklabels?

Plot 1:

enter image description here

Code:

# imports
import numpy as np
import pandas as pd
import plotly.express as px
from datetime import datetime

# data
np.random.seed(1)
cols=list('ABCDE')
df = pd.DataFrame(np.random.randint(0,2,size=(5, len(cols))), columns=cols)
drng=pd.date_range(datetime(2020, 1, 1).strftime('%Y-%m-%d'), periods=df.shape[0]).tolist()
df['date']=[d.strftime('%Y-%m-%d') for d in drng]
dfm=pd.melt(df, id_vars=['date'], value_vars=df.columns[:-1])

# plotly express
fig = px.bar(dfm, x="date", y="variable", color='value', orientation='h',
             hover_data=["date"],
             height=400,
             color_continuous_scale=['blue', 'teal'],
             title='Custom date ticklabels for vertical bar plot',
             template='plotly_white',
            )

fig.update_traces(showlegend=False)
fig.update(layout_coloraxis_showscale=False)
fig.show()

What I've tried:

I've tried different combinations for tickmode, tickvals and ticktext for xaxis=dict() in fig.update_layout, alas with completely useless results.

Attempt 2: ticktext

Set tickvals=df['date']

fig.update_layout(yaxis=dict(title=''),
                  xaxis=dict(title='',
                  gridcolor='grey',
                  #tickmode= 'array',
                  #tickmode= 'linear',
                  #tick0= 2220,
                  #dtick=200,
                  #tickvals= [2020, 2040],
                  ticktext = df['date'])
                 )

Plot 2:

Same as before:

enter image description here

Attempt 3: ticktext & dtick

To my amazement, setting dtick to some arbitrary value gives you the plot below.

fig.update_layout(yaxis=dict(title=''),
                  xaxis=dict(title='',
                  gridcolor='grey',
                  #tickmode= 'array',
                  #tickmode= 'linear',
                  tick0= 2050,
                  dtick=2,
                  #tickvals= [2020, 2040],
                  ticktext = df['date'])
                 )

Plot 3:

enter image description here

Still amazingly useless, but now the ticks at least looks like dates, although we're looking at a value that represents a timestamp in 2008 and the source data is 2020...

Attempt 4: tickvals and ticktext

fig.update_layout(yaxis=dict(title=''),
                  xaxis=dict(title='',
                  gridcolor='grey',
                  #tickmode= 'array',
                  #tickmode= 'linear',
                  tick0= 2050,
                  #dtick=2,
                  tickvals= [2050, 2100, 2150, 2200],
                  ticktext = df['date'])
                 )

Plot 4:

From the looks of if, this is exactly what I'm looking for:

enter image description here

But this is equally useless like the other attempts, since we have to specify tickvals= [2050, 2100, 2150, 2200]. If we change the period, these values will have to be re-specified, and that's not very flexible. Of course, if we somehow could retrieve the default tickvalues used by plotly, we could easily replace them with the dates in the dataset. But that seems to still be impossible according to the answer to the post Plotly: How to retrieve values for major ticks and gridlines?

I'm at a complete loss here, and baffled by the uselessness of my attempts, so any other suggestions would be great!

vestland
  • 55,229
  • 37
  • 187
  • 305
  • I'm confused about what you're trying to do here... you're calling this a "vertical bar plot" although `orientation` is set to `h` and the x value is a date. – nicolaskruchten Jan 07 '20 at 03:38
  • 1
    Specifying the length of a bar chart as a date is kind of fraught: there's no obvious zero! In this case the bars start at `1970-01-01` (the beginning of the Unix epoch) and get added on horizontally based on the delta so the first one goes to `2020-01-01` (a duration of 50 years) and the second one does about the same so it goes another 50 years to 2070, and the third one goes to 2120 etc. That's why your ticks show up as 2050, 2100 etc. – nicolaskruchten Jan 07 '20 at 03:45
  • Ah I see, you're trying to answer https://stackoverflow.com/questions/59602653/data-availability-chart-in-python ... yeah to do this you will likely want to set the `base` of each bar *and* you'll have to make the `x` value of each bar the date which corresponds to 1970-01-01T00:00:00 + the timespan you want the bar length to be. Gross but true. – nicolaskruchten Jan 07 '20 at 03:49
  • You could also consider using https://plot.ly/python/gantt/ – nicolaskruchten Jan 07 '20 at 03:50
  • @nicolaskruchten Thank you for taking a look at this. Yeah, I was trying to provide an complete answer to [Data Availability Chart in Python](https://stackoverflow.com/questions/59602653/data-availability-chart-in-python) – vestland Jan 07 '20 at 08:07
  • @nicolaskruchten And yes, you're right that this is a horizontal and not a vertical bar chart. I did consider using a gantt chart, but I really liked the simplicity that this setup provided. Aside from the dates of course. Any chance that we'll see a possible solution to [How to retrieve values for major ticks and gridlines? ](https://stackoverflow.com/questions/55118898/plotly-how-to-retrieve-values-for-major-ticks-and-gridlines) in the near future? – vestland Jan 07 '20 at 08:08
  • 1
    Another approach here would be to use really fat line segments with start and end dates... – nicolaskruchten Jan 07 '20 at 17:30

1 Answers1

4

You must activate tickmode to 'array' and then define tickvals and ticktext, like:

tickmode = 'array',
tickvals = [2050, 2100, 2150, 2200],
ticktext = df['date'])
סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68