J'ai créé une simple carte thermique matplotlib où chaque cellule sera rouge ou verte si la valeur de la cellule est supérieure à 2.3.

Maintenant, au lieu d'avoir la couleur simplement rouge ou verte, j'aimerais l'avoir plus sombre ou plus clair en fonction de la différence entre la valeur de la cellule et 2.3, par exemple 1 aura un rouge plus foncé que 2.1.

Y a-t-il un moyen de faire ça? Jusqu'à présent, je n'arrivais à le faire qu'en binaire, grâce à cette question.

ax1 = fig.add_subplot(111)

a = np.array([[0.8, 2.4, 2.5, 3.9],
              [2.4, 0.0, 4.0, 1.0],
              [1.1, 2.4, 0.8, 4.3],
              [0.6, 0.0, 0.3, 0.0],
              [0.7, 1.7, 0.6, 2.6]])

cmap = matplotlib.colors.ListedColormap(['#ff3d3d', '#74ff52'])

bounds = [np.amin(a), 2.3, np.amax(a)]

norm = matplotlib.colors.BoundaryNorm(bounds, cmap.N)

ax1.imshow(a, interpolation='none', cmap=cmap, norm=norm)
0
JayK23 27 août 2020 à 00:35

2 réponses

Meilleure réponse

Un LinearSegmentedColormap peut créer un continu palette de couleurs à partir d'une liste de couleurs. Il est utile de définir explicitement une couleur au milieu (par exemple «jaune») pour créer une distinction.

Un TwoSlopeNorm peut identifier une valeur exacte pour le centre.

import matplotlib.pyplot as plt
import matplotlib
from matplotlib.ticker import MultipleLocator
import numpy as np

a = np.array([[0.8, 2.4, 2.5, 3.9],
              [2.4, 0.0, 4.0, 1.0],
              [1.1, 2.4, 0.8, 4.3],
              [0.6, 0.0, 0.3, 0.0],
              [0.7, 1.7, 0.6, 2.6]])
cmap = matplotlib.colors.LinearSegmentedColormap.from_list('', ['#ff3d3d', 'yellow', '#74ff52'])
norm = matplotlib.colors.TwoSlopeNorm(vcenter=2.3, vmin=a.min(), vmax=a.max())

fig, ax = plt.subplots()
img = ax.imshow(a, interpolation='none', cmap=cmap, norm=norm)
ax.xaxis.set_major_locator(MultipleLocator(1))
ax.yaxis.set_major_locator(MultipleLocator(1))
plt.colorbar(img, ax=ax)
plt.tight_layout()
plt.show()

À gauche, un exemple avec le jaune comme couleur centrale, au centre avec du blanc et à droite sans définir une couleur centrale explicite.

resulting plot

PS: Si la valeur centrale ne se situait pas entre le minimum et le maximum, l'image entière serait soit rouge, soit verte. Dans ce cas, vous pouvez créer la norme comme:

bounds = sorted([2.3,  a.min(), a.max()])
norm = matplotlib.colors.TwoSlopeNorm(vcenter=bounds[1], vmin=bounds[0], vmax=bounds[2])
1
JohanC 26 août 2020 à 22:39

Voici ma solution en utilisant la bibliothèque seaborn.
(Idéalement, installez matplotlib 3.1.0 sur votre PC, car matplotlib 3.1.1 peut causer des problèmes lors de l'affichage de la carte thermique).

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

a = np.array([[0.8, 2.4, 2.5, 3.9],
              [2.4, 0.0, 4.0, 1.0],
              [1.1, 2.4, 0.8, 4.3],
              [0.6, 0.0, 0.3, 0.0],
              [0.7, 1.7, 0.6, 2.6]])

#b = np.array([[1,2],[3,4]])
minVal = np.amin(a)
maxVal = np.amax(a)
diffs = abs(2.3 - a)

seaborn.heatmap(a, annot=True, linewidths=.5, square=True, vmin=np.amin(a), vmax=np.amax(a), cmap='RdYlGn')
plt.figure()
seaborn.heatmap(diffs, annot=True, linewidths=.5, square=True, vmin=np.amin(diffs), vmax=np.amax(diffs), cmap='Reds')

La première carte thermique est votre matrice 'a' originale, qui ressemblera à ceci:
asdf

La deuxième carte thermique représente les valeurs a diffère de 2,3, ce qui ressemblera à ceci: asdf

1
Jacob K 26 août 2020 à 22:10