Cómo elegir un punto en un subplot y resaltarlo en subplots adyacentes en matplotlib (extensión a la región de puntos)

Quiero crear una matriz de diagtwig de dispersión que estará compuesta por algunos subplots. He extraído de un archivo .txt mis datos y he creado una matriz de forma (x, y, z, p1, p2, p3). Las primeras tres columnas de la matriz representan las coordenadas x, y, z de la imagen original de la que provienen estos datos y las últimas tres columnas (p1, p2, p3) algunos otros parámetros. En consecuencia, en cada fila de la matriz, los parámetros p1, p2, p3 tienen las mismas coordenadas (x, y, z). En el diagtwig de dispersión, quiero visualizar el parámetro p1 contra los parámetros p2, p3 en una primera etapa. Para cada punto que escojo, me gustaría que sus parámetros (x, y, z) de las primeras tres columnas de mi matriz estén anotados y que el punto con las mismas coordenadas en el argumento secundario resaltado o su color se modifique.

En mi código, se crean dos subplots y en el terminal se imprimen los valores (p1, p2 o p3) que se adquieren al elegir un punto, los valores respectivos del mismo punto en la subplot adyacente y el (x, y, z ) Parámetros de este punto.

Además, cuando escojo un punto en la primera subplot, el color del punto correspondiente en la segunda subplot cambia pero no al revés. Esta modificación de color solo es reconocible si redimensiono manualmente la figura. ¿Cómo podría agregar interactividad para ambas subplots sin tener que modificar la figura para notar cualquier cambio? ¿Qué tipo de modificaciones debo hacer para que esta interactividad sea factible en una matriz de diagtwig de dispersión reducida como en esta pregunta ” ¿Existe una función para hacer matrices de dispersión en matplotlib? “. No soy un usuario experimentado de python, matplotlib, por lo que cualquier tipo de ayuda será apreciada.

import numpy as np import matplotlib.pyplot as plt import pylab as pl def main(): #load data from file data = np.loadtxt(r"data.txt") plt.close("all") x = data[:, 3] y = data[:, 4] y1 = data[:, 5] fig1 = plt.figure(1) #subplot p1 vs p2 plt.subplot(121) subplot1, = plt.plot(x, y, 'bo', picker=3) plt.xlabel('p1') plt.ylabel('p2') #subplot p1 vs p3 plt.subplot(122) subplot2, = plt.plot(x, y1, 'bo', picker=3) plt.xlabel('p1') plt.ylabel('p3') plt.subplots_adjust(left=0.1, right=0.95, wspace=0.3, hspace=0.45) # art.getp(fig1.patch) def onpick(event): thisevent = event.artist valx = thisevent.get_xdata() valy = thisevent.get_ydata() ind = event.ind print 'index', ind print 'selected point:', zip(valx[ind], valy[ind]) print 'point in the adjacent subplot', x[ind], y1[ind] print '(x,y,z):', data[:, 0][ind], data[:, 1][ind], data[:, 2][ind] for xcord,ycord in zip(valx[ind], valy[ind]): plt.annotate("(x,y,z):", xy = (x[ind], y1[ind]), xycoords = ('data' ), xytext=(x[ind] - .5, y1[ind]- .5), textcoords='data', arrowprops=dict(arrowstyle="->", connectionstyle="arc3"), ) subplot2, = plt.plot(x[ind], y[ind], 'ro', picker=3) subplot1 = plt.plot(x[ind], y[ind], 'ro', picker=3) fig1.canvas.mpl_connect('pick_event', onpick) plt.show() main() 

Resultados

En conclusión, la información se imprime en el terminal, independientemente de la ttwig secundaria, cuando escojo un punto. Pero, el color se modifica solo en los puntos de la subplot derecha, cuando selecciono un punto en la subplot izquierda y no al revés. Además, el cambio de color no se nota hasta que modifico la figura (p. Ej., La muevo o la redimensionamos) y cuando elijo un segundo punto, el anterior permanece coloreado.

Cualquier tipo de contribución será apreciada. Gracias de antemano.

Ya estás en el camino correcto con tu código actual. Básicamente, simplemente está perdiendo una llamada a plt.draw() en su función onpick .

Sin embargo, en nuestra discusión en los comentarios, surgió mpldatacursor , y usted preguntó acerca de un ejemplo de cómo hacer las cosas de esa manera.

El actual HighlightingDataCursor en mpldatacursor está configurado alrededor de la idea de resaltar un artista Line2D completo, no solo un índice particular de él. (Es deliberadamente un poco limitado, ya que no hay una buena manera de dibujar un punto culminante arbitrario para cualquier artista en matplotlib, así que mantuve las partes destacadas pequeñas).

Sin embargo, podría hacer una subclase de cosas similares a esto (se supone que está utilizando plot y desea que se use lo primero que dibuje en cada eje). También estoy ilustrando usando point_labels , en caso de que quiera tener diferentes tags para cada punto que se muestra:

 import numpy as np import matplotlib.pyplot as plt from mpldatacursor import HighlightingDataCursor, DataCursor def main(): fig, axes = plt.subplots(nrows=2, ncols=2) for ax, marker in zip(axes.flat, ['o', '^', 's', '*']): x, y = np.random.random((2,20)) ax.plot(x, y, ls='', marker=marker) IndexedHighlight(axes.flat, point_labels=[str(i) for i in range(20)]) plt.show() class IndexedHighlight(HighlightingDataCursor): def __init__(self, axes, **kwargs): # Use the first plotted Line2D in each axes artists = [ax.lines[0] for ax in axes] kwargs['display'] = 'single' HighlightingDataCursor.__init__(self, artists, **kwargs) self.highlights = [self.create_highlight(artist) for artist in artists] plt.setp(self.highlights, visible=False) def update(self, event, annotation): # Hide all other annotations plt.setp(self.highlights, visible=False) # Highlight everything with the same index. artist, ind = event.artist, event.ind for original, highlight in zip(self.artists, self.highlights): x, y = original.get_data() highlight.set(visible=True, xdata=x[ind], ydata=y[ind]) DataCursor.update(self, event, annotation) main() 

introduzca la descripción de la imagen aquí

Nuevamente, esto supone que estás utilizando la plot y no, digamos, scatter . Es posible hacer esto con scatter , pero necesita cambiar una cantidad molesta de detalles. (No hay una forma general de resaltar un artista de matplotlib arbitrario, por lo que debe tener un montón de código muy detallado para tratar con cada tipo de artista de forma individual).

Espero que sea útil, al menos.