How do I create a contour plot on magnetometer data?

Viewed 185

I have been struggling to solve this problem for days. I am working on a project Indoor localization based on sensors. I am using a dataset that contains magnetometer sensor readings (Columns are X, Y, Z, Magnitude) and want to plot a contour where X and Y are coordinates and z axis should represent the mean values of magnitude.

I have total 9 such datasets and I have to create a contour plot where I have X and Y as coordinates that look like:

0,0 | 0,1 | 0,2

1,0 | 1,1 | 1,2

2,0 | 2,2 | 2,2

and Z should be mean of Magnitude.

Here's what i have tried till now: Z needs to be a 2D value so it cannot be a single value. So I used all 9 datasets and got 9 means of magnitude. Here's the code:

# Create an array of all the means of readings on Z axis 
mag_nmean = np.array((mag_mean, mag_mean1, mag_mean2, mag_mean3, mag_mean4, mag_mean5, mag_mean6, mag_mean7, mag_mean8))
mag_nmean.shape
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(6,5))
left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
ax = fig.add_axes([left, bottom, width, height]) 

start, stop = 0, 5

x_vals = [0, 1, 2]
y_vals = [0, 1, 2]
X, Y = np.meshgrid(x_vals, y_vals)

Z = mag_nmean.reshape((3,3))

# X, Y and Z should have same shape
print(X.shape, Y.shape, Z.shape)

cp = plt.contourf(X, Y, Z, cmap = plt.cm.jet)
#plt.colorbar(cp)
contours = plt.contour(X, Y, Z, colors = 'black')
plt.clabel(contours, fontsize = 8)

plt.colorbar(cp)
plt.axis(aspect = 'image')
plt.show()

The above code plots:

This is what I have tried although I do not understand the plot so I dont know if I am on the right path.

I cannot figure out how to solve this problem.

1 Answers

The problem I see is that the data points are irregularly spaced.
Because of this, you need to interpolate Magnitude values for every X and Y combination.

I tried modify your code to follow the matplotlib example for contour plots of irregularly spaced data here: https://matplotlib.org/3.2.2/gallery/images_contours_and_fields/irregulardatagrid.html#sphx-glr-gallery-images-contours-and-fields-irregulardatagrid-py, using the data in the table you provided:

import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np

fig = plt.figure(figsize=(6,5))
left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
ax = fig.add_axes([left, bottom, width, height]) 

start, stop = 0, 5

# You can find a way to read these from file 
x_vals = np.array((-17.4, -17.34, -17.4, -17.22, -17.22, -17.58, -17.82, -18.3, -18.43))
y_vals = np.array((29.28, 29.52, 29.28, 29.7, 29.28, 29.28, 29.16, 28.5, 28.62))
# assuming these are the mean Magnitudes of all Z's on corresponding X and Y points
mag_vals = np.array((27.83946, 27.94255, 27.75191, 27.61076, 27.91546, 28.17137, 28.44899, 28.90352, 28.67554))

# The points are irregularly spaced. 
# There needs to be a Z value corresponding to every X and Y
# Need to interpolate some points
triang = tri.Triangulation(x_vals, y_vals)
interpolator = tri.LinearTriInterpolator(triang, z_vals)
Xi, Yi = np.meshgrid(x_vals, y_vals)
Zi = interpolator(Xi, Yi)

# X, Y and Z should have same shape
print(Xi.shape, Yi.shape, Zi.shape)
cp = plt.contourf(Xi, Yi, Zi, cmap = plt.cm.jet)
contours = plt.contour(Xi, Yi, Zi, colors = 'black')
plt.clabel(contours, fontsize = 8)

plt.colorbar(cp)
plt.axis(aspect = 'image')
plt.show()

If you run this, it ends up with a pretty useless looking plot :)

enter image description here

Investigating why, it is because the interpolated Z values have a lot of gaps where the interpolator won't work! Probably because I only had that small subset of data.

print(Zi)

(-- == NaN)

[[27.839459999999995 27.86479333333334 27.839459999999995 27.91546 27.91546 28.171369999999992 -- -- --] [27.90326500000002 27.942550000000026 27.90326500000002 27.74134571428571 27.74134571428571 -- -- -- --] [27.839459999999995 27.86479333333334 27.839459999999995 27.91546 27.91546 28.171369999999992 -- -- --] [-- -- -- 27.610760000000482 27.610760000000482 -- -- -- --] [27.839459999999995 27.86479333333334 27.839459999999995 27.91546 27.91546 28.171369999999992 -- -- --] [27.839459999999995 27.86479333333334 27.839459999999995 27.91546 27.91546 28.171369999999992 -- -- --] [28.06162307692307 -- 28.06162307692307 -- -- 28.068939508196713 28.44899000000032 -- --] [-- -- -- -- -- -- -- 28.90352 --] [-- -- -- -- -- -- -- 28.762499665271967 28.675540000000183]]

Maybe with your full data set it will make more sense.

Related