gradstudent61
gradstudent61

Reputation: 15

Plotting spatial data on a heatmap

I have a challenging problem that I have not figured out yet. So, I have a bunch of data from a fluid flow simulation. I have two files: the spatial (x,y,z) data, which looks like this (note, I only care about 2D, so only the x and y values):

(-2 -1.5 0.1)
(5 -1.5 0.1)
(-2 -1.5 0.6)
(5 -1.5 0.6)
(-2 1.92708 0.1)
...

and its corresponding velocity_magnitude values. where each line corresponds to the velocty_x at the location in the spatial data file. For example, the value 0.08 is at (-2 -1.5 0.1).

0.08 
0.07
0.1 
0.34 ...
...

I want to make this into a heat map. I naively first just focused on the velocity data, reformatted into a 2D array, and showed that heatmap but the locations are all wrong. The problem is the spatial data is not in order, so doing it my way did not work. How do I combine both the x,y location with the actual velocity value to create a heatmap for my data?

Upvotes: 1

Views: 1795

Answers (1)

jlandercy
jlandercy

Reputation: 11002

If you are interested in rendering mean velocity on the heatmap Matplotlib, Numpy and Scipy are packages of interest. Let's investigate some options you have...

Data Visualisation

Trial Dataset

First we create a trial dataset:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
   
# Create trial dataset:
N = 10000
a = np.array([-10, -10, 0])
b = np.array([15, 15, 0])
x0 = 3*np.random.randn(N, 3) + a
x1 = 5*np.random.randn(N, 3) + b
x = np.vstack([x0, x1])
v0 = np.exp(-0.01*np.linalg.norm(x0-a, axis=1)**2)
v1 = np.exp(-0.01*np.linalg.norm(x1-b, axis=1)**2)
v = np.hstack([v0, v1])

# Render dataset:
axe = plt.axes(projection='3d')
axe.plot_trisurf(x[:,0], x[:,1], v, cmap='jet', alpha=0.5)
axe.set_xlabel("x")
axe.set_ylabel("y")
axe.set_zlabel("Speed")
axe.view_init(elev=25, azim=-45)

It looks like:

enter image description here

2D Hexagonal Histogram

The easiest way is probably to use Matplotlib hexbin function:

# Render hexagonal histogram:
pc = plt.hexbin(x[:,0], x[:,1], C=v, gridsize=20)
pc.axes.set_title("Heatmap")
pc.axes.set_xlabel("x")
pc.axes.set_ylabel("y")
pc.axes.set_aspect("equal")
cb = plt.colorbar(ax=pc.axes)
cb.set_label("Speed")

It renders:

enter image description here

2D Rectangular Histogram

You can also use numpy.histogram2D and Matplolib imshow:

# Bin Counts:
c, *_ = np.histogram2d(x[:,0], x[:,1], bins=20)
# Bin Weight Sums:
s, xbin, ybin = np.histogram2d(x[:,0], x[:,1], bins=20, weights=v)
lims = [xbin.min(), xbin.max(), ybin.min(), ybin.max()]

# Render rectangular histogram:
iax = plt.imshow((s/c).T, extent=lims, origin='lower')
iax.axes.set_title("Heatmap")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
cb = plt.colorbar(ax=iax.axes)
cb.set_label("Speed")

It outputs:

enter image description here

Linear Interpolation

As pointed out by @rioV8, your dataset seems to be spatially irregular. If you need to map it to a rectangular grid, you can use the mutlidimensional linear interpolator of Scipy.

from scipy import interpolate

# Create interpolator:
ndpol = interpolate.LinearNDInterpolator(x[:,:2], v)

# Create meshgrid:
xl = np.linspace(-20, 30, 20)
X, Y = np.meshgrid(xl, xl)
lims = [xl.min(), xl.max(), xl.min(), xl.max()]

# Interpolate over meshgrid:
V = ndpol(list(zip(X.ravel(),Y.ravel()))).reshape(X.shape)

# Render interpolated speeds:
iax = plt.imshow(V, extent=lims, origin='lower')
iax.axes.set_title("Heatmap")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
cb = plt.colorbar(ax=iax.axes)
cb.set_label("Speed")

It renders:

enter image description here

Nota: in this version ticks still need to be centered on each pixel.

Contours

Once you have a rectangular grid you can also draw Matplotlib contours:

# Render contours:
iax = plt.contour(X, Y, V)
iax.axes.set_title("Contours")
iax.axes.set_xlabel("x")
iax.axes.set_ylabel("y")
iax.axes.set_aspect("equal")
iax.axes.grid()
iax.axes.clabel(iax)

enter image description here

Data Manipulation

Based on the file formats you provided, it is easy to import it using pandas:

import io
import pandas as pd
    
with open("spatial.txt") as fh:
    file1 = io.StringIO(fh.read().replace("(", "").replace(")", ""))
x = pd.read_csv(file1, sep=" ", header=None).values

v = pd.read_csv("speed.txt", header=None).squeeze().values

Upvotes: 5

Related Questions