Trazando una matriz numpy 2d con colores personalizados

Tengo una matriz numpy 2d que quiero trazar para poder ver cómo se posiciona cada categoría en la cuadrícula. La matriz (mat) se ve algo como esto:

156 138 156 1300 137 156 138 138 1300 137 137 137 

Traje esto como sigue:

  plt.imshow(mat, cmap='tab20', interpolation='none') 

Sin embargo, quiero tener colores personalizados. Tengo un csv donde los identificadores se corresponden con los valores en la matriz:

 id,R,G,B 156,200,200,200 138,170,255,245 137,208,130,40 1300,63,165,76 

¿Hay alguna manera de que los valores en la matriz se correspondan con los valores R, G, B en el archivo csv?

Edición: alguien solicitó una aclaración pero se eliminó la respuesta completa.

cada fila tiene un ID y 3 columnas, que representan los valores R, G y B respectivos. Así que la primera fila tiene ID 156 (un código específico de dominio) con R 200, G 200 y B 200 (que es gris).

Ahora tengo una matriz 2d que quiero trazar, y en cada coordenada donde el valor es 156 quiero que el píxel sea gris. Lo mismo con ID 1300, donde los colores 63, 165 y 76 representan un color verde que quiero usar en la matriz.

Utilizando un mapa de colores

En principio, la matriz con valores RGB es algún tipo de mapa de colores. Tiene sentido usar un mapa de colores en matplotlib para obtener los colores de una ttwig. Lo que hace esto un poco más complicado aquí es que los valores no están bien espaciados. Así que una idea sería mapearlos a enteros comenzando en 0 primero. Luego, crear un mapa de colores a partir de esos valores y usarlo con un BoundaryNorm permite tener una barra de colores equidistante. Finalmente, uno puede poner las marcas de verificación de la barra de colores de nuevo a los valores iniciales.

 import numpy as np import matplotlib.pyplot as plt import matplotlib.colors a =np.array([[156, 138, 156], [1300, 137, 156], [138, 138, 1300], [137, 137, 137]]) ca = np.array([[156,200,200,200], [138,170,255,245], [137,208,130,40], [1300,63,165,76]]) u, ind = np.unique(a, return_inverse=True) b = ind.reshape((a.shape)) colors = ca[ca[:,0].argsort()][:,1:]/255. cmap = matplotlib.colors.ListedColormap(colors) norm = matplotlib.colors.BoundaryNorm(np.arange(len(ca)+1)-0.5, len(ca)) plt.imshow(b, cmap=cmap, norm=norm) cb = plt.colorbar(ticks=np.arange(len(ca))) cb.ax.set_yticklabels(np.unique(ca[:,0])) plt.show() 

introduzca la descripción de la imagen aquí

Trazado de matriz RGB

Puede crear una matriz RGB a partir de sus datos para trazar directamente como imshow . Para este fin, puede indexar la matriz original con los colores de la matriz de color y cambiar la forma de la matriz resultante de modo que tenga la forma correcta para ser representada con imshow.

 import numpy as np import matplotlib.pyplot as plt a =np.array([[156, 138, 156], [1300, 137, 156], [138, 138, 1300], [137, 137, 137]]) ca = np.array([[156,200,200,200], [138,170,255,245], [137,208,130,40], [1300,63,165,76]]) u, ind = np.unique(a, return_inverse=True) c = ca[ca[:,0].argsort()][:,1:]/255. b = np.moveaxis(c[ind][:,:,np.newaxis],1,2).reshape((a.shape[0],a.shape[1],3)) plt.imshow(b) plt.show() 

El resultado es el mismo que el anterior, pero sin barra de colores (ya que no hay una cantidad que asignar aquí).

No es particularmente elegante, pero es simple.

 In [72]: import numpy as np In [73]: import matplotlib.pyplot as plt In [74]: a = np.mat("156 138 156;1300 137 156;138 138 1300;137 137 137") In [75]: d = { 156: [200, 200, 200], ...: 138: [170, 255, 245], ...: 137: [208, 130, 40], ...: 1300: [63, 165, 76]} In [76]: image = np.array([[d[val] for val in row] for row in a], dtype='B') In [77]: plt.imshow(image); 

la trama está aquí

El punto es generar una matriz del tipo de dtype correcto (‘B’ codifica un entero sin signo corto) que contiene las tuplas RGB correctas (y desempaquetadas).


Apéndice

Después de un intercambio de comentarios después de la pregunta original en este Anexo, propondré una posible solución al problema de trazar el mismo tipo de datos usando plt.scatter() (el problema fue un poco más difícil de lo que esperaba …)

 import numpy as np import matplotlib.pyplot as plt from random import choices, randrange ######## THIS IS FOR IMSHOW ###################################### # the like of my previous answer values = [20,150,900,1200] rgb = lambda x=255:(randrange(x), randrange(x), randrange(x)) colord = {v:rgb() for v in values} nr, nc = 3, 5 data = np.array(choices(values, k=nr*nc)).reshape((nr,nc)) c = np.array([[colord[v] for v in row] for row in data], dtype='B') ######## THIS IS FOR SCATTER ###################################### # This is for having the coordinates of the scattered points, note that rows' indices # map to y coordinates and columns' map to x coordinates y, x = np.array([(i,j) for i in range(nr) for j in range(nc)]).T # Scatter does not expect a 3D array of uints but a 2D array of RGB floats c1 = (c/255.0).reshape(nr*nc,3) ######## THIS IS FOR PLOTTING ###################################### # two subplots, plot immediately the imshow f, (ax1, ax2) = plt.subplots(nrows=2) ax1.imshow(c) # to make a side by side comparison we set the boundaries and aspect # of the second plot to mimic imshow's ax2.set_ylim(ax1.get_ylim()) ax2.set_xlim(ax1.get_xlim()) ax2.set_aspect(1) # and finally plot the data --- the size of dots `s=900` was by trial and error ax2.scatter(x, y, c=c1, s=900) plt.show() 

introduzca la descripción de la imagen aquí

Las pandas pueden ayudarte a recostackr datos:

 im = pd.read_clipboard(header=None) # from your post colours = pd.read_clipboard(index_col=0,sep=',') # from your post 

Pandas ayuda también para el mapa de colores:

 colordf = colours.reindex(arange(1301)).fillna(0).astype(np.uint8) 

Y numpy.take construye la imagen:

 rgbim = colordf.values.take(im,axis=0)) 

plt.imshow(rgbim):

introduzca la descripción de la imagen aquí

Usando pandas y numpy, (Editar para matriz nxm):

 import numpy as np import pandas as pd import matplotlib.pyplot as plt n = 2 m = 2 df = pd.read_csv('matrix.txt') id = df.id.values id = np.reshape(id, (n, m)) R = df.R.values R = np.reshape(R/255, (n, m)) G = df.R.values G = np.reshape(G/255, (n, m)) B = df.B.values B = np.reshape(B/255, (n, m)) img = [] for i in range(n): img.append([]) for j in range(m): img[i].append((R[i][j], G[i][j], B[i][j])) plt.imshow(img) plt.show()