0

I have a CSV data file that has data of the (simplified) form:

1.2, 2.2,   o,   s
1.7,   s, 2.4, 2.9
  o, 0.9, 0.1, NaN
1.4,   s, 0.5, 0.9

NB: This contains the character 'o', not the number zero (0). This file is mixed with characters that indicate different types of "failed" measurements. These matrices are typically much larger than a 4x4 grid.

I would like to plot these matrices on a colour map using matplotlib but where each failed measurement value is assigned its own colour on the plot, whilst preserving the colour range of legitimate data.

Something with logic like e.g. `

if data == 'o':
   pixel_colour = 'red'

if data == 's':
   pixel_colour = 'black'

if data == 'NaN':
   pixel_colour = 'white'

` I have seen this helpful post (Changing colours of pixels of plt.imshow() image.) already but I can't think of how to get this to handle heterogeneous data types.

5
  • Do you have just o and s? Or are there more categories? Commented May 25, 2021 at 14:33
  • For now, just 'o' and 's'. NaN represents missing data in this case, which I should have specified. Commented May 25, 2021 at 14:41
  • Not an answer to your question, but you may just want to use "over" and "under" colors in your colormap: stackoverflow.com/questions/11386054/… Commented May 25, 2021 at 15:17
  • To answer your question you can always pass an rgbA array to imshow and it will just use those values. Commented May 25, 2021 at 15:26
  • Thank you for sharing! That makes sense but I think the issue would be assigning large numbers to, say, 's' will throw off the scale of the colour map. Also, this is only useful for 2 different types of 'failed' measurement. We have 3 and potentially more in the future. Thanks again though! Commented May 25, 2021 at 15:28

1 Answer 1

2

To properly answer your question, you can mask the bad values, norm, map to RGBA, and then fill in the other colors as you like

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

data = np.array([[1.2, 2.2,   'o',   's', 2.5],
                 [1.7,   's', 2.4, 2.9, 1.7],
                 ['o', 0.9, 0.1, 'NaN', 0.4]])
data[data == 'NaN'] = -4000           
data[data == 'o'] = -5000           
data[data == 's'] = -6000
data = data.astype(np.float64)

norm = mpl.colors.Normalize(vmin=0, vmax=3)
cmap = plt.get_cmap('viridis')

# convert from 0-1:
datan = norm(data)
# convert to rgba:
rgba = cmap(datan)
# Fill in colours for the out of range data:
rgba[data==-4000, :] = [1, 1, 1, 1]
rgba[data==-5000, :] = [1, 0, 0, 1]
rgba[data==-6000, :] = [0, 1, 1, 1]

# plot:
fig, ax = plt.subplots()
ax.imshow(rgba)
plt.show()

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

This is great, thank you! However, I can't seem to get a colour bar to work on the side of the plot? Getting an error: RuntimeError: No mappable was found to use for colorbar creation. Fi rst define a mappable such as an image (with imshow) or a contour se t (with contourf).
For future reference: I eventually fixed the colour bar issue by following the matplotlib colorbar docs: matplotlib.org/stable/gallery/color/colorbar_basics.html

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.