Show unique color for unique value - matplotlib

I have a 2d numpy array obtained by reading from an image. The unique values of the array are 0, 1, and 2. I want to plot the image showing unique colors red, green, and blue for the values 0,1, and 2 respectively.
plt.imshow(data, cmap=colors.ListedColormap(['red'])
How would you do it?

from matplotlib.colors import from_levels_and_colors
cmap, norm = from_levels_and_colors([0,1,2,3],['red','green','blue'])
plt.imshow(data, cmap=cmap, norm=norm)

Related

Numpy, mapping a RGB colour ramp to normalised values

I have a normalised range of values in a numpy array, so 0 to 1, let's call this normal_array.
normal_array = np.array([0.0, 0.3, 0.356, 0.49, 0.64, 0.784, 1.0])
I need to create another numpy array which contains the rgb values of a colour ramp, let's call this colour_array. How do I map the RGB values from a colour ramp to the normal_array?
It would be great if I could use an existing colour ramp like these from matplotlib; https://matplotlib.org/stable/tutorials/colors/colormaps.html
How do you map the 0-1 values to rgb values from a colour ramp?

Force grayscale legend colors in scatterplot

I want to prepare a grayscale figure with multiple, overlapping scatter plots. A simplified version of my code is as follows:
for object in list_of_objects:
plt.scatter(object.x,object.y,marker=object.marker,label=object.label)
plt.legend()
plt.show()
The problem is that the legend appears in non-grayscale color, so is there any way to force it to use grayscale colors? (i.e. a different grayscale color for the data of each object)
Matplotlib
If you need to use matplotlib, then here is a sample of how you can achieve this. Assuming there are 5 groups that you want to add here.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.rand(100)
y = np.random.rand(100)
groups = [1, 2, 3, 4, 5] * 20
plt.scatter(x, y, c=groups, cmap='Greys')
plt.colorbar(ticks=[1, 2, 3, 4, 5])
plt.show()
Output graph:
Seaborn
If you are able to use seaborn, it is simpler...
You can use palette = 'gray' and hue=<your group> to give it different shades of gray.
Sample code:
tips = sns.load_dataset("tips")
sns.scatterplot(data=tips, x="total_bill", y="tip", hue="size", palette="gray")
Will give this pic

How to show following data with colors and color bar. What will be suitable command for this? [duplicate]

I want to make a scatterplot (using matplotlib) where the points are shaded according to a third variable. I've got very close with this:
plt.scatter(w, M, c=p, marker='s')
where w and M are the data points and p is the variable I want to shade with respect to.
However I want to do it in greyscale rather than colour. Can anyone help?
There's no need to manually set the colors. Instead, specify a grayscale colormap...
import numpy as np
import matplotlib.pyplot as plt
# Generate data...
x = np.random.random(10)
y = np.random.random(10)
# Plot...
plt.scatter(x, y, c=y, s=500) # s is a size of marker
plt.gray()
plt.show()
Or, if you'd prefer a wider range of colormaps, you can also specify the cmap kwarg to scatter. To use the reversed version of any of these, just specify the "_r" version of any of them. E.g. gray_r instead of gray. There are several different grayscale colormaps pre-made (e.g. gray, gist_yarg, binary, etc).
import matplotlib.pyplot as plt
import numpy as np
# Generate data...
x = np.random.random(10)
y = np.random.random(10)
plt.scatter(x, y, c=y, s=500, cmap='gray')
plt.show()
In matplotlib grey colors can be given as a string of a numerical value between 0-1.
For example c = '0.1'
Then you can convert your third variable in a value inside this range and to use it to color your points.
In the following example I used the y position of the point as the value that determines the color:
from matplotlib import pyplot as plt
x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
y = [125, 32, 54, 253, 67, 87, 233, 56, 67]
color = [str(item/255.) for item in y]
plt.scatter(x, y, s=500, c=color)
plt.show()
Sometimes you may need to plot color precisely based on the x-value case. For example, you may have a dataframe with 3 types of variables and some data points. And you want to do following,
Plot points corresponding to Physical variable 'A' in RED.
Plot points corresponding to Physical variable 'B' in BLUE.
Plot points corresponding to Physical variable 'C' in GREEN.
In this case, you may have to write to short function to map the x-values to corresponding color names as a list and then pass on that list to the plt.scatter command.
x=['A','B','B','C','A','B']
y=[15,30,25,18,22,13]
# Function to map the colors as a list from the input list of x variables
def pltcolor(lst):
cols=[]
for l in lst:
if l=='A':
cols.append('red')
elif l=='B':
cols.append('blue')
else:
cols.append('green')
return cols
# Create the colors list using the function above
cols=pltcolor(x)
plt.scatter(x=x,y=y,s=500,c=cols) #Pass on the list created by the function here
plt.grid(True)
plt.show()
A pretty straightforward solution is also this one:
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(8,8))
p = ax.scatter(x, y, c=y, cmap='cmo.deep')
fig.colorbar(p,ax=ax,orientation='vertical',label='labelname')

How to create a discrete colormap that maps integers to colors, invariant to range of input data

Let's say I have a vector containing integers from the set [1,2,3]. I would like to create a colormap in which 1 always appears as blue, 2 always appears as red, and 3 always appears as purple, regardless of the range of the input data--e.g., even if the input vector only contains 1s and 2s, I would still like those to appear as blue and red, respectively (and purple is not used in this case).
I've tried the code below:
This works as expected (data contains 1, 2 and 3):
cmap = colors.ListedColormap(["blue", "red", "purple"])
bounds = [0.5,1.5,2.5,3.5]
norm = colors.BoundaryNorm(bounds, cmap.N)
data = np.array([1,2,1,2,3])
sns.heatmap(data.reshape(-1,1), cmap=cmap, norm=norm, annot=True)
Does not work as expected (data contains only 1 and 2):
cmap = colors.ListedColormap(["blue", "red", "purple"])
bounds = [0.5,1.5,2.5,3.5]
norm = colors.BoundaryNorm(bounds, cmap.N)
data = np.array([1,2,1,2,2])
sns.heatmap(data.reshape(-1,1), cmap=cmap, norm=norm, annot=True)
In the first example, 1 appears as blue, 2 appears as red and 3 appears as purple, as desired.
In the second example, 1 appears as blue and 2 appears as purple, while red is not used.
Not completely sure, but I think this minimal example solves your problem. Here, I've taken an actual colormap and edited it to produce a smaller version of it. Hope it helps!
#0. Import libraries
#==============================
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import colors
import seaborn as sns
import numpy as np
#==============================
#1. Create own colormap
#======================================
#1.1. Choose the colormap you want to
#pick up colors from
source_cmap=matplotlib.cm.get_cmap('Set2')
#1.2. Choose number of colors and set a step
cols=4;step=1/float(cols - 1)
#1.3. Declare a vector to store given colors
cmap_vec=[]
#1.4. Run from 0 to 1 (limits of colormap)
#stepwise and pick up equidistant colors
#---------------------------------------
for color in np.arange(0,1.1,step):
#store color in vector
cmap_vec.append( source_cmap(color) )
#---------------------------------------
#1.5. Create colormap with chosen colors
custom_cmap=\
colors.ListedColormap([ color for color in cmap_vec ])
#====================================
#2. Basic example to plot in
#======================================
A = np.matrix('0 3; 1 2')
B=np.asarray(A)
ax=sns.heatmap(B,annot=True,cmap=custom_cmap)
plt.show()
#======================================

How to change colorbar's color (in some particular value interval)?

In matplotlib, I would like to change colorbar's color in some particular value interval. For example, I would like to change the seismic colorbar, to let the values between -0.5 and 0.5 turn white, how can I do this?
thank you very much
You basically need to create your own colormap that has the particular features you want. Of course it is possible to make use of existing colormaps when doing so.
Colormaps are always ranged between 0 and 1. This range will then be mapped to the data interval. So in order to create whites between -0.5 and 0.5 we need to know the range of data - let's say data goes from -1 to 1. We can then decide to have the lower (blues) part of the seismic map go from -1 to -0.5, then have white between -0.5 and +0.5 and finally the upper part of the seismic map (reds) from 0.5 to 1. In the language of a colormap this corresponds to the ranges [0,0.25], [0.25, 0.75] and [0.75,1]. We can then create a list, with the first and last 25% percent being the colors of the seismic map and the middle 50% white.
This list can be used to create a colormap, using matplotlib.colors.LinearSegmentedColormap.from_list("colormapname", listofcolors).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
n=50
x = 0.5
lower = plt.cm.seismic(np.linspace(0, x, n))
white = plt.cm.seismic(np.ones(100)*0.5)
upper = plt.cm.seismic(np.linspace(1-x, 1, n))
colors = np.vstack((lower, white, upper))
tmap = matplotlib.colors.LinearSegmentedColormap.from_list('terrain_map_white', colors)
x = np.linspace(0,10)
X,Y = np.meshgrid(x,x)
z = np.sin(X) * np.cos(Y*0.4)
fig, ax = plt.subplots()
im = ax.imshow(z, cmap=tmap)
plt.colorbar(im)
plt.show()
For more general cases, you may need a color normalization (using matplotlib.colors.Normalize). See e.g. this example, where a certain color in the colormap is always fixed at a data value of 0, independent of the data range.