6

I have some numpy array containing data that I would visualize on a 2D grid. Some of the data is unphysical and I would like to mask this data. However, I could not figure out how to set the mask attribute of tricontour correctly. I tried:

import matplotlib.pyplot as mp
import numpy as np

with open('some_data.dat', 'r') as infile:
        x, y, z = np.loadtxt(infile, usecols=(0, 1, 2), unpack=True)
isbad = np.less(z, 1.4) | np.greater(z, 2.1)
mp.tricontourf(x, y, z, mask = isbad)

But the resulting figure is simply not masked. I tried masking part of a contourf plot in matplotlib, i.e.

z2 = np.ma.array(z, mask= isbad)
mp.tricontourf(x, y, z2)

which did not work either. I want to use tricontourf instrad of contourf, because I do not want to grid my data.

z[isbad] = np.nan

results in a Segmentation fault when calling tricontourf

Here's the figure, the red colours are the ones I would like to mark as unphysical.A coloured contour plot with an overshooting color axis, due to unphysical data

Community
  • 1
  • 1
wsj
  • 677
  • 7
  • 11

2 Answers2

3

Here comes the trick. I need to collect the indices of triangles (which are indices into z!), evaluate whether they are good or not and then accept only the triangles for that at least one corner is valid (reducing the dimension from (ntri, 3) to ntri

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

triang = tr.Triangulation(x, y)
mask = np.all(np.where(isbad[triang.triangles], True, False), axis=1)
triang.set_mask(mask)
colplt = plt.tricontourf(triang, z)
plt.colorbar()

Inspired by this link: http://matplotlib.org/examples/pylab_examples/tripcolor_demo.html

Coloured contour plot with maksed unphysical region

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
wsj
  • 677
  • 7
  • 11
  • 1
    Really should use "any" instead of "all", if a node has a NaN, using all will still allow NaN values into the contouring algorithm, and cause Segmentation faults – Michael Sep 07 '16 at 22:01
  • I used a `mask = np.sum(isbad[triang.triangles],axis=1)>1` to test if 2 or 3 nodes were suspect, since I wanted to see results where at least 1 node was in range. – Dave X Mar 29 '17 at 20:47
0

wsj's answer didn't work for me since it didn't remove certain masked points (I think when not all of the nodes were bad).

This solution did:

z[isbad] = numpy.NaN
z = numpy.ma.masked_invalid(z)
vmin, vmax = z.min(), z.max()
z = z.filled(fill_value=-999)

levels = numpy.linspace(vmin, vmax, n_points)
plt.tricontourf(x, y, z, levels=levels)
Hypercube
  • 1,181
  • 2
  • 10
  • 16