Noter
Cliquez ici pour télécharger l'exemple de code complet
Choisir des palettes de couleurs dans Matplotlib #
Matplotlib a un certain nombre de palettes de couleurs intégrées accessibles via
matplotlib.colormaps
. Il existe également des bibliothèques externes qui ont de nombreuses palettes de couleurs supplémentaires, qui peuvent être consultées dans la
section Palettes de couleurs tierces de la documentation Matplotlib. Ici, nous discutons brièvement de la façon de choisir entre les nombreuses options. Pour obtenir de l'aide sur la création de vos propres palettes de couleurs, consultez
Création de palettes de couleurs dans Matplotlib .
Aperçu #
L'idée derrière le choix d'une bonne palette de couleurs est de trouver une bonne représentation dans l'espace colorimétrique 3D pour votre ensemble de données. La meilleure palette de couleurs pour un ensemble de données donné dépend de nombreux facteurs, notamment :
Qu'il s'agisse de représenter un formulaire ou des données métriques ( [Ware] )
Votre connaissance de l'ensemble de données ( par exemple , existe-t-il une valeur critique à partir de laquelle les autres valeurs s'écartent ?)
S'il existe un jeu de couleurs intuitif pour le paramètre que vous tracez
S'il existe une norme dans le domaine, le public peut s'attendre à
Pour de nombreuses applications, une palette de couleurs uniforme est le meilleur choix ; c'est-à-dire une palette de couleurs dans laquelle des pas égaux dans les données sont perçus comme des pas égaux dans l'espace colorimétrique. Les chercheurs ont découvert que le cerveau humain perçoit beaucoup mieux les changements du paramètre de luminosité comme des changements dans les données que, par exemple, des changements de teinte. Par conséquent, les palettes de couleurs qui ont une luminosité croissante de manière monotone à travers la palette de couleurs seront mieux interprétées par le spectateur. De merveilleux exemples de palettes de couleurs perceptuellement uniformes peuvent également être trouvés dans la section Palettes de couleurs tierces .
La couleur peut être représentée dans l'espace 3D de différentes manières. Une façon de représenter la couleur consiste à utiliser CIELAB. Dans CIELAB, l'espace colorimétrique est représenté par la luminosité, \(L^*\); Rouge, Vert,\(a^*\); et jaune-bleu,\(b^*\). Le paramètre de luminosité\(L^*\)peut ensuite être utilisé pour en savoir plus sur la façon dont les palettes de couleurs matplotlib seront perçues par les téléspectateurs.
[IBM] est une excellente ressource de départ pour en savoir plus sur la perception humaine des palettes de couleurs .
Classes de palettes de couleurs #
Les palettes de couleurs sont souvent divisées en plusieurs catégories en fonction de leur fonction (voir, par exemple , [Moreland] ) :
Séquentiel : modification de la luminosité et souvent saturation de la couleur de manière incrémentielle, souvent en utilisant une seule teinte ; doit être utilisé pour représenter les informations qui ont un ordre.
Divergent : modification de la luminosité et éventuellement saturation de deux couleurs différentes qui se rejoignent au milieu d'une couleur non saturée ; doit être utilisé lorsque les informations tracées ont une valeur médiane critique, telle que la topographie ou lorsque les données s'écartent autour de zéro.
Cyclique : changement de luminosité de deux couleurs différentes qui se rencontrent au milieu et au début/fin d'une couleur non saturée ; doit être utilisé pour les valeurs qui s'enroulent autour des extrémités, telles que l'angle de phase, la direction du vent ou l'heure de la journée.
Qualitatif : sont souvent des couleurs diverses ; doit être utilisé pour représenter des informations qui n'ont pas d'ordre ou de relations.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from colorspacious import cspace_converter
Tout d'abord, nous allons montrer la gamme de chaque palette de couleurs. Notez que certains semblent changer plus "rapidement" que d'autres.
cmaps = {}
gradient = np.linspace(0, 1, 256)
gradient = np.vstack((gradient, gradient))
def plot_color_gradients(category, cmap_list):
# Create figure and adjust figure height to number of colormaps
nrows = len(cmap_list)
figh = 0.35 + 0.15 + (nrows + (nrows - 1) * 0.1) * 0.22
fig, axs = plt.subplots(nrows=nrows + 1, figsize=(6.4, figh))
fig.subplots_adjust(top=1 - 0.35 / figh, bottom=0.15 / figh,
left=0.2, right=0.99)
axs[0].set_title(f'{category} colormaps', fontsize=14)
for ax, name in zip(axs, cmap_list):
ax.imshow(gradient, aspect='auto', cmap=mpl.colormaps[name])
ax.text(-0.01, 0.5, name, va='center', ha='right', fontsize=10,
transform=ax.transAxes)
# Turn off *all* ticks & spines, not just the ones with colormaps.
for ax in axs:
ax.set_axis_off()
# Save colormap list for later.
cmaps[category] = cmap_list
# séquentiel
Pour les tracés séquentiels, la valeur de luminosité augmente de manière monotone à travers les palettes de couleurs. C'est bon. Certains\(L^*\)les valeurs dans les palettes de couleurs vont de 0 à 100 (binaire et l'autre échelle de gris), et d'autres commencent autour \(L^*=20\). Ceux qui ont une plus petite gamme de\(L^*\)aura donc une portée perceptuelle plus petite. Notez également que le\(L^*\)fonction varie selon les palettes de couleurs : certaines sont approximativement linéaires dans\(L^*\)et d'autres sont plus courbes.
plot_color_gradients('Perceptually Uniform Sequential',
['viridis', 'plasma', 'inferno', 'magma', 'cividis'])
plot_color_gradients('Sequential',
['Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'])
Séquentiel2 #
Beaucoup de\(L^*\)les valeurs des tracés Sequential2 augmentent de manière monotone, mais certaines (automne, frais, printemps et hiver) plafonnent ou même montent et descendent à la fois.\(L^*\)espace. D'autres (afmhot, copper, gist_heat et hot) ont des défauts dans le\(L^*\)les fonctions. Les données qui sont représentées dans une région de la palette de couleurs qui est à un plateau ou à un coude conduiront à une perception de bandes des données dans ces valeurs dans la palette de couleurs (voir [mycarta-banding] pour un excellent exemple de cela).
plot_color_gradients('Sequential (2)',
['binary', 'gist_yarg', 'gist_gray', 'gray', 'bone',
'pink', 'spring', 'summer', 'autumn', 'winter', 'cool',
'Wistia', 'hot', 'afmhot', 'gist_heat', 'copper'])
# divergent
Pour les cartes divergentes, nous voulons avoir une croissance monotone\(L^*\) valeurs jusqu'à un maximum, qui doit être proche de\(L^*=100\), suivie d'une décroissance monotone\(L^*\)valeurs. Nous recherchons un minimum approximativement égal\(L^*\)valeurs aux extrémités opposées de la palette de couleurs. Par ces mesures, BrBG et RdBu sont de bonnes options. coolwarm est une bonne option, mais elle ne couvre pas un large éventail de\(L^*\)valeurs (voir la section sur les niveaux de gris ci-dessous).
plot_color_gradients('Diverging',
['PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', 'RdYlBu',
'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'])
Cyclique #
Pour les cartes cycliques, nous voulons commencer et finir sur la même couleur et rencontrer un point central symétrique au milieu.\(L^*\)doit changer de manière monotone du début au milieu et inversement du milieu à la fin. Il doit être symétrique du côté croissant et décroissant, et ne différer que par la teinte. Aux extrémités et au milieu,\(L^*\)inversera la direction, qui devrait être lissée dans \(L^*\)espace pour réduire les artefacts. Voir [kovesi-colormaps] pour plus d'informations sur la conception des cartes cycliques.
La palette de couleurs HSV souvent utilisée est incluse dans cet ensemble de palettes de couleurs, bien qu'elle ne soit pas symétrique par rapport à un point central. De plus, le\(L^*\)les valeurs varient considérablement tout au long de la palette de couleurs, ce qui en fait un mauvais choix pour représenter les données que les téléspectateurs peuvent voir perceptuellement. Voir une extension sur cette idée sur [mycarta-jet] .
plot_color_gradients('Cyclic', ['twilight', 'twilight_shifted', 'hsv'])
Qualitatif #
Les cartes de couleurs qualitatives ne visent pas à être des cartes perceptives, mais l'examen du paramètre de luminosité peut le vérifier pour nous. La\(L^*\)les valeurs se déplacent partout dans la palette de couleurs et n'augmentent clairement pas de manière monotone. Ce ne seraient pas de bonnes options à utiliser comme palettes de couleurs perceptuelles.
plot_color_gradients('Qualitative',
['Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2',
'Set1', 'Set2', 'Set3', 'tab10', 'tab20', 'tab20b',
'tab20c'])
Divers #
Certaines des palettes de couleurs diverses ont des utilisations particulières pour lesquelles elles ont été créées. Par exemple, gist_earth, ocean et terrain semblent tous avoir été créés pour tracer ensemble la topographie (vert/marron) et les profondeurs d'eau (bleu). Nous nous attendrions donc à voir une divergence dans ces palettes de couleurs, mais plusieurs plis peuvent ne pas être idéaux, comme dans gist_earth et terrain. CMRmap a été créé pour bien convertir en niveaux de gris, bien qu'il semble avoir quelques petits défauts dans \(L^*\). cubehelix a été créé pour varier en douceur à la fois dans la luminosité et la teinte, mais semble avoir une petite bosse dans la zone de teinte verte. turbo a été créé pour afficher les données de profondeur et de disparité.
La palette de couleurs Jet souvent utilisée est incluse dans cet ensemble de palettes de couleurs. Nous pouvons voir que le\(L^*\)les valeurs varient considérablement tout au long de la palette de couleurs, ce qui en fait un mauvais choix pour représenter les données que les téléspectateurs peuvent voir perceptuellement. Voir une extension sur cette idée sur [mycarta-jet] et [turbo] .
plot_color_gradients('Miscellaneous',
['flag', 'prism', 'ocean', 'gist_earth', 'terrain',
'gist_stern', 'gnuplot', 'gnuplot2', 'CMRmap',
'cubehelix', 'brg', 'gist_rainbow', 'rainbow', 'jet',
'turbo', 'nipy_spectral', 'gist_ncar'])
plt.show()
Légèreté des colormaps Matplotlib #
Ici, nous examinons les valeurs de luminosité des palettes de couleurs matplotlib. Notez qu'une documentation sur les palettes de couleurs est disponible ( [list-colormaps] ).
mpl.rcParams.update({'font.size': 12})
# Number of colormap per subplot for particular cmap categories
_DSUBS = {'Perceptually Uniform Sequential': 5, 'Sequential': 6,
'Sequential (2)': 6, 'Diverging': 6, 'Cyclic': 3,
'Qualitative': 4, 'Miscellaneous': 6}
# Spacing between the colormaps of a subplot
_DC = {'Perceptually Uniform Sequential': 1.4, 'Sequential': 0.7,
'Sequential (2)': 1.4, 'Diverging': 1.4, 'Cyclic': 1.4,
'Qualitative': 1.4, 'Miscellaneous': 1.4}
# Indices to step through colormap
x = np.linspace(0.0, 1.0, 100)
# Do plot
for cmap_category, cmap_list in cmaps.items():
# Do subplots so that colormaps have enough space.
# Default is 6 colormaps per subplot.
dsub = _DSUBS.get(cmap_category, 6)
nsubplots = int(np.ceil(len(cmap_list) / dsub))
# squeeze=False to handle similarly the case of a single subplot
fig, axs = plt.subplots(nrows=nsubplots, squeeze=False,
figsize=(7, 2.6*nsubplots))
for i, ax in enumerate(axs.flat):
locs = [] # locations for text labels
for j, cmap in enumerate(cmap_list[i*dsub:(i+1)*dsub]):
# Get RGB values for colormap and convert the colormap in
# CAM02-UCS colorspace. lab[0, :, 0] is the lightness.
rgb = mpl.colormaps[cmap](x)[np.newaxis, :, :3]
lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb)
# Plot colormap L values. Do separately for each category
# so each plot can be pretty. To make scatter markers change
# color along plot:
# https://stackoverflow.com/q/8202605/
if cmap_category == 'Sequential':
# These colormaps all start at high lightness but we want them
# reversed to look nice in the plot, so reverse the order.
y_ = lab[0, ::-1, 0]
c_ = x[::-1]
else:
y_ = lab[0, :, 0]
c_ = x
dc = _DC.get(cmap_category, 1.4) # cmaps horizontal spacing
ax.scatter(x + j*dc, y_, c=c_, cmap=cmap, s=300, linewidths=0.0)
# Store locations for colormap labels
if cmap_category in ('Perceptually Uniform Sequential',
'Sequential'):
locs.append(x[-1] + j*dc)
elif cmap_category in ('Diverging', 'Qualitative', 'Cyclic',
'Miscellaneous', 'Sequential (2)'):
locs.append(x[int(x.size/2.)] + j*dc)
# Set up the axis limits:
# * the 1st subplot is used as a reference for the x-axis limits
# * lightness values goes from 0 to 100 (y-axis limits)
ax.set_xlim(axs[0, 0].get_xlim())
ax.set_ylim(0.0, 100.0)
# Set up labels for colormaps
ax.xaxis.set_ticks_position('top')
ticker = mpl.ticker.FixedLocator(locs)
ax.xaxis.set_major_locator(ticker)
formatter = mpl.ticker.FixedFormatter(cmap_list[i*dsub:(i+1)*dsub])
ax.xaxis.set_major_formatter(formatter)
ax.xaxis.set_tick_params(rotation=50)
ax.set_ylabel('Lightness $L^*$', fontsize=12)
ax.set_xlabel(cmap_category + ' colormaps', fontsize=14)
fig.tight_layout(h_pad=0.0, pad=1.5)
plt.show()
Conversion en niveaux de gris #
Il est important de prêter attention à la conversion en niveaux de gris pour les tracés en couleur, car ils peuvent être imprimés sur des imprimantes en noir et blanc. S'ils ne sont pas soigneusement examinés, vos lecteurs peuvent se retrouver avec des tracés indéchiffrables car les niveaux de gris changent de manière imprévisible à travers la palette de couleurs.
La conversion en niveaux de gris se fait de différentes manières [bw] . Certains des meilleurs utilisent une combinaison linéaire des valeurs RVB d'un pixel, mais pondérées en fonction de la façon dont nous percevons l'intensité des couleurs. Une méthode non linéaire de conversion en niveaux de gris consiste à utiliser la\(L^*\)valeurs des pixels. En général, des principes similaires s'appliquent à cette question comme ils le font pour présenter ses informations de manière perceptive; c'est-à-dire, si une palette de couleurs est choisie qui augmente de manière monotone dans\(L^*\)valeurs, il imprimera de manière raisonnable en niveaux de gris.
Dans cet esprit, nous voyons que les palettes de couleurs séquentielles ont des représentations raisonnables en niveaux de gris. Certaines des cartes de couleurs Sequential2 ont des représentations en niveaux de gris suffisamment décentes, bien que certaines (automne, printemps, été, hiver) aient très peu de changement en niveaux de gris. Si une palette de couleurs comme celle-ci a été utilisée dans un tracé, puis que le tracé a été imprimé en niveaux de gris, une grande partie des informations peut correspondre aux mêmes valeurs de gris. Les palettes de couleurs divergentes varient principalement du gris plus foncé sur les bords extérieurs au blanc au milieu. Certains (PuOr et sismiques) ont un gris sensiblement plus foncé d'un côté que de l'autre et ne sont donc pas très symétriques. coolwarm a peu de niveaux de gris et imprimerait un tracé plus uniforme, perdant beaucoup de détails. Notez que les contours superposés et étiquetés peuvent aider à différencier un côté de la palette de couleurs par rapport à un côté. l'autre puisque la couleur ne peut pas être utilisée une fois qu'un tracé est imprimé en niveaux de gris. De nombreuses palettes de couleurs qualitatives et diverses, telles que Accent, hsv, jet et turbo, passent du plus foncé au plus clair et reviennent au gris plus foncé dans toute la palette de couleurs. Cela rendrait impossible pour un spectateur d'interpréter les informations d'un tracé une fois qu'il est imprimé en niveaux de gris.
mpl.rcParams.update({'font.size': 14})
# Indices to step through colormap.
x = np.linspace(0.0, 1.0, 100)
gradient = np.linspace(0, 1, 256)
gradient = np.vstack((gradient, gradient))
def plot_color_gradients(cmap_category, cmap_list):
fig, axs = plt.subplots(nrows=len(cmap_list), ncols=2)
fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99,
wspace=0.05)
fig.suptitle(cmap_category + ' colormaps', fontsize=14, y=1.0, x=0.6)
for ax, name in zip(axs, cmap_list):
# Get RGB values for colormap.
rgb = mpl.colormaps[name](x)[np.newaxis, :, :3]
# Get colormap in CAM02-UCS colorspace. We want the lightness.
lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb)
L = lab[0, :, 0]
L = np.float32(np.vstack((L, L, L)))
ax[0].imshow(gradient, aspect='auto', cmap=mpl.colormaps[name])
ax[1].imshow(L, aspect='auto', cmap='binary_r', vmin=0., vmax=100.)
pos = list(ax[0].get_position().bounds)
x_text = pos[0] - 0.01
y_text = pos[1] + pos[3]/2.
fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10)
# Turn off *all* ticks & spines, not just the ones with colormaps.
for ax in axs.flat:
ax.set_axis_off()
plt.show()
for cmap_category, cmap_list in cmaps.items():
plot_color_gradients(cmap_category, cmap_list)
Déficiences de la vision des couleurs #
Il existe de nombreuses informations sur le daltonisme ( p. ex. , [daltonisme] ). De plus, il existe des outils disponibles pour convertir les images en fonction de leur apparence pour différents types de déficiences de la vision des couleurs.
La forme la plus courante de déficience de la vision des couleurs consiste à faire la différence entre le rouge et le vert. Ainsi, éviter les palettes de couleurs avec à la fois du rouge et du vert évitera de nombreux problèmes en général.
Références #
https://mycarta.wordpress.com/2012/10/06/the-rainbow-is-deadlong-live-the-rainbow-part-3/
Durée totale d'exécution du script : (0 minutes 14,251 secondes)