2012-03-21 12 views
6

Este es un seguimiento muy directo en this question.El artista Matplotlib se queda igual cuando se acerca, pero también se mueve con panoramización?

Usando matplotlib, me gustaría poder colocar una especie de "barra de resaltado" sobre una gama de marcadores de datos que sé que estarán en una línea horizontal recta.

Este bar/rectángulo debe ser ligeramente más alto que los marcadores y contenerlos, algo como esto para los tres marcadores a continuación:

enter image description here

Con el fin de ser una barra de resaltado sensible, tiene que tener los siguientes dos rasgos:

  • Si la trama se panoramiza, la barra se mueve con los marcadores (por lo que siempre los cubre).
  • Si se amplía la gráfica, la altura de la barra no cambia (por lo que siempre es un poco más alta que los marcadores).

Si es útil saber, estos marcadores no tienen valores y significativos (se trazan todos en y = -1), solo valores x significativos. Por lo tanto, la altura de la barra no tiene sentido en las coordenadas de datos; simplemente necesita ser siempre lo suficientemente alto como para encerrar los marcadores.

+1

No tengo tiempo para ordenarlo por completo, pero parece que será una forma de transformación combinada. Espero que esto ayude: http://matplotlib.sourceforge.net/users/transforms_tutorial.html#blended-transformations o al menos consigue que alguien comience por el camino correcto. – Paul

Respuesta

6

¡Gran pregunta! Este fue un buen desafío y requiere una combinación de cosas para lograr.

En primer lugar, tenemos que inventar una transformación que devolverá las coordenadas del dispositivo de un valor predefinido más un desplazamiento basado en el punto dado. Por ejemplo, si sabemos que queremos la barra para estar en x_pt, y_pt, a continuación, la transformación debe representar (en pseudocódigo):

def transform(x, y): 
    return x_pt_in_device + x, y_pt_in_device + y 

Una vez hecho esto, se podría utilizar esta transformación para dibujar un cuadro de 20 píxeles alrededor de un punto de datos fijo. Sin embargo, solo desea dibujar un cuadro de altura de píxel fija en la dirección y, pero en la dirección x desea una escala de datos estándar.

Por lo tanto, necesitamos crear una transformación combinada que pueda transformar las coordenadas xey de forma independiente. Todo el código para hacer lo que está pidiendo:

import matplotlib.pyplot as plt 
import matplotlib.patches as mpatches 
import matplotlib.path as mpath 
import matplotlib.transforms as mtrans 

import numpy as np 


class FixedPointOffsetTransform(mtrans.Transform): 
    """ 
    Always returns the same transformed point plus 
    the given point in device coordinates as an offset. 
    """ 
    def __init__(self, trans, fixed_point): 
     mtrans.Transform.__init__(self) 
     self.input_dims = self.output_dims = 2 
     self.trans = trans 
     self.fixed_point = np.array(fixed_point).reshape(1, 2) 

    def transform(self, values): 
     fp = self.trans.transform(self.fixed_point) 
     values = np.array(values) 
     if values.ndim == 1: 
      return fp.flatten() + values 
     else: 
      return fp + values 


plt.scatter([3.1, 3.2, 3.4, 5], [2, 2, 2, 6]) 

ax = plt.gca() 
fixed_pt_trans = FixedPointOffsetTransform(ax.transData, (0, 2)) 

xdata_yfixed = mtrans.blended_transform_factory(ax.transData, fixed_pt_trans) 


x = [3.075, 3.425] # x range of box (in data coords) 
height = 20 # of box in device coords (pixels) 
path = mpath.Path([[x[0], -height], [x[1], -height], 
        [x[1], height], [x[0], height], 
        [x[0], -height]]) 
patch = mpatches.PathPatch(path, transform=xdata_yfixed, 
          facecolor='red', edgecolor='black', 
          alpha=0.4, zorder=0) 
ax.add_patch(patch) 

plt.show() 
+0

Verdaderamente excelente, muchas gracias. Me atrasé en otros errores y me limité a implementar esto, ¡qué mejoría! Creo que este tipo de barra de resaltado es una buena adición a mpl, también. Gran trabajo, daría más de +1 si pudiera. : D – Chelonian

+0

Gracias @Chelonian. Es posible que haya pasado por alto una respuesta más simple en el sentido de que probablemente sea más fácil crear un nuevo tipo de artista (http://matplotlib.sourceforge.net/users/artists.html). Si alguien más está interesado en producir exactamente el mismo resultado que mi respuesta usando un artista, estaría muy interesado en verlo. – pelson

Cuestiones relacionadas