2015-05-06 9 views
7

Czy istnieje sposób określenia krawędzi dla matplotlib's Rectangle patch, tak aby ramka znajdowała się poza podaną domeną? W programie Photoshop nazywałby się na przykład "pozycją obrysu". Pozwala mi ilustrują przykład:Ustaw krawędź prostokąta matplotlib na zewnątrz określonej szerokości?

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.patches import Rectangle 


# Here's my "image" 
X = np.arange(16).reshape(4,4) 

# Suppose I want to highlight some feature in the middle boxes. 
fig = plt.figure() 
ax = fig.add_subplot(111) 
ax.imshow(X, cmap=plt.cm.gray, interpolation='nearest') 
ax.add_patch(Rectangle((0.5, 0.5), 2, 2, fc='none', ec='r')) 
plt.show() 

Daje to następujące:

enter image description here

Jednakże, w przypadku zmian wyżej następująco

ax.add_patch(Rectangle((0.5, 0.5), 2, 2, fc='none', ec='r', lw=10)) 

ja otrzymać postać:

enter image description here

Jak widać, krawędź jest umieszczona centralnie wzdłuż granicy domeny obiektu Rectangle, a więc spływa do tej domeny. Czy możliwe jest wymuszenie, aby krawędź krawędzi znajdowała się poza domeną Prostokąta?

+0

myślę, że to nieco dziwniejsze, że granica krwawienia * z * domeny prostokąta, nawet. Wydaje mi się, że tak czy inaczej rozwiązaniem jest przetłumaczenie _pointów_, w których szerokość linii jest określona we współrzędnych, z którymi definiowany jest Prostokąt (zwykle współrzędne danych, może to być dowolna transformacja), a następnie dostosuj 'x, y' prostokąta. Co wyraźnie jest kłopotliwe. Może jest coś w "patheffects". – cphlewis

+0

Więc, w zasadzie narysuj większy prostokąt i odpowiednio dopasuj '(x, y)'? Myślałem o czymś podobnym, ale "linewidth" wydaje się być oparty na bieżącym rozmiarze, a nie pikselach. Nie mogę znaleźć w dokumentacji, jak to jest określone: ​​mówi tylko o "wartości float w punktach": http://matplotlib.org/api/lines_api.html#matplotlib.lines.Line2D.set_linewidth –

+0

(grzebany w "patheffects" dla bitu informującego o tym, co potrafi Strokes: offset, ale nie, AFAICT, rodzaj rozszerzenia i pułapkowania, jakie mogą zrobić programy drukujące. Myślę, że dostosowanie 'x, y' będzie konieczne.) – cphlewis

Odpowiedz

1

Możesz użyć numeru AnnotationBbox, w środku którego znajduje się AuxTransformBox. Ten AuxTransformBox będzie zawierał prostokąt proxy o pożądanym rozmiarze. Można to uczynić niewidocznym (na przykład fc='none', ec='none'). Jego jedyną funkcją jest skalowanie AuxTransformBox w odpowiednim rozmiarze. Teraz AnnotationBbox może otrzymać ramkę o dużej szerokości linii. Jeśli siedzi mocno przy AuxTransformBox, granica zacznie się tylko wtedy, gdy kończy się AuxTransformBox. Aby szczelnie dopasować obramowanie, można ustawić wyściółkę pad na połowę szerokości linii obramowania. Ponieważ padding jest podany w jednostkach fontsize, to rozmiar czcionki musi być ustawiony na szerokość linii i dopełnienie do 0.5, pad=0.5,fontsize=linewidth. Zauważ, że wydaje się, że nieco większa wyściółka o wartości 0,52 wygląda ładniej na działce; w każdym razie można to dostosować do własnych upodobań.

Brzmi skomplikowanie, ale kod jest kopiowany i nadaje się do wklejenia w celu użycia w dowolnym miejscu, w którym zwykle byłby używany prostokąt.

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.patches import Rectangle 
from matplotlib.offsetbox import AnnotationBbox, AuxTransformBox 


# Here's my "image" 
X = np.arange(16).reshape(4,4) 

# Suppose I want to highlight some feature in the middle boxes. 
fig = plt.figure() 
ax = fig.add_subplot(111) 
ax.imshow(X, cmap=plt.cm.gray, interpolation='nearest', aspect="auto") 

linewidth=14 
xy, w, h = (0.5, 0.5), 2, 2 
r = Rectangle(xy, w, h, fc='none', ec='gold', lw=1) 

offsetbox = AuxTransformBox(ax.transData) 
offsetbox.add_artist(r) 
ab = AnnotationBbox(offsetbox, (xy[0]+w/2.,xy[1]+w/2.), 
        boxcoords="data", pad=0.52,fontsize=linewidth, 
        bboxprops=dict(facecolor = "none", edgecolor='r', 
           lw = linewidth)) 
ax.add_artist(ab) 


plt.show() 

enter image description here

Powiązane problemy