Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have an image that I'm showing with matplotlib.

enter image description here

The image is generated by the following code:

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


labels = ['Name1', 'Name2', 'Name3', 'Name4', 'Name5', 'Name6']

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.array(data, mask=mask) # Mask out the lower triangle of data.

fig, ax = plt.subplots(sharex=True)
im = ax.pcolor(data, edgecolors='black', linewidths=0.3)

# Format
fig = plt.gcf()
fig.set_size_inches(10, 10)

ax.set_yticks(np.arange(data.shape[0]) + 0.5, minor=False)
ax.set_xticks(np.arange(data.shape[1]) + 0.5, minor=False)

# Turn off the frame.
ax.set_frame_on(False)
ax.set_aspect('equal')  # Ensure heatmap cells are square.

# Want a more natural, table-like display.
ax.invert_yaxis()
ax.yaxis.tick_right()
ax.xaxis.tick_top()

ax.set_xticklabels(labels, minor=False)
ax.set_yticklabels(labels, minor=False)

# Rotate the upper labels.
plt.xticks(rotation=90)
ax.grid(False)
ax = plt.gca()

for t in ax.xaxis.get_major_ticks():
    t.tick1On = False
    t.tick2On = False
for t in ax.yaxis.get_major_ticks():
    t.tick1On = False
    t.tick2On = False

fig.colorbar(im)

fig.savefig('out.png', transparent=False, bbox_inches='tight', pad_inches=0)

I'd like to apply a custom colormap so that values:

  • between 0-1 are linear gradient from blue and white
  • between 1-3 are linear gradient from white and red.

Any help will be greatly appreciated.

share|improve this question
1  
Check out this SO question: stackoverflow.com/questions/16834861/… –  mwaskom Jul 28 '14 at 15:04

2 Answers 2

up vote 3 down vote accepted

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()

enter image description here

share|improve this answer

This sounds like the seismic colormap

You might want to force the minimum and maximum to get the middle to be white.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.