0

I have seen numerous resources for establishing unique cmap color codes, such as:

i) Merge colormaps in matplotlib

ii) Python: Invalid RGBA argument 0.0 color points according to class

iii) Defining a discrete colormap for imshow in matplotlib

None of these quite answer my question. I have 900 rows and each row has 200 data points that are either 1 or 0. In the finished product, the top 20% of the chart should have blue spikes for 1's and the bottom 80% should have red spikes for 1's. So y-axis >=720== blue and y-axis <720 = red.

The imshow cmap codes for these colors are plt.cm.Blues and plt.cm.Red

It's relatively easy to have all the spikes be coded blue:

img0 = raster[0].imshow(spikes, cmap=plt.cm.Blues, origin='lower', aspect="auto")

Spike raster for 900 neurons over 200 time steps

However, when I try to split the coding of cmap, I run into RGB errors related to the format of the input data. My code is below, and any help would be appreciated.

colors1 = plt.cm.Reds(np.linspace(0,1,int(200*900*.8)).reshape(int(900*.8),200))
colors2 = plt.cm.Blues(np.linspace(0,1,int(200*900*.2)).reshape(int(900*.2),200))
cmap = matplotlib.colors.LinearSegmentedColormap.from_list('mycmap', np.append(colors1,colors2))
img0 = raster[0].imshow(spikes, cmap=cmap, origin='lower', aspect="auto")

Final answer that works

img0 = raster[0].imshow(spikes[720:,:], cmap='Blues', extent=[0, 30, 720, 899], origin='lower', aspect="auto")
img0 = raster[0].imshow(spikes[:720,:], cmap='Reds', extent=[0, 30, 0, 719], origin='lower', aspect="auto")
raster[0].set_ylim(0, 900)
da Bears
  • 13
  • 5
  • Please see https://matplotlib.org/stable/tutorials/colors/colormap-manipulation.html#creating-listed-colormaps, in particular the example of concatenating two colormaps. – Jody Klymak Sep 05 '22 at 16:07
  • Hi Jody, thank you for that link. As described in the link, I also tried things like colors = ["red", "blue"], but that only changed the default colors of the plot. In matplotlib, there is an option called ``cdict'' that seems promising, but it requires explicitly setting the colors of points--given we have 900*200 data points, that's a bit unwieldy...my attempt above took a stab at doing this with cmap – da Bears Sep 05 '22 at 16:19
  • This could be a lot clearer - avoid the use of jargon like “spike” and consider making a synthetic dataset – Jody Klymak Sep 05 '22 at 18:38

1 Answers1

0

Based on your comments, all you want is two images with different colormaps on the same axes:


import matplotlib.pyplot as plt
import numpy as np

data = np.random.rand(900, 30)

fig, ax = plt.subplots()
img0 = ax.imshow(data[:720,:], cmap='Blues', vmin=0, vmax=1,
                  extent=[0, 30, 0, 719],
                  origin='lower', aspect="auto")
img1 = ax.imshow(data[720:,:], cmap='Reds', vmin=0, vmax=1,
                  extent=[0, 30, 720, 899],
                  origin='lower', aspect="auto")
ax.set_ylim(0, 900)
plt.show()

enter image description here

Something like

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

data = np.random.rand(50, 30) * 900

bottom = cm.get_cmap('Blues', 204)
top = cm.get_cmap('Reds', 52)

newcolors = np.vstack((bottom(np.linspace(0, 1, 204)),
                       top(np.linspace(0, 1, 52))))
newcmp = ListedColormap(newcolors, name='RedBlue')
img0 = plt.imshow(data, cmap=newcmp, vmin=0, vmax= 900,
                        origin='lower', aspect="auto")
plt.colorbar()
plt.show()

enter image description here

Jody Klymak
  • 4,979
  • 2
  • 15
  • 31
  • Thank you, Jody! That's a beautiful chart, but not quite what I'm looking for. The bottom 720 rows should be blue and the top 180 rows should be red. The chart above (which I greatly appreciate) appears to apply this logic based on the values of the cells, so cells with values above 720 are red and below 720 are blue. – da Bears Sep 05 '22 at 18:23
  • I'm going to edit my question to make this clearer--I apologize for any confusion. I'd give you a thumbs up, but do not have enough reputation points. – da Bears Sep 05 '22 at 18:24
  • Then just make two images - one with the extent to 720 and the other from 720-900 and use the colormap you want for each – Jody Klymak Sep 05 '22 at 18:37
  • Thank you so much! Now I know about the extent argument, which is making everything work perfectly. – da Bears Sep 05 '22 at 21:47
  • One question here. It appears the method you used changes the whole color scheme to "reds" so even the background has a red hue. Is there a method to change the color scheme to red/white, so the background is white? I did not see this listed as a default option in the matplotlib library. It appears the options are all based on gradients – da Bears Sep 06 '22 at 13:12
  • That is just aliasing (too many vertical bins for the size of the image). There are white bins in there. – Jody Klymak Sep 06 '22 at 16:27