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):