6. Creating Heat maps#
Heat map charts are a versatile data visualization technique that uses color to represent values in a two-dimensional matrix or grid. Each cell in the heat map corresponds to a combination of two variables, and the color intensity or hue indicates the magnitude of the data point. This approach makes it easy to identify patterns, trends, and outliers across large datasets. Heat maps are particularly useful when working with data that has a natural tabular structure, such as correlation matrices, sales performance by product and region, or time-series data by categories.
One powerful application of heat maps is in illustrating yield curves’ term structures over time. In this context, the x-axis could represent time (e.g., months or years), while the y-axis shows the maturity periods of bonds (e.g., 3 months, 2 years, 10 years). The color in each cell would reflect the yield for a given maturity at a specific time, allowing analysts to quickly observe changes in interest rate environments and identify trends like steepening or flattening yield curves. This makes heat maps an invaluable tool for financial professionals seeking insights into interest rate dynamics.
Despite their utility, heat maps should be avoided in cases where precise numerical values are critical, as the reliance on color gradation can obscure exact measurements. They are also less effective when the dataset is small or lacks meaningful variability, as the visualization may appear sparse or uninformative. Additionally, choosing an inappropriate color scale or failing to consider colorblind accessibility can lead to misinterpretation. Heat maps work best when the goal is to identify high-level patterns and trends across large datasets, rather than focusing on detailed or highly specific comparisons.
Getting ready#
For this recipe we will use data from the Federal Reserve Economic Data which is saved in a spreadsheet
Import the
pandas
Python library aspd
import pandas as pd
Use the function
read_csv
to read the data. Make sure you set the argumentparse_dates
asTrue
to guarantee that the dates are being parsed correctly
data = pd.read_csv('data/data_fed_yc.csv', parse_dates=True).set_index('DATE')
Inspect the data by calling the method
head
on theDataFrame
data.head()
30-year | 10-year | 5-year | 3-year | 2-year | 1-year | 6-month | 3-month | 1-month | |
---|---|---|---|---|---|---|---|---|---|
DATE | |||||||||
1990-01-31 | 8.26 | 8.21 | 8.12 | 8.13 | 8.09 | 7.92 | 7.96 | 7.90 | NaN |
1990-02-28 | 8.50 | 8.47 | 8.42 | 8.39 | 8.37 | 8.11 | 8.12 | 8.00 | NaN |
1990-03-31 | 8.56 | 8.59 | 8.60 | 8.63 | 8.63 | 8.35 | 8.28 | 8.17 | NaN |
1990-04-30 | 8.76 | 8.79 | 8.77 | 8.78 | 8.72 | 8.40 | 8.27 | 8.04 | NaN |
1990-05-31 | 8.73 | 8.76 | 8.74 | 8.69 | 8.64 | 8.32 | 8.19 | 8.01 | NaN |
Transpose the
DataFrame
to have the tenors as indices and the dates as columsn. This will facilitate making the heatmap
data = data.T
data = data.iloc[::-1]
data.head()
DATE | 1990-01-31 | 1990-02-28 | 1990-03-31 | 1990-04-30 | 1990-05-31 | 1990-06-30 | 1990-07-31 | 1990-08-31 | 1990-09-30 | 1990-10-31 | ... | 2023-07-31 | 2023-08-31 | 2023-09-30 | 2023-10-31 | 2023-11-30 | 2023-12-31 | 2024-01-31 | 2024-02-29 | 2024-03-31 | 2024-04-30 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1-month | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 5.39 | 5.54 | 5.53 | 5.57 | 5.53 | 5.54 | 5.54 | 5.49 | 5.51 | 5.48 |
3-month | 7.90 | 8.00 | 8.17 | 8.04 | 8.01 | 7.99 | 7.87 | 7.69 | 7.60 | 7.40 | ... | 5.49 | 5.56 | 5.56 | 5.60 | 5.52 | 5.44 | 5.45 | 5.44 | 5.47 | 5.44 |
6-month | 7.96 | 8.12 | 8.28 | 8.27 | 8.19 | 8.05 | 7.92 | 7.77 | 7.70 | 7.53 | ... | 5.53 | 5.54 | 5.51 | 5.57 | 5.44 | 5.34 | 5.21 | 5.28 | 5.36 | 5.38 |
1-year | 7.92 | 8.11 | 8.35 | 8.40 | 8.32 | 8.10 | 7.94 | 7.78 | 7.76 | 7.55 | ... | 5.37 | 5.37 | 5.44 | 5.42 | 5.28 | 4.96 | 4.79 | 4.92 | 4.99 | 5.14 |
2-year | 8.09 | 8.37 | 8.63 | 8.72 | 8.64 | 8.35 | 8.16 | 8.06 | 8.08 | 7.88 | ... | 4.83 | 4.90 | 5.02 | 5.07 | 4.88 | 4.46 | 4.32 | 4.54 | 4.59 | 4.87 |
5 rows × 412 columns
How to do it#
Import the
plotly.graph_objects
module asgo
import plotly.graph_objects as go
Make a minimal heat-map using the function
Heatmap
from thego
module. You need to specify the following three key arguments
x
y
z
The data that describes the heatmap value-to-color mapping is set in z. Data in z can either be a 2D list of values (ragged or not) or a 1D array of values. In the case where z is a 2D list, say that z has N rows and M columns. Then, by default, the resulting heatmap will have N partitions along the y axis and M partitions along the x axis. In other words, the i-th row/ j-th column cell in z is mapped to the i-th partition of the y axis (starting from the bottom of the plot) and the j-th partition of the x-axis (starting from the left of the plot). This behavior can be flipped by using transpose.
Moreover, x (y) can be provided with M or M+1 (N or N+1) elements. If M (N), then the coordinates correspond to the center of the heatmap cells and the cells have equal width. If M+1 (N+1), then the coordinates correspond to the edges of the heatmap cells. In the case where z is a 1D list, the x and y coordinates must be provided in x and y respectively to form data triplets.
fig = go.Figure(data=[go.Heatmap(x=data.columns,
y=data.index,
z=data.values,
)])
fig.show()
Change the color palette in the Heatmap by using the argument
colorscale
. In this case, we specify it to ‘ice’ but it can be the bame of any colorscale available inPlotly
fig = go.Figure(data=[go.Heatmap(z=data.values,
x=data.columns,
y=data.index,
colorscale='ice',
)])
fig.show()
Reverse the way the color scale is mapped into the
z
values by setting the argumentreversescale
toTrue
. In this case, this case the effect of mapping lighter (darker) blue tones to lower (higher) percentage points.
fig = go.Figure(data=[go.Heatmap(z=data.values,
x=data.columns,
y=data.index,
colorscale='ice',
reversescale=True,
)])
fig.show()
Customise the information available in the hover box as well as its format by using the argument
hovertemplate
. Note that we are using HTML elements to define the formatting
fig = go.Figure(data=[go.Heatmap(z=data.values,
x=data.columns,
y=data.index,
colorscale='ice',
reversescale=True,
hovertemplate='<br>Date: %{x}' + \
'<br>Maturity: %{y}' + \
'<br>Yield: %{z:.2f}<extra></extra>',
)])
fig.show()
Use the method
update_layout
to customise the following elements in the Figure object
title
title_x
title_font
width
andheight
template
fig = go.Figure(data=[go.Heatmap(z=data.values,
x=data.columns,
y=data.index,
colorscale='ice',
reversescale=True,
hovertemplate='<br>Date: %{x}' + \
'<br>Maturity: %{y}' + \
'<br>Yield: %{z:.2f}<extra></extra>',
)])
fig.update_layout(title='A Heatmap of the Yield Curve Evolution over Time',
title_x=0.5,
title_font={'size':18},
width=1000,
height=600,
template='plotly_white'
)
fig.show()