python imshow, set certain value to defined color
Asked Answered
V

4

14

I have a RGB Image, which I plot with matplotlib.pyplot.imshow and it works fine. But now I want to change the plot, that where the value of the picture is e.g 1, the color of the plot should change to white at all this positions.

Is there a way to do this?

Viral answered 9/6, 2016 at 7:20 Comment(0)
S
5

Assuming that your image is a single-channel image rather than a three-channel image, the required task can be performed by defining a palette that maps indices (e.g. gray level intensities or picture values) into colors:

import numpy as np
import matplotlib.pyplot as plt

palette = np.array([[  0,   0,   0],   # black
                    [255,   0,   0],   # red
                    [  0, 255,   0],   # green
                    [  0,   0, 255],   # blue
                    [255, 255, 255]])  # white
I = np.array([[ 0, 1, 2, 0],    # 2 rows, 4 columns, 1 channel
              [ 0, 3, 4, 0]])

Image conversion is efficiently accomplished through NumPy's broadcasting:

RGB = palette[I]

And this is how the transformed image looks like:

>>> RGB
array([[[  0,  0,    0],  # 2 rows, 4 columns, 3 channels
        [255,  0,    0],
        [  0, 255,   0],
        [  0,   0,   0]],
       
       [[  0,   0,   0],
        [  0,   0, 255],
        [255, 255, 255],
        [  0,   0,   0]]])

plt.imshow(RGB)

enter image description here

Stotinka answered 9/6, 2016 at 8:27 Comment(0)
D
26

I will answer the general question of how to set a particular value to a particular color regardless of the color map.

In the code below for illustration purposes I supposed that is the value -1 that you want to map white. You will be wanting to do something different for your code.

This technique uses a masked array to set the parts where your data is equal to -1 (the value you wish to map) and then uses cmap.set_bad() to assign the color white to this value.

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

value = -1
data = np.arange(100).reshape((10, 10))
data[5, :] = -1  # Values to set -1

masked_array = np.ma.masked_where(data == value, data)

cmap = matplotlib.cm.spring  # Can be any colormap that you want after the cm
cmap.set_bad(color='white')

plt.imshow(masked_array, cmap=cmap)
plt.show()

enter image description here

Hope it helps.

Dithyramb answered 10/3, 2017 at 13:50 Comment(1)
I needed to use cmap = plt.get_cmap('spring') to get the cmap object instead of matplotlib.cm.springStealage
A
7

I am going to present a solution to the original question, which is extendable to assigning several values to several different colors respectively.

Solution

The solution involves creating a new three dimensional NumPy ndarray that contains, at each i,j position, an NumPy array with RGB values. This new data3d array is then plotted with imshow (or matshow)

# import packages 
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

# generate data 
np.random.seed(42)
data = np.random.randint(low=1, high=4, size=(10,10)) # possible values are 1,2,3

# define color map 
color_map = {1: np.array([255, 0, 0]), # red
             2: np.array([0, 255, 0]), # green
             3: np.array([0, 0, 255])} # blue 

# make a 3d numpy array that has a color channel dimension   
data_3d = np.ndarray(shape=(data.shape[0], data.shape[1], 3), dtype=int)
for i in range(0, data.shape[0]):
    for j in range(0, data.shape[1]):
        data_3d[i][j] = color_map[data[i][j]]

# display the plot 
fig, ax = plt.subplots(1,1)
ax.imshow(data_3d)

# add numbers to the plot 
# thanks to tmdavison answer here https://mcmap.net/q/595396/-display-matrix-values-and-colormap
for i in range(0, data.shape[0]):
    for j in range(0, data.shape[1]):
        c = data[j,i]
        ax.text(i, j, str(c), va='center', ha='center')

matrix with colors assigned to numbers

Background I encountered a problem recently where I needed to plot several one-channel matrices and assign a distinct color to the 1's 2's and 3's in each matrix. The ordering of the 1's, 2's and 3's changed depending on the matrix, which meant that using a defined color scheme often led to the assignment of different colors to the same value in different matrices. For example in the first matrix the 1's were assigned to red, whereas in the second matrix the 1's were assigned to blue.

I spent a lot of time searching around stackoverflow for a solution, but never found anything that worked. Eventually, was able to work one out on my own. This is solution to the problem in this question, that is extendable to multiple values and independent of the ordering of the values in the main matrix. It will also work with matshow instead of imshow.

Alissaalistair answered 26/3, 2021 at 17:34 Comment(1)
This was the idea I needed for my application, Thanks!!Jutta
S
5

Assuming that your image is a single-channel image rather than a three-channel image, the required task can be performed by defining a palette that maps indices (e.g. gray level intensities or picture values) into colors:

import numpy as np
import matplotlib.pyplot as plt

palette = np.array([[  0,   0,   0],   # black
                    [255,   0,   0],   # red
                    [  0, 255,   0],   # green
                    [  0,   0, 255],   # blue
                    [255, 255, 255]])  # white
I = np.array([[ 0, 1, 2, 0],    # 2 rows, 4 columns, 1 channel
              [ 0, 3, 4, 0]])

Image conversion is efficiently accomplished through NumPy's broadcasting:

RGB = palette[I]

And this is how the transformed image looks like:

>>> RGB
array([[[  0,  0,    0],  # 2 rows, 4 columns, 3 channels
        [255,  0,    0],
        [  0, 255,   0],
        [  0,   0,   0]],
       
       [[  0,   0,   0],
        [  0,   0, 255],
        [255, 255, 255],
        [  0,   0,   0]]])

plt.imshow(RGB)

enter image description here

Stotinka answered 9/6, 2016 at 8:27 Comment(0)
S
0

A little modification of @alluppercase answer. Instead of looping through individual pixels, I looped through RGB layers and color index, which maybe more efficient for large image:

color_list = {0: np.array([255, 255, 255]), # white
              1: np.array([0, 0, 255]), # blue
              2: np.array([0, 255, 0]), # green
              3: np.array([255, 0, 0])} # red
arr_rgb = np.ndarray(shape=(arr.shape[0], arr.shape[1], 3), dtype=int)
for layer in range(3):
    for code in color_list.keys():
        arr_rgb[:, :, layer][arr == code] = color_list[code][layer]
Sickener answered 24/1 at 17:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.