Plotting a heatmap or colormap with interpolation in Python
Asked Answered
D

1

6

I need to create a 'heatmap' or 'colormap' in python. I have three python list, namely: X_COORDINATE, Z_COORDINATE and C_I. The X_COORDINATE and Z_COORDINATE lists contain the x and z coordinates that I have specific data points for (stored in the C_I list). The C_I list contains the values that I need to plot onto the x-z grid at the corresponding coordinates.

The heatmap / colormap needs to interpolate between the points that are known and contained with the C_I list, such that the map is smooth, and NOT as square blocks. I cannot share the code or the source data as this is sensitive. However, for the purposes of understanding how to code one of these maps, assume that:

X = [1.1, 1.5, 2.0, 3.0, 4.0, 5.0, 1.1, 1.5, 2.0, 3.0, 4.0, 5.0, 1.1, 1.5, 2.0, 3.0, 4.0, 5.0, 0.0, 0.5, 1.0, 1.1, 1.5, 2.0, 3.0, 4.0, 5.0, 0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0]

Z = [0, 0, 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 1, 1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5]

C_I = [1.02414267447743, 0.210700871073941, 0.156586042435711, 0.109151033138569, 0.2279728779957, 0.204768257586954, 1.09037445301743, 0.287155868433615, 0.211257395413685, 0.132554129593619, 0.0900680495011601, 0.194608837248807, 1.34397119257655, 0.1201882143371, 0.17555070608144, 0.127220190160657, 0.204384526301353, 0.197414938747342, 0.195583977408476, 0.148150828086297, 0.183751866814816, 0.134858902076203, 0.183027629350907, 0.180267135381046, 0.0876356087026242, 0.183285092770786, 0.165502978081942, 0.0487725567447014, 0.172053559692846, 0.142204671797215, 0.166163224221791, 0.249334486033046, 0.150888488422605, 0.259452257883415]

So the zeroth element in the X_COORDINATE list is the x-coordinate for the first data point, the zeroth element in the Z_COORDINATE list is the z-coordinate for the first data point and the zeroth element in the C_I list is the value that must be plotted for that first point.

I would like X_COORDINATE on the x-axis and Z_COORDINATE on the z-axis with the interior of the map coloured by the corresponding C_I values. To be clear I would like the map to be similar to the following attached images; although I would like the X and Z axes ticks to be present and the associated colorbar. How do I do this?

The grid should be 5 units in the x-direction by 2.5 units in the z-direction (y-axis)

sample heatmap

Desirous answered 22/6, 2020 at 20:22 Comment(0)
D
5

So, I found a solution. For future reference this code should give those with the same problem what they need. I added an 'interpolation' argument to the plot.imshow() function like:

import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import interp2d

# fmt: off
X_COORDINATE = [1.1, 1.5, 2.0, 3.0, 4.0, 5.0, 1.1, 1.5, 2.0, 3.0, 4.0, 5.0, 1.1, 1.5, 2.0, 3.0, 4.0, 5.0, 0.0, 0.5, 1.0, 1.1, 1.5, 2.0, 3.0, 4.0, 5.0, 0.0, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0]
Z_COORDINATE = [0, 0, 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 1, 1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5]
C_I = [1.02414267447743, 0.210700871073941, 0.156586042435711, 0.109151033138569, 0.2279728779957, 0.204768257586954, 1.09037445301743, 0.287155868433615, 0.211257395413685, 0.132554129593619, 0.0900680495011601, 0.194608837248807, 1.34397119257655, 0.1201882143371, 0.17555070608144, 0.127220190160657, 0.204384526301353, 0.197414938747342, 0.195583977408476, 0.148150828086297, 0.183751866814816, 0.134858902076203, 0.183027629350907, 0.180267135381046, 0.0876356087026242, 0.183285092770786, 0.165502978081942, 0.0487725567447014, 0.172053559692846, 0.142204671797215, 0.166163224221791, 0.249334486033046, 0.150888488422605, 0.259452257883415]
# fmt: on

x_list = np.array(X_COORDINATE)
z_list = np.array(Z_COORDINATE)
C_I_list = np.array(C_I)

#   f will be a function with two arguments (x and z coordinates),
# but those can be array_like structures too, in which case the
# result will be a matrix representing the values in the grid
# specified by those arguments
f = interp2d(x_list, z_list, C_I_list, kind="linear")

x_coords = np.arange(min(x_list), max(x_list) + 1)
z_coords = np.arange(min(z_list), max(z_list) + 1)
c_i = f(x_coords, z_coords)

fig = plt.imshow(
    c_i,
    extent=[min(x_list), max(x_list), min(z_list), max(z_list)],
    origin="lower",
    interpolation="bicubic",
)

# Show the positions of the sample points, just to have some reference
fig.axes.set_autoscale_on(False)
plt.scatter(x_list, z_list, 400, facecolors="none")
plt.colorbar()
plt.show()

Does anybody know how I can change the resolution of the colours on the map so that I can better see the variation between values of 0 and 1 throughout the map?

The map now looks like the following:

updated heatmap

Desirous answered 23/6, 2020 at 8:50 Comment(1)
The issue with this solution is that it assumes x_list and 'z_list' in your example to be sampled from a rectangular grid and monotonic. While it works well, users may need to bin the data to regular grids and then apply interp2Veolaver

© 2022 - 2025 — McMap. All rights reserved.