Change Font Size While Zooming On Plotly Graph

I have a lot of information being displayed on a heatmap so as a result my font size for the annotations is very small. I’m wondering if anyone may know of a way to increase the font size dynamically when zooming in further so it is more readable. I know that when using the regular “text”, “texttemplate”, and “textfont” arguments in go.Figure(data=go.Heatmap()) simply leaving out the “textfont” argument will adjust the size of the font dynamically. But I had to do some work-arounds in order to have my annotations appear the way that they do, and I am now having trouble figuring out how to have the font change dynamically with my current code. Does anyone know of a solution or work-around?

truck_df output:

                            Truck        Date  VIPR Data  Viriciti Data
140726  231_28_KAL_T2E_KIT_353604  2022-06-10       True          False
140727  231_28_KAL_T2E_KIT_353604  2022-06-11       True          False
140728  231_28_KAL_T2E_KIT_353604  2022-06-12       True          False
140729  231_28_KAL_T2E_KIT_353604  2022-06-13       True          False
140730  231_28_KAL_T2E_KIT_353604  2022-06-14       True          False
140731  231_28_KAL_T2E_KIT_353604  2022-06-15       True          False
140732  231_28_KAL_T2E_KIT_353604  2022-06-16       True          False
140733  231_28_KAL_T2E_KIT_353604  2022-06-17       True          False
140734  231_28_KAL_T2E_KIT_353604  2022-06-18       True          False
140735  231_28_KAL_T2E_KIT_353604  2022-06-19       True          False
140736  231_28_KAL_T2E_KIT_353604  2022-06-20       True          False
140737  231_28_KAL_T2E_KIT_353604  2022-06-21       True          False
140738  231_28_KAL_T2E_KIT_353604  2022-06-22      False          False
140739  231_28_KAL_T2E_KIT_353604  2022-06-23      False          False
140740  231_28_KAL_T2E_KIT_353604  2022-06-24      False          False
140741  231_28_KAL_T2E_KIT_353604  2022-06-25      False          False
140742  231_28_KAL_T2E_KIT_353604  2022-06-26      False          False
140743  231_28_KAL_T2E_KIT_353604  2022-06-27      False          False
140744  231_28_KAL_T2E_KIT_353604  2022-06-28      False          False
140745  231_28_KAL_T2E_KIT_353604  2022-06-29      False          False
140746  231_28_KAL_T2E_KIT_353604  2022-06-30      False          False
140747  231_28_KAL_T2E_KIT_353604  2022-07-01      False          False
140748  231_28_KAL_T2E_KIT_353604  2022-07-02      False          False
140749  231_28_KAL_T2E_KIT_353604  2022-07-03      False          False
140750  231_28_KAL_T2E_KIT_353604  2022-07-04      False          False
140751  231_28_KAL_T2E_KIT_353604  2022-07-05       True          False
140752  231_28_KAL_T2E_KIT_353604  2022-07-06       True          False
140753  231_28_KAL_T2E_KIT_353604  2022-07-07       True          False
140754  231_28_KAL_T2E_KIT_353604  2022-07-08       True          False
140755  231_28_KAL_T2E_KIT_353604  2022-07-09       True          False
140756  231_28_KAL_T2E_KIT_353604  2022-07-10       True          False
140757  231_28_KAL_T2E_KIT_353604  2022-07-11       True          False
140758  231_28_KAL_T2E_KIT_353604  2022-07-12       True          False
140759  231_28_KAL_T2E_KIT_353604  2022-07-13       True          False
140760  231_28_KAL_T2E_KIT_353604  2022-07-14       True          False
140761  231_28_KAL_T2E_KIT_353604  2022-07-15       True          False
140762  231_28_KAL_T2E_KIT_353604  2022-07-16       True          False
140763  231_28_KAL_T2E_KIT_353604  2022-07-17       True          False
140764  231_28_KAL_T2E_KIT_353604  2022-07-18       True          False
140765  231_28_KAL_T2E_KIT_353604  2022-07-19       True          False
140766  231_28_KAL_T2E_KIT_353604  2022-07-20       True          False
140767  231_28_KAL_T2E_KIT_353604  2022-07-21       True          False
140768  231_28_KAL_T2E_KIT_353604  2022-07-22      False          False
140769  231_28_KAL_T2E_KIT_353604  2022-07-23      False          False
140770  231_28_KAL_T2E_KIT_353604  2022-07-24       True          False
140771  231_28_KAL_T2E_KIT_353604  2022-07-25       True          False
140772  231_28_KAL_T2E_KIT_353604  2022-07-26       True          False
140773  231_28_KAL_T2E_KIT_353604  2022-07-27       True          False
140774  231_28_KAL_T2E_KIT_353604  2022-07-28       True          False
140775  231_28_KAL_T2E_KIT_353604  2022-07-29       True          False
140776  231_28_KAL_T2E_KIT_353604  2022-07-30       True          False
140777  231_28_KAL_T2E_KIT_353604  2022-07-31       True          False
140778  231_28_KAL_T2E_KIT_353604  2022-08-01       True          False
140779  231_28_KAL_T2E_KIT_353604  2022-08-02       True          False
140780  231_28_KAL_T2E_KIT_353604  2022-08-03       True          False
140781  231_28_KAL_T2E_KIT_353604  2022-08-04       True          False
140782  231_28_KAL_T2E_KIT_353604  2022-08-05       True          False
140783  231_28_KAL_T2E_KIT_353604  2022-08-06       True          False
140784  231_28_KAL_T2E_KIT_353604  2022-08-07       True          False
140785  231_28_KAL_T2E_KIT_353604  2022-08-08       True          False
140786  231_28_KAL_T2E_KIT_353604  2022-08-09       True          False
140787  231_28_KAL_T2E_KIT_353604  2022-08-10       True          False
140788  231_28_KAL_T2E_KIT_353604  2022-08-11       True          False
140789  231_28_KAL_T2E_KIT_353604  2022-08-12       True          False
140790  231_28_KAL_T2E_KIT_353604  2022-08-13       True          False
140791  231_28_KAL_T2E_KIT_353604  2022-08-14       True          False
140792  231_28_KAL_T2E_KIT_353604  2022-08-15       True          False
140793  231_28_KAL_T2E_KIT_353604  2022-08-16       True          False
140794  231_28_KAL_T2E_KIT_353604  2022-08-17       True          False
140795  231_28_KAL_T2E_KIT_353604  2022-08-18       True          False
140796  231_28_KAL_T2E_KIT_353604  2022-08-19       True          False
140797  231_28_KAL_T2E_KIT_353604  2022-08-20       True          False
140798  231_28_KAL_T2E_KIT_353604  2022-08-21       True          False
140799  231_28_KAL_T2E_KIT_353604  2022-08-22       True          False
140800  231_28_KAL_T2E_KIT_353604  2022-08-23       True          False
140801  231_28_KAL_T2E_KIT_353604  2022-08-24       True          False
140802  231_28_KAL_T2E_KIT_353604  2022-08-25       True          False
140803  231_28_KAL_T2E_KIT_353604  2022-08-26       True          False
140804  231_28_KAL_T2E_KIT_353604  2022-08-27       True          False
140805  231_28_KAL_T2E_KIT_353604  2022-08-28       True          False
140806  231_28_KAL_T2E_KIT_353604  2022-08-29      False          False
140807  231_28_KAL_T2E_KIT_353604  2022-08-30       True          False
140808  231_28_KAL_T2E_KIT_353604  2022-08-31      False          False
140809  231_28_KAL_T2E_KIT_353604  2022-09-01      False          False
140810  231_28_KAL_T2E_KIT_353604  2022-09-02      False          False
140811  231_28_KAL_T2E_KIT_353604  2022-09-03      False          False
140812  231_28_KAL_T2E_KIT_353604  2022-09-04      False          False
140813  231_28_KAL_T2E_KIT_353604  2022-09-05       True          False
140814  231_28_KAL_T2E_KIT_353604  2022-09-06      False          False
140815  231_28_KAL_T2E_KIT_353604  2022-09-07      False          False
140816  231_28_KAL_T2E_KIT_353604  2022-09-08      False          False
140817  231_28_KAL_T2E_KIT_353604  2022-09-09      False          False
140818  231_28_KAL_T2E_KIT_353604  2022-09-10      False          False
140819  231_28_KAL_T2E_KIT_353604  2022-09-11      False          False
140820  231_28_KAL_T2E_KIT_353604  2022-09-12      False          False
140821  231_28_KAL_T2E_KIT_353604  2022-09-13      False          False
140822  231_28_KAL_T2E_KIT_353604  2022-09-14      False          False
140823  231_28_KAL_T2E_KIT_353604  2022-09-15      False          False
140824  231_28_KAL_T2E_KIT_353604  2022-09-16       True          False
140825  231_28_KAL_T2E_KIT_353604  2022-09-17       True          False
140826  231_28_KAL_T2E_KIT_353604  2022-09-18       True          False
140827  231_28_KAL_T2E_KIT_353604  2022-09-19       True          False
140828  231_28_KAL_T2E_KIT_353604  2022-09-20       True          False
140829  231_28_KAL_T2E_KIT_353604  2022-09-21       True          False
140830  231_28_KAL_T2E_KIT_353604  2022-09-22      False          False
140831  231_28_KAL_T2E_KIT_353604  2022-09-23      False          False
140832  231_28_KAL_T2E_KIT_353604  2022-09-24      False          False
140833  231_28_KAL_T2E_KIT_353604  2022-09-25      False          False
140834  231_28_KAL_T2E_KIT_353604  2022-09-26       True          False
140835  231_28_KAL_T2E_KIT_353604  2022-09-27       True          False
140836  231_28_KAL_T2E_KIT_353604  2022-09-28       True          False
140837  231_28_KAL_T2E_KIT_353604  2022-09-29       True          False
140838  231_28_KAL_T2E_KIT_353604  2022-09-30       True          False
140839  231_28_KAL_T2E_KIT_353604  2022-10-01       True          False
140840  231_28_KAL_T2E_KIT_353604  2022-10-02       True          False
140841  231_28_KAL_T2E_KIT_353604  2022-10-03       True          False
140842  231_28_KAL_T2E_KIT_353604  2022-10-04       True          False
140843  231_28_KAL_T2E_KIT_353604  2022-10-05       True          False

Code:

import plotly.graph_objects as go
import numpy as np
import pandas as pd
from datetime import date, datetime, timedelta, time
import dash
from dash import dcc, html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
from numpy import NaN

try:
    # Filter DataFrame to only the rows that contain data for the selected truck
    truck_df = df[df['Truck']==truck]
    # Subset the DataFrame to isolate the date column
    truck_date_df = pd.to_datetime(truck_df['Date']).dt.date
    # Convert the 'vipr_bool' column of the DataFrame into a list
    vipr_bool = list(truck_df['VIPR Data'])
    # Convert 'False' to '0'
    vipr_bool = [0 if item == False else item for item in vipr_bool]
    # Convert 'True' to '1'
    vipr_bool = [1 if item == True else item for item in vipr_bool]
except Exception as e:
    print('-' * 40)
    print('update_plot ERROR')
    print(e)
    print('-' * 40)

try:
    # Filter the list to find the first 'True' value
    vipr_first_true = vipr_bool.index(1)
    # Reverse the list
    vipr_first_true_reversed = vipr_bool[::-1]
    # Find the index position of the last 'True'
    vipr_first_index_reversed = vipr_first_true_reversed.index(1)
    # Subtract 1 & the index position of the last 'True' from the length of 'vipr_bool' to obtain the index of the last 'True'
    vipr_last_true = len(vipr_bool)-1-vipr_first_index_reversed
    # Finds the row # and date of the first 'True' value
    vipr_low = truck_date_df[vipr_first_true:vipr_first_true+1]
    # Removes the index row # and isolates only the date
    vipr_low = vipr_low.iloc[0]
    # Finds the row # and date of the last 'True' value
    vipr_high = truck_date_df[vipr_last_true:vipr_last_true+1]
    # Removes the index row # and isolates only the date
    vipr_high = vipr_high.iloc[0]
    # Convert all '0' values to 'None', leaving the '1' values
    vipr_ones = [None if v!=1 else v for v in vipr_bool]
    # Convert all '1' values to 'None' leaving the '0' values
    vipr_zeros = [None if v!=0 else v for v in vipr_bool]
except Exception as e:
    print('VIPR')
    print(e)
    vipr_low = date(2014, 1, 1)
    vipr_high = date.today()
    vipr_ones = [0] * len(vipr_bool)
    vipr_zeros = [0] * len(vipr_bool)

try:
    # Assign vipr_low & vipr_high to low_range & high_range
    low_range = vipr_low
    high_range = vipr_high + timedelta(days=1)
except Exception as e:
    print(e)
    high_range = vipr_high

try:
    # Initialize figure for plotly graph object
    fig = go.Figure()
except Exception as e:
    print('-' * 40)
    print('fig initialization ERROR')
    print(e)
    print('-' * 40)

try:
    if 1 in vipr_bool:
        # Add a trace to the heatmap containing all of the '1' values along with a legend marker
        fig.add_trace(go.Heatmap(
                x=truck_date_df,
                y=[''],
                z=[vipr_ones],
                name='= Data Found',
                colorscale=[(0.00, "#DA291C"), (1.0, "#DA291C")],
                showscale=False,
                showlegend=True,
                hovertemplate='<i><b>Date</i>: %{x}<extra></extra>',
                xgap=1,
                xperiod=86400000,
                xperiodalignment='middle',
                visible=True
            )
        )
    else:
        # Add a trace to the heatmap containing all of the '1' values along with a legend marker
        fig.add_trace(go.Heatmap(
                x=truck_date_df,
                y=[''],
                z=[vipr_ones],
                name='= Data Found',
                colorscale=[(0.00, "#DA291C"), (1.0, "#DA291C")],
                showscale=False,
                showlegend=True,
                hovertemplate='<i><b>Date</i>: %{x}<extra></extra>',
                visible=True
            )
        )
    fig['layout'].update(plot_bgcolor='white')

except Exception as e:
    print(e)
    
try:
    if 1 in vipr_bool:
        # Add a trace to the heatmap containing all of the '0' values along with a legend marker
        fig.add_trace(go.Heatmap(
                x=truck_date_df,
                y=[''],
                z=[vipr_zeros],
                name='= Data Not Found',
                colorscale=[(0.00, "#D3D3D3"), (1.0, "#D3D3D3")],
                showscale=False,
                showlegend=True,
                hovertemplate='<i><b>Date</i>: %{x}<extra></extra>',
                xgap=1,
                xperiod=86400000,
                xperiodalignment='middle',
                visible=True
            )
        )
    else:
        # Add a trace to the heatmap containing all of the '0' values along with a legend marker
        fig.add_trace(go.Heatmap(
                x=truck_date_df,
                y=[''],
                z=[vipr_zeros],
                name='= Data Not Found',
                colorscale=[(0.00, "#D3D3D3"), (1.0, "#D3D3D3")],
                showscale=False,
                showlegend=True,
                hovertemplate='<i><b>Date</i>: %{x}<extra></extra>',
                visible=True
            )
        )
except Exception as e:
    print(e)
    # Add a trace to the heatmap containing all of the '0' values along with a legend marker
    fig.add_trace(go.Heatmap(
            x=truck_date_df,
            y=[''],
            z=[vipr_zeros],
            name='= Data Not Found',
            colorscale=[(0.00, "#D3D3D3"), (1.0, "#D3D3D3")],
            showscale=False,
            showlegend=True,
            hovertemplate='<i><b>Date</i>: %{x}<extra></extra>'
        )
    )

try:
    # Update the figure's x-axis/y-axis titles and the x-axis range
    fig.update_layout(title=go.layout.Title(text='<b>Data for Truck: </b>' + str(truck)),
                            xaxis_title='<b>Date</b>',
                            yaxis_title='',
                            xaxis_range=[low_range, high_range]
                            )
except Exception as e:
    print(e)
    # Update the figure's x-axis/y-axis titles and the x-axis range
    fig.update_layout(title=go.layout.Title(text='<b>Data for Truck: </b>' + str(truck)),
                            xaxis_title='<b>Date</b>',
                            yaxis_title='',
                            xaxis_range=[date(2014, 1, 1), date(date.today())]
                            )

try:
    fig.update_layout(legend=dict(
        orientation='h',
        yanchor="bottom",
        y=1.02,
        xanchor="right",
        x=1
    ))
except Exception as e:
    print(e)

try:
    # Make a list containing only dates where data exists. Where data does not exist, 'None' is entered
    date_data = truck_df.apply(lambda x: None if x['VIPR Data']==False else x['Date'], axis=1).tolist()
except Exception as e:
    print(e)
    date_data = []

try:
    date_data = [datetime.strptime(date, '%Y-%m-%d') for date in date_data if date != None]
    date_data = [z + timedelta(hours=12) for z in date_data]
    date_data = [str(y) for y in date_data]

    fig.update_layout(annotations=[
        go.layout.Annotation(
            x=d,
            y=0.5,
            yref='paper',
            text='' if d == None else d.split('-')[2].lstrip('0').removesuffix('12:00:00'), # Extracts only the day without the leading 0 from the date, if 'None' enter a blank
            # font_size=10,
            font_color='#000000',
            textangle=-90,
            valign='top',
            xshift=-1,
            showarrow=False) for d in date_data], autosize=True)

    fig.update_xaxes(showgrid=True, gridwidth=2, gridcolor='white', type='date',
        rangeslider_visible=False, ticks='outside', tickson='boundaries', ticklen=20,
        tickformatstops = [
            dict(dtickrange=[None, 1000], value="%H:%M:%S.%L\n%b %e %Y"),
            dict(dtickrange=[1000, 60000], value="%H:%M:%S\n%b %e %Y"),
            dict(dtickrange=[60000, 3600000], value="%H:%M\n%b %e %Y"),
            dict(dtickrange=[3600000, 86400000], value="%H:%M\n%b %e %Y"),
            dict(dtickrange=[86400000, 604800000], value="%b %e (%a)\n%Y"),
            dict(dtickrange=[604800000, "M1"], value="%b %e (%a)\n%Y"),
            dict(dtickrange=["M1", "M12"], value="%B\n%Y"),
            dict(dtickrange=["M12", None], value="%Y")
        ])

    fig.update_yaxes(showgrid=True, gridwidth=2, gridcolor='white')
except Exception as e:
    print(e)

fig.show()

Output:


Output (zoomed in):

Desired output (zoomed in):