2

I'm new to Python and am really struggling to get a sensible colourmap for my data.

I'm plotting 29x29 numpy arrays, where most of the cells are 0 but on average around 10-15 cells have non-zero values which can range from low 10s to several 1000s.

In C++ ROOT you automatically get a nice plot that has a white background and a nice rainbow colourbar that you can see below.

However, in matplotlib, following the advice here:

python matplotlib heatmap colorbar from transparent With the code:

from matplotlib.colors import LinearSegmentedColormap
%matplotlib inline 
#Lets visualise some events

# plot states
# plot states

# get colormap
ncolors = 256
color_array = plt.get_cmap('gist_rainbow')(range(ncolors))

# change alpha values
color_array[:,-1] = np.linspace(1.0,0.0,ncolors)

# create a colormap object
map_object = LinearSegmentedColormap.from_list(name='rainbow_alpha',colors=color_array)

# register this new colormap with matplotlib
plt.register_cmap(cmap=map_object)

# set colourbar map
cmap_args=dict(cmap='jet')

fig, axarr = plt.subplots(nrows=1, ncols=3)

axarr[0].imshow(events[0],**cmap_args)
axarr[0].set_title('Event0',fontsize=16)
axarr[0].tick_params(labelsize=16)

axarr[1].imshow(events[1],**cmap_args)
axarr[1].set_title('Event1',fontsize=16)
axarr[1].tick_params(labelsize=16)

axarr[2].imshow(events[2],**cmap_args)
axarr[2].set_title('Event2',fontsize=16)
axarr[2].tick_params(labelsize=16)

fig.subplots_adjust(right=2.0)
plt.show()

I get images like the one below, which is impossible to read.

Please can someone explain how to get a white background and a rainbow colourbar on the side of the plot?

Thanks a lot!

Text

Text

Beth Long
  • 375
  • 3
  • 24

1 Answers1

4

To show all zero values as white, a 'under' color could be set. The under color is used for values that are lower than the lowest value in the colorbar. Forcing the colorbar to start at 1 with vmin=1 makes all values lower than 1 to be considered 'under'.

from matplotlib import pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator
#%matplotlib inline

# create a colormap object
cmap = plt.get_cmap('rainbow')
cmap.set_under('white')

# set colourbar map
cmap_args = dict(cmap=cmap, vmin=1, vmax=8000)

fig, axarr = plt.subplots(nrows=1, ncols=4, figsize=(12, 3), gridspec_kw={'width_ratios': [10, 10, 10, 1]})

events = np.random.randint(0, 9, size=(3, 10, 10)) * 1000 * np.random.randint(0, 2, size=(3, 10, 10))

for ax, event, title in zip(axarr[:3], events, ['Event 0', 'Event 1', 'Event 2']):
    img = ax.imshow(event, **cmap_args)
    ax.set_title(title, fontsize=16)
    ax.tick_params(labelsize=16)
    ax.xaxis.set_major_locator(MultipleLocator(1))
    ax.yaxis.set_major_locator(MultipleLocator(1))
fig.colorbar(img, cax=axarr[3])

# to make the colorbar exactly the same height as the image plots:
pos_ax2 = axarr[2].get_position()
pos_ax3 = axarr[3].get_position()
pos_ax3.y0 = pos_ax2.y0
pos_ax3.y1 = pos_ax2.y1
axarr[3].set_position(pos_ax3)

plt.show()

example plot

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • Interesting use of the last ax to hold the colorbar alone. What would be the object-orientated version of `plt.colorbar(img, cax=axarr[3])` please? Just `axarr[3].colorbar(img)`? – Guimoute Jun 18 '20 at 16:08
  • 1
    @Guimoute The object-oriented version would be `fig.colorbar(img, cax=axarr[3])`. `colorbar` isn't an axes level function. It usually needs to change the `fig` to make more room. I'll edit my post to use `fig`. See [this doc](https://matplotlib.org/3.1.0/gallery/subplots_axes_and_figures/colorbar_placement.html) about the preferred ways to add a colorbar belonging to more than one `ax`. – JohanC Jun 18 '20 at 17:43
  • This has been incredibly helpful, and with a bit of tweaking of the parameters I've come to a graphic that I'm almost happy with - except now the colourbar is much longer than the plots. I tried using 'height_ratios' but that's obviously the height of a row of the array of figures, not of one individual element of the array. Please can you help me find a solution to this? – Beth Long Jun 19 '20 at 13:41
  • 1
    Can you try whether the updated code works for you? – JohanC Jun 19 '20 at 14:29