How to Format Plotly Hover Dates: Show Month, Days, Year

Plotly & Dash charts are great, but often people struggle with their complexity. I solve plotly date hover format issues, as well as plotting out the dates on the xaxis.

Solving Plotly & Dash Hover Problems Display Dates as (M-D-Y),

Are you trying to fix or format the info / dates that pops up when hovering in Plotly?  

I recently had a pretty tough time trying to format plotly hover dates, which took me quite a bit of time to solve.  Once I got it, I wanted to share how I solved the issues, in case anyone else also has trouble searching online for good documentation on plotly hover mode.

In this article, I cover some issues people will run into when using Dash Plotly charts, with both Date formatting, and hovering data.  

The issue that I solved recently, were really 2 similar issues:

fixing hover issues in plotly dash format date to show days and months
  1.   I had multiple traces, and not all of the data on the chart was showing.

  2.   During Hover, the dates did not appear as days, only the year showed up. This makes financial data much harder to read.

I found the documentation confusing, and lacking the specifics I needed.  As a result, I had a hard time finding out how to format the hover template, so that it would show the full date, including the days.   

Once I found it, I decided to write this article to help others that might have trouble finding how to format plotly hover dates.  And that’s exactly what this article covers: ‘How to format plotly Dash hover templates to show dates with Month, Days, year


How to display Plotly hover information for all traces & charts?

In this section, I assume at this point, that you have built out a chart, and just need to change the format of the data on hover mode.  

The first problem I set out to solve, was how to show all my charts data, when hovering?

First, I found there were multiple ways to format how the hover labels worked, when I stumbled upon the hover and layout options on Dash.   Basically, there are several ‘hovermode’s that allow you to change up how you display your data:

The options are; 

  • “Hovermode closest” (default mode) this one is not ideal for multiple charts, as it only highlights 1 chart at a time, whichever is closest.
Plotly hovermode closest was not great, it didnt solve my problem for 2 charts, but it was the default option.
  • “Hovermode x” and “Hovermode y”

This starts looking a little better than the previous hover, especially if you have 2 charts.  This will draw a line on the x or y axis, and it will hover info for everything that crosses the line.  

However, this was still not formatted the way I wanted it, it wasn’t clean enough.

Hovermode x does allow you to hover data across an axis, but does not look that great or organized.
  •  “x unified” & “y unified”

This ended up being exactly what I was looking for, what this did, was it would unify everything on the chart, and bring it all together in clean looking box.  

In this next section, I’ll show you how I used x unified to fix issue number 1.  

Add hovermode = "x unified" to hover multiple charts data for an x-axis

After some trial and error, I gathered the easiest way to add this to your chart, was to use the ‘update_layout’ call.

To summarize what I did below:

  1. I created the Figure using Fig = go.Figure(), with a DataFrame I had of Bitcoin Prices.

  2. Then, because I was charting the price along with completely separate value (a BTC indicator), I created 2 subplots, trace1 and trace2.

  3. I used fig=make_subplots(specs=[[{‘secondary_y’: True}]]) so that I could overlay both charts on top of eachother.

  4. I then set both traces to fig, and set the 2nd trace Y axis on the right, using the fig.add_trace() method.  I then had to update the layout, to make the Bitcoin price Y axis a Logarithmic chart.

  5. Then, on line 51, I updated the layout to include the hovermode code, and set it to fig.update_layout(hovermode=”x unified”).

Note* I did not add the code hovermode=”x unified” to the previous ‘update_layout’ argument, although it could have been placed there, as you may have noticed.  I find this to be the least confusing way to demonstrate a code sample to people learning to code.

					    fig = go.Figure(
        data = [
                name = 'Bitcoin Price'
    # Create Subplots (Trace1, Trace2)
    trace1 = go.Scatter(x = csv_nupl['Years'], y = csv_nupl['Value'], name='BTC Value: ')
    trace2 = go.Scatter(x = df['Date'], y = df['Price'], line={'color': light_mode_lines, 'width': 0.5}, name = "BTC Price: ", hovertemplate="%{y}<br>Date: %{x}")

    fig = make_subplots(specs=[[{'secondary_y': True}]])


    minimum = date(2010, 7, 18),
    maximum = date(2023, 10, 26),
    x2 = csv_nupl['Value'].min() - 0.1,
    y2 = csv_nupl['Value'].max() + 0.1,

    #Update Subplots, overlaying Y, Log Chart
            range=[x2, y2],
        xaxis = dict(
            range=[minimum, maximum],
            dtick = 30557600000,
        autosize = True,
            title='Bitcoin Price',

    fig.update_layout(hovermode="x unified")

    fig_nupl.add_trace(go.Scatter(x = csv_nupl['Years'], y = csv_nupl['Value'].where(csv_nupl.Value > 0.68), line={'color': '#1c8fed', 'width': 1.3}, name='SELL, ', hoverinfo='skip'))
    fig_nupl.add_trace(go.Scatter(x = csv_nupl['Years'], y = csv_nupl['Value'].where((csv_nupl.Value >= 0.46) & (csv_nupl.Value <= 0.75)), line={'color': '#1CEC79', 'width': 1.2}, name='HODL, ', hoverinfo='skip'))
    fig_nupl.add_trace(go.Scatter(x = csv_nupl['Years'], y = csv_nupl['Value'].where((csv_nupl.Value >= 0.199) & (csv_nupl.Value <= 0.52)), line={'color': '#FEDB00', 'width': 1.2}, name='HODL, ', hoverinfo='skip'))
    fig_nupl.add_trace(go.Scatter(x = csv_nupl['Years'], y = csv_nupl['Value'].where((csv_nupl.Value >= -0.145) & (csv_nupl.Value <= 0.3157)), line={'color': '#ff9451', 'width': 1.2}, name='Buy, ', hoverinfo='skip'))
    fig_nupl.add_trace(go.Scatter(x = csv_nupl['Years'], y = csv_nupl['Value'].where(csv_nupl.Value <= 0.05), line={'color': '#ff6464', 'width': 1.18}, name='Buy, ', hoverinfo='skip'))
    fig_nupl.add_trace(go.Scatter(x = csv_nupl['Years'], y = csv_nupl['Value'].where(csv_nupl.Value < -0.33), line={'color': '#FB3640', 'width': 1.15}, name='Buy ', hoverinfo='skip'))

    # Place Legend and modify layout 
    fig_nupl.layout.legend.itemsizing = 'constant'

    fig_nupl.layout.template = 'plotly_white'

How to Display Dates as (M-D-Y): hovering in dash & Plotly

The 2nd issue I solved, was an issue with how the dates were formatted in Plotly hovermode.  This issue was a little more complex, as it came from multiple parts of the code.   I had set the xaxis tic marks to the value of “30557600000” to serve the purpose of only showing the year for the longer term charts.

					update_layout(xaxis = dict(dtick="30557600000"))
Show only the years, with no months or days in the xaxis with dtick="30557600000"

Luckily, this is a super simple issue to solve, if you know where to look.  Unfortunately, I had not had much luck with Datetime in Python.

I had largely avoided Python Datetime, because of the confusion over Datetime.Datetime & not working depending on how Datetime was imported.   (I know now the answer is to ‘import Datetime as dt’, and use dt instead of Datetime, as it (Datetime) is both a method and an object, and Python will shit a brick).  But at the time, it frustrated me beyond belief.  

Which meant, this problem took me a while to solve.  I looked everywhere, and it seemed like nothing worked.  There was so much advice to do all these different tricks that only work in some scenarios.  Then on the Plotly documentation, I found it extremely hard to read and understand, as no scenarios specifically fit my issue.   

The answer is to use hovertemplate.


					hovertemplate="$%{y}<br>Date: %{x}"

Hover template allows you to completely customize the hover data with custom messages.   I used this code to first show the Bitcoin Value of the indicator I had, then the BTC Price, and the Date, with M-D-Y.  

In the above code, I started with ‘$’ to show the dollar sign in front of Bitcoins Price, the %{y} value. 

<br> for a line break, and then I wrote ‘Date:  ‘ on the new line created by <br>, followed by the x-axis value for date, %{x}.  

You can use this template to customize your hover information data with any custom text you want.  

Now that I fixed the hoverdata, and formatted it the way I wanted to, I still needed to fix the date issue.  

This was done by using another xaxis=dict() component, called tickformat.  


Tickformat is amazing, as it lets me set just the year at the bottom of the chart.  I wanted to hover the M-D-Y, but didnt want to take up too much room on the xaxis.  It took me a long time to find this one, possibly because of a lack of knowledge in what to search for.  

Once I found it, it was super simple to fix.  tickformat gets added to your ‘update_layout’ statement, inside of the ‘xaxis=dict()’ statement.  

            range=[x1, y1],
        xaxis = dict(
            range=[past_nupl, future_nupl],
            dtick = 30557600000,
        autosize = True, #width = 1080, height = 620,
            title='Bitcoin Price',

So far, the dates on the bottom of the chart were looking better than ever, thanks to tickformat.  The hover template itself was coming together, thanks to hovermode=”x unified”, that organized everything in a clean box layout, and hovertemplate, allowing me to write custom text.  The only thing I needed to fix at this point, was how to keep just years at the bottom, but on hover, to show the full date with the month, days, and year.  

This last piece of the puzzle was solved using ‘xhoverformat’.


While hovermode=”x unified”, tickformat, dtick were all added to the update_layout statement, hovertemplate and xhoverformat are both added directly to the trace itself.  

I was specifically the go.scatter methods, and not plotly express:  fig = go.Figure() and trace1 = go.Scatter().   Because of this, I had to default to using xhoverformat.   

If you are using scattergl instead, or  fig = px.line(df, val1, val2), then you would instead use the hover_data statement, as shown below.  

hover_data={"date": "|%B %d, %Y"},

Here’s what the code looked like after I added xhoverformat and hovertemplate together:

					    #Create Subplots (Trace1, Trace2)
    trace1 = go.Scatter(x = csv_nupl['Years'], y = csv_nupl['Value'], name='BTC Value', xhoverformat="%b-%d-%Y", hovertemplate="%{y}<br>Date:  %{x}")
    trace2 = go.Scatter(x = df['Date'], y = df['Price'], line={'color': light_mode_lines, 'width': 0.5}, name = "BTC Price", hovertemplate="$%{y}")
    fig = make_subplots(specs=[[{'secondary_y': True}]])

This ends up being a perfect example, because I had to use hover template in each trace (Trace2 showed the Bitcoin Price I needed, so I used ‘hovertemplate=”$%{y}”, and notice I only used xhoverformat once.  I only needed the dates values once, even though they exist in both traces.

Trace1 shows BTC Value: and Date: while Trace2 shows BTC Price: .

xhoverformat needs to be attached to the dataframe that you want the data to show up for, same goes for hovertemplate.

With this final solution, the hover table looks much better!  

I hope you enjoyed this article on how to format plotly hover dates, and I hope it helped you at least somewhat.  

After applying several fixes to plotly hover format, the dates are now perectly showing up as I want the to.