0

I have a data which looks like (example)

x y  d
0 0 -2
1 0  0
0 1  1 
1 1  3

And I want to turn this into a coloumap plot which looks like one of these:

enter image description here

where x and y are in the table and the color is given by 'd'. However, I want a predetermined color for each number, for example:

-2 - orange
 0 - blue
 1 - red
 3 - yellow

Not necessarily these colours but I need to address a number to a colour and the numbers are not in order or sequence, the are just a set of five or six random numbers which repeat themselves across the entire array.

Any ideas, I haven't got a code for that as I don't know where to start. I have however looked at the examples in here such as:

Matplotlib python change single color in colormap

However they only show how to define colours and not how to link those colours to an specific value.

1
  • I believe my solution solves this problem stackoverflow.com/a/66821752/7871710 without the need to define a custom color map and is independent of the ordering of the numbers in the matrix. Commented Mar 26, 2021 at 17:40

1 Answer 1

1

It turns out this is harder than I thought, so maybe someone has an easier way of doing this.

Since we need to create an image of the data, we will store them in a 2D array. We can then map the data to the integers 0 .. number of different data values and assign a color to each of them. The reason is that we want the final colormap to be equally spaced. So

value -2 --> integer 0 --> color orange
value 0 --> integer 1 --> color blue and so on.

Having nicely spaced integers, we can use a ListedColormap on the image of newly created integer values.

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

# define the image as a 2D array
d = np.array([[-2,0],[1,3]])

# create a sorted list of all unique values from d
ticks = np.unique(d.flatten()).tolist()
# create a new array of same shape as d
# we will later use this to store values from 0 to number of unique values
dc = np.zeros(d.shape)
#fill the array dc
for i in range(d.shape[0]):
    for j in range(d.shape[1]):
        dc[i,j] = ticks.index(d[i,j])

# now we need n (= number of unique values) different colors        
colors= ["orange", "blue", "red", "yellow"]
# and put them to a listed colormap
colormap =  matplotlib.colors.ListedColormap(colors)


plt.figure(figsize=(5,3))
#plot the newly created array, shift the colorlimits, 
# such that later the ticks are in the middle
im = plt.imshow(dc, cmap=colormap, interpolation="none", vmin=-0.5, vmax=len(colors)-0.5)
# create a colorbar with n different ticks
cbar = plt.colorbar(im, ticks=range(len(colors)) )
#set the ticklabels to the unique values from d
cbar.ax.set_yticklabels(ticks)
#set nice tickmarks on image
plt.gca().set_xticks(range(d.shape[1]))
plt.gca().set_yticks(range(d.shape[0]))

plt.show()

enter image description here


As it may not be intuitively clear how to get the array d in the shape needed for plotting with imshow, i.e. as 2D array, here are two ways of converting the input data columns:

import numpy as np

x = np.array([0,1,0,1])
y  = np.array([ 0,0,1,1])
d_original = np.array([-2,0,1,3])

#### Method 1 ####
# Intuitive method. 
# Assumption: 
#    * Indexing in x and y start at 0 
#    * every index pair occurs exactly once.
# Create an empty array of shape (n+1,m+1) 
#   where n is the maximum index in y and
#         m is the maximum index in x
d = np.zeros((y.max()+1 , x.max()+1), dtype=np.int) 
for k in range(len(d_original)) :
    d[y[k],x[k]] = d_original[k]  
print d

#### Method 2 ####
# Fast method
# Additional assumption: 
#  indizes in x and y are ordered exactly such
#  that y is sorted ascendingly first, 
#  and for each index in y, x is sorted. 
# In this case the original d array can bes simply reshaped
d2 = d_original.reshape((y.max()+1 , x.max()+1))
print d2
Sign up to request clarification or add additional context in comments.

12 Comments

Hey mate, that sounds exactly like what I wanted to do. Just one question though. My data is a long list of numbers (like a hundred of them) I've got the x and y positions which you didn't seem to use. But how do I use a long list of values into the 2D array, which would be your d?
I'm assuming I'd need to create an array, say if my data gives a 10x10 graph of colours I'd need a 10x10 array, is that accurate?
I edited the answer to include how to make the required array from the column structure you have. It is indeed true, that for plotting a 10x10 graph, you need a 10x10 array. The indexing is done implicitely, first column, first row of that array is the index 0,0. Last column, last row would have the index 9,9.
That totally did it mate! Silly question, is there an easy way to change the size of each square? Now its only unity, but if I want each square to be 3x3?
The squares have no size. Do you mean to change the labeling? Try adding plt.gca().set_xticklabels(np.array(range(d.shape[1]))*3 ).
|

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.