0

I consider large matrices attaining values in between -1 to 1 and I wish to plot their heatmaps in python. Most values are very small, let's say around 10^{-8} but one or two entries are close to the edges. When I try the codes from the answers for this question I always get an image which is mostly unicolor with some points. For instance in this image the image is mostly red with some black points. I did try playing with vmin=np.amin(data),vmax=np.amax(data) but of course it does not solve the issue. I also tried some divergent colormaps but they didn't help much.

I wonder if matplotlib or seaborn can handle such type of data and if it is possible changing the scale/colormap so it will be wider based on the frequency of values (in the photo, that would mean I want more hues of red while keeping black points).

Minimal example which yields mostly white plot:

import numpy as np
import seaborn as sns
import matplotlib.pylab as plt
uniform_data = np.random.rand(1200, 1200)
uniform_data /= 10 ** 8
uniform_data[42,42] += 2
uniform_data[442,442] -= 2
ax = sns.heatmap(uniform_data)
plt.show()

1 Answers1

0

(Note that you should import matplotlib.pyplot as pylab is now discouraged.)

If your data is uniformly distributed in a small interval, you could use the minimum and maximum of that interval for the color range. You could change these limits by, say, 10% so the extreme values still get another color (or use cmap.set_over() and cmap.set_under() to give the extreme values a completely different color).

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

uniform_data = np.random.rand(1200, 1200)
uniform_data /= 10 ** 8
uniform_data[42, 42] += 2
uniform_data[442, 442] -= 2
vmin = uniform_data[np.abs(uniform_data) < 0.1].min()
vmin = vmin * 0.9 if vmin > 0 else vmin * 1.1
vmax = uniform_data[np.abs(uniform_data) < 0.1].max()
vmmax = vmax * 0.9 if vmax < 0 else vmax * 1.1
ax = sns.heatmap(uniform_data, vmin=vmin, vmax=vmax)
plt.show()

sns.heatmap with custom color range

If the values have very different orders of magnitude, you might use their logarithm to decide the color. With positive and negative values could be drawn in separate passes:

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

data = np.random.randn(20, 20) ** 9
pos_data = np.where(data > 0, data, np.nan)
neg_data = np.where(data < 0, data, np.nan)
fig, ax = plt.subplots()
sns.heatmap(np.log(pos_data), cmap='Blues_r', cbar=False, ax=ax)
sns.heatmap(np.log(-neg_data), cmap='Reds_r', cbar=False, ax=ax)
plt.show()

using the log to decide the color

JohanC
  • 71,591
  • 8
  • 33
  • 66