Create Own Colormap Using Matplotlib and Plot Color Scale

Create own colormap using matplotlib and plot color scale

There is an illustrative example of how to create custom colormaps here.
The docstring is essential for understanding the meaning of
cdict. Once you get that under your belt, you might use a cdict like this:

cdict = {'red':   ((0.0, 1.0, 1.0), 
(0.1, 1.0, 1.0), # red
(0.4, 1.0, 1.0), # violet
(1.0, 0.0, 0.0)), # blue

'green': ((0.0, 0.0, 0.0),
(1.0, 0.0, 0.0)),

'blue': ((0.0, 0.0, 0.0),
(0.1, 0.0, 0.0), # red
(0.4, 1.0, 1.0), # violet
(1.0, 1.0, 0.0)) # blue
}

Although the cdict format gives you a lot of flexibility, I find for simple
gradients its format is rather unintuitive. Here is a utility function to help
generate simple LinearSegmentedColormaps:

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

def make_colormap(seq):
"""Return a LinearSegmentedColormap
seq: a sequence of floats and RGB-tuples. The floats should be increasing
and in the interval (0,1).
"""
seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
cdict = {'red': [], 'green': [], 'blue': []}
for i, item in enumerate(seq):
if isinstance(item, float):
r1, g1, b1 = seq[i - 1]
r2, g2, b2 = seq[i + 1]
cdict['red'].append([item, r1, r2])
cdict['green'].append([item, g1, g2])
cdict['blue'].append([item, b1, b2])
return mcolors.LinearSegmentedColormap('CustomMap', cdict)

c = mcolors.ColorConverter().to_rgb
rvb = make_colormap(
[c('red'), c('violet'), 0.33, c('violet'), c('blue'), 0.66, c('blue')])
N = 1000
array_dg = np.random.uniform(0, 10, size=(N, 2))
colors = np.random.uniform(-2, 2, size=(N,))
plt.scatter(array_dg[:, 0], array_dg[:, 1], c=colors, cmap=rvb)
plt.colorbar()
plt.show()

Sample Image


By the way, the for-loop

for i in range(0, len(array_dg)):
plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())

plots one point for every call to plt.plot. This will work for a small number of points, but will become extremely slow for many points. plt.plot can only draw in one color, but plt.scatter can assign a different color to each dot. Thus, plt.scatter is the way to go.

How to create a custom colormap with three colors?

I used this adapted code from the matplotlib documentation

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap

def plot_examples(colormaps):
"""
Helper function to plot data with associated colormap.
"""
np.random.seed(19680801)
data = np.random.randn(30, 30)
n = len(colormaps)
fig, axs = plt.subplots(1, n, figsize=(n * 2 + 2, 3),
constrained_layout=True, squeeze=False)
for [ax, cmap] in zip(axs.flat, colormaps):
psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
fig.colorbar(psm, ax=ax)
plt.show()

# Red, Green, Blue
N = 256
vals = np.ones((N, 4))
# Red stays constant until middle of colormap all other channels increas
# to result in white
# from middle of colormap we decrease to 0, 0, 255 which is blue
vals[:, 0] = np.concatenate((np.linspace(1, 1, N//2), np.linspace(1, 0, N//2)), axis=None)
vals[:, 1] = np.concatenate((np.linspace(0, 1, N//2), np.linspace(1, 0, N//2)), axis=None)
vals[:, 2] = np.concatenate((np.linspace(0, 1, N//2), np.linspace(1, 1, N//2)), axis=None)
newcmp = ListedColormap(vals)

plot_examples([newcmp])

The output of this script looks similar to this
custom colormap

Making a custom colormap using matplotlib in python

There's more than one way to do this. In your case, it's easiest to use LinearSegmentedColormap.from_list and specify relative positions of colors as well as the colornames. (If you had evenly-spaced changes, you could skip the tuples and just do from_list('my cmap', ['blue', 'white', 'red']).) You'll then need to specify a manual min and max to the data (the vmin and vmax kwargs to imshow/pcolor/etc).

As an example:

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

data = np.array(
[[ 0.000, 0.120, 0.043, 0.094, 0.037, 0.045],
[ 0.120, 0.000, 0.108, 0.107, 0.105, 0.108],
[ 0.043, 0.108, 0.000, 0.083, 0.043, 0.042],
[ 0.094, 0.107, 0.083, 0.000, 0.083, 0.089],
[ 0.037, 0.105, 0.043, 0.083, 0.000, 2.440],
[ 0.045, 0.108, 0.042, 0.089, 2.440, 0.000]])
mask = np.tri(data.shape[0], k=-1)
data = np.ma.masked_where(mask, data)

vmax = 3.0
cmap = LinearSegmentedColormap.from_list('mycmap', [(0 / vmax, 'blue'),
(1 / vmax, 'white'),
(3 / vmax, 'red')]
)

fig, ax = plt.subplots()
im = ax.pcolor(data, cmap=cmap, vmin=0, vmax=vmax, edgecolors='black')
cbar = fig.colorbar(im)

cbar.set_ticks(range(4)) # Integer colorbar tick locations
ax.set(frame_on=False, aspect=1, xticks=[], yticks=[])
ax.invert_yaxis()

plt.show()

Sample Image

Plot a custom colormap next to iterative scatterplot

import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import Normalize
import numpy as np

# Create the dates
dates = np.datetime64('2017') + np.arange(5)*np.timedelta64(1, 'Y')

# Create array where the dates are the 2nd dimension
arr = np.random.randn(3,5,10,2)
values = np.linspace(0,1, num=arr.shape[1])

# create a normalizer
norm = Normalize(vmin=values.min(), vmax=values.max())
# normalize values
norm_values = norm(values)
# choose a colormap
cmap = cm.seismic
# create colors
colors = cmap(norm_values)
# map values to a colorbar
mappable = cm.ScalarMappable(norm=norm, cmap=cmap)
mappable.set_array(values)

fig, ax = plt.subplots()

# Iterate through the 1st and 2nd dimension
for g in range(0,arr.shape[0]):
for i in range(0,arr.shape[1]):
plot = plt.scatter(arr[g,i,:,0],arr[g,i,:,1], s = 10, marker = '_', color = colors[i])

# replace ticks by the years
cb = fig.colorbar(mappable, ticks=values)
cb.ax.set_yticklabels(dates)
cb.set_label("Date")

Sample Image

Create a Color Map in Matplotlib via Hex Codes

I would recommend converting your hex values into RGB tuples, then adding them all to a list. you can then utilize the from_list() method of linearSegmentedColormap to create a unique color map

LinearSegmentedColormap.from_list()

If you need more information you can use this as a reference:

https://matplotlib.org/gallery/images_contours_and_fields/custom_cmap.html

Matplotlib: Custom colormap with three colors

A solution to a very similar question was provided here. In summary ,

import matplotlib
matplotlib.colors.ListedColormap(list-of-colours)

is your friend.

Can I plot a colorbar from a list of colors and for loop?

Matplotlib's colorbar needs a ScalarMappable object. By default, it is taken from what's plotted, e.g. a scatter plot that is created in one call. If you need to combine the results of multiple calls, you can create an own ScalarMappable. It needs a colormap and a norm.

from matplotlib import pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.cm import ScalarMappable
import numpy as np

cycles = 7
N = 100
KL_rest = np.sin(np.linspace(0, 10 * np.pi, cycles * N))
scanpoints = np.arange(N)
cm = LinearSegmentedColormap.from_list('defcol', ["#000000", "#FF0000"])
trace_color = cm(np.linspace(0, 1, cycles))
for k, color in zip(range(cycles), trace_color):
lis = KL_rest[k::cycles]
plt.scatter(scanpoints, lis, color=color, marker='^', alpha=0.9)
plt.colorbar(ScalarMappable(cmap=cm, norm=plt.Normalize(0, cycles - 1)), ticks=np.arange(cycles), label='cycles')
plt.show()

custom colorbar

Note that in this case, you can create the scatter plot in one go, enabling a default color bar. For this to work, the scanpoints can be repeated for each cycle, and the colors can be indicated by tiling the cycle for each scan point.

If you only want to show the really used colors, you can add N=cycles in the creation of the color map. To put the tick marks for each number in the center of the cells, you can move the default limits by 0.5.

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

cycles = 7
N = 100
KL_rest = np.sin(np.linspace(0, 10 * np.pi, cycles * N))
scanpoints = np.arange(N)
cm = LinearSegmentedColormap.from_list('defcol', ["#000000", "#FF0000"], N=cycles)

plt.scatter(np.repeat(scanpoints, cycles), KL_rest,
c=np.tile(range(cycles), len(scanpoints)),
cmap=cm, norm=plt.Normalize(-0.5, cycles - 0.5),
marker='^', alpha=0.9)
plt.colorbar(ticks=np.arange(cycles), label='cycles')
plt.show()

scatterplot in one go

Matplotlib Colormaps – Choosing a different color for each graph/line/subject

One way to achieve your goal is to slice-up a colormap and then plot each line with one of the resulting colors. See the lines below that can be integrated in your code in appropriate places.

import numpy as np
import matplotlib.pyplot as plt

# 1. Choose your desired colormap
cmap = plt.get_cmap('plasma')

# 2. Segmenting the whole range (from 0 to 1) of the color map into multiple segments
slicedCM = cmap(np.linspace(0, 1, len(Subjects)))

# 3. Color the i-th line with the i-th color, i.e. slicedCM[i]
plt.plot(f, Welch, c=slicedCM[Subjects.index(Subject)])

(The first two lines can be put in the beginning and you can replace the line plotting curves in your code with the third line of code suggested above.)

Alternatively, and perhaps a neater approach, is using the below lines inside your main loop through Subjects:

cmap = plt.get_cmap('inferno')
plt.plot(f, Welch, c=cmap(Subjects.index(Subject)/len(Subjects)))

(I see in your question that you are changing Subject when you load the file again into Subject. Just use another variable name, say, data = np.loadtxt... and then f, Welch = signal.welch(data, ..... Keep the codes for plotting with different colors as suggested above and you won't have any problem.)



Related Topics



Leave a reply



Submit