2015-01-02 3 views
2

Есть ли способ установить границы клипа для matplotlib.text.Annotation?Обрезание аннотаций в matplotlib

import matplotlib.pyplot as plt 
from matplotlib.transforms import Bbox 

fig, ax = plt.subplots() 
vals = [ 
     (10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"), 
     (30,20, "Pellentesque scelerisque congue fermentum."), 
     (50,10, "Aliquam erat volutpat") 
] 
ax.set_ylim(0,1) 
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1), facecolors=('yellow','red','green')) 
for v in vals: 
    ax.annotate(
     v[2], 
     xy=(v[0],0.4), 
     clip_on=True, 
     clip_box=Bbox([[v[0],0],[v[0]+v[1],1]]) 
    ) 

plt.show() 

Я попытался установить clip_box & clip_path на ax.annotate звонки, но это не работает. enter image description here

+2

Что такое использование случай, когда вы используете 'broken_bar_h'? – tacaswell

+1

Я нашел его идеальным инструментом для визуализации телешоу ([пример] (http://cl.ly/image/0T3g2A301b3r)). Некоторое время назад я делал подобное в ggplot, и там я полагался на 'aes (xmin =, xmax =, ymin =, ymax =)' – trnl

+0

Интересно. Это довольно крутая фигура! – tacaswell

ответ

4

Во-первых, хороший вопрос! Вы погружаетесь в подробные детали, поэтому есть довольно много полудокументированных деталей, которые вам нужно знать.

Ваш текущий метод будет работать за исключением двух вещей:

  1. clip_box, как ожидается, будет в координатах дисплея, так что вам нужно, чтобы преобразовать его.
  2. Для этого недостаточно использовать «равнину» Bbox. Для преобразования координат данных, которые необходимо переделать каждый раз при изменении дисплея, вам необходимо использовать TransformedBbox.

Чтобы продемонстрировать немного больше того, что происходит, давайте исправим первую проблему, но не второй:

import matplotlib.pyplot as plt 
from matplotlib.transforms import Bbox 

fig, ax = plt.subplots() 
vals = [ 
     (10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"), 
     (30,20, "Pellentesque scelerisque congue fermentum."), 
     (50,10, "Aliquam erat volutpat") 
] 
ax.set_ylim(0,1) 
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1), 
       facecolors=('yellow','red','green')) 
for v in vals: 
    box = Bbox([[v[0],0],[v[0]+v[1],1]]).transformed(ax.transData) 
    anno = ax.annotate(v[2], xy=(v[0],0.4), clip_box=box) 

plt.show() 

enter image description here

Он хорошо выглядит на первый, но есть еще одна проблема : Поскольку clip_box является статическим и в координатах отображения, он будет находиться в неправильном положении, как только вы измените сюжет каким-либо образом (например, масштабирование, панорамирование, автомасштабирование, изменение размера окна фигуры, изменение фигуры DPI).

Например, если я нажал кнопку «Сохранить» (или позвонил savefig), поле клипа будет неправильным, потому что DPI рисунка будет изменен (от 80 до 100) перед сохранением!

enter image description here

По этой причине, вы должны использовать TransformedBbox для этого. Это всего лишь версия Bbox, которая сохраняет ссылку на преобразование и преобразует базовый Bbox, если изменение изменится. Есть несколько классов Transformed* по этим линиям в matplotlib: например. TransformedPath и т. Д. Они не являются уровнем детализации, о котором вы всегда должны знать, но они могут быть очень полезными.

В качестве последнего примера, что не будет работать правильно, независимо от того, как масштабируется сюжет/панорамирование/изменено:

import matplotlib.pyplot as plt 
from matplotlib.transforms import TransformedBbox, Bbox 

fig, ax = plt.subplots() 
vals = [ 
     (10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"), 
     (30,20, "Pellentesque scelerisque congue fermentum."), 
     (50,10, "Aliquam erat volutpat") 
] 
ax.set_ylim(0,1) 
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1), 
       facecolors=('yellow','red','green')) 
for v in vals: 
    box = TransformedBbox(Bbox([[v[0],0],[v[0]+v[1],1]]), ax.transData) 
    anno = ax.annotate(v[2], xy=(v[0],0.4), clip_box=box) 

plt.show() 

enter image description here

+1

Ничего себе, спасибо, это очень полный ответ! Одно из которых я нашел - если вы устанавливаете clip_box на границы определенного сломанного_бара, тогда значение 'clip_on = True' отбрасывается, поэтому для его исправления вам нужно обратить внимание на' ax.get_xlim() 'while создавая 'TransformedBbox'. – trnl

+0

http://matplotlib.org/users/transforms_tutorial.html является полезным дополнением к этому ответу. – trnl

Смежные вопросы