2017-07-04 5 views
1

Ich versuche herauszufinden, wie man das folgende richtig zeichnet.Wie zeichne Graph Stick mit gedrehten Rechteck richtig in Matplotlib?

Sagen wir, ich habe zwei Knoten, d. H. 2 Punkte in R^2, nämlich src = (x1, y1) und dst = (x2, y2).

Ich möchte eine Kante/Linie zwischen ihnen, aber beginnend mit einer Box.

Dies ist ein Beispiel, das ich mit tikz erstellt: enter image description here

src und dest sind die Zentren dieser Knoten. Beachten Sie, dass sie auch auf verschiedenen Höhen sein können. Das Problem ist, wenn ich versuche, die Box (mit patches.Rectangle) zu bauen, muss ich es drehen und dann ändert es seine Größe.

Vielen Dank im Voraus

Antwort

2

Wenn Sie gerne einen gefüllten rectange für die Grafik mit einem gedrehten Rechteck als Stick zu verwenden, kann dies durch eine einfache Linie emuliert wird, die bei der so dick wie ein Streupunkt ist Diagrammkanten.

import matplotlib.pyplot as plt 
import numpy as np 

def plot_spec_line(src, dst, length=0.3, srctext="v", dsttext="w", 
        ax=None, color="k", textcolor="k"): 
    if not ax: ax=plt.gca() 
    lend=src+(dst-src)*length 
    ax.plot([src[0],lend[0]], [src[1],lend[1]], lw=24,solid_capstyle="butt", zorder=1, color=color) 
    ax.plot([src[0],dst[0]], [src[1],dst[1]], lw=2,solid_capstyle="butt", zorder=0, color=color) 
    ax.scatter([src[0],dst[0]], [src[1],dst[1]], s=24**2, marker="o", lw=2, edgecolors=color, c="w", zorder=2) 
    ax.text(src[0],src[1], srctext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor) 
    ax.text(dst[0],dst[1], dsttext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor) 

s = np.array([1,1]) 
d = np.array([3,2])  
plot_spec_line(s, d, length=0.3, srctext="v", dsttext="w") 

s = np.array([1.5,0.9]) 
d = np.array([2.8,1.2])  
plot_spec_line(s, d, length=0.2, srctext="a", dsttext="b", color="gray") 

s = np.array([1,2]) 
d = np.array([2,1.9])  
plot_spec_line(s, d, length=0.7, srctext="X", dsttext="Y", textcolor="limegreen", color="limegreen") 

plt.margins(0.2) 
plt.show() 

enter image description here


ein Rechteck zu erhalten, das oder nicht, und mehr imporatantly gefüllt werden kann, eine Kante hat, können Sie eine Rectangle verwenden. Sie können rotate a rectangle durch Festlegen einer geeigneten Transformation. Es ist dann sinnvoll, ein Diagramm mit gleichem Seitenverhältnis zu verwenden, so dass das Rechteck und die Kreise nicht verzerrt sind.

import matplotlib.pyplot as plt 
import matplotlib.transforms 
import numpy as np 

def plot_spec_line(src, dst, length=0.3, radius=0.1, srctext="v", dsttext="w", 
        ax=None, color="k", textcolor="k", reccolor="w", lw=1): 
    if not ax: ax=plt.gca() 
    lend=np.sqrt(np.sum(((dst-src)*length)**2)) 
    s = dst-src 
    angle = np.rad2deg(np.arctan2(s[1],s[0])) 
    delta = np.array([0,radius]) 
    tr = matplotlib.transforms.Affine2D().rotate_deg_around(src[0],src[1], angle) 
    t = tr + ax.transData 
    rec = plt.Rectangle(src-delta, width=lend, height=radius*2, ec=color,facecolor=reccolor, transform=t, linewidth=lw) 
    ax.add_patch(rec) 
    ax.plot([src[0],dst[0]], [src[1],dst[1]], lw=lw,solid_capstyle="butt", zorder=0, color=color) 
    circ1= plt.Circle(src, radius=radius, fill=True, facecolor="w", edgecolor=color, lw=lw) 
    circ2= plt.Circle(dst, radius=radius, fill=True, facecolor="w", edgecolor=color, lw=lw) 
    ax.add_patch(circ1) 
    ax.add_patch(circ2) 
    ax.text(src[0],src[1], srctext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor) 
    ax.text(dst[0],dst[1], dsttext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor) 

s = np.array([1,1]) 
d = np.array([3,2])  
plot_spec_line(s, d, length=0.3, srctext="v", dsttext="w", radius=0.06, 
       reccolor="plum",) 

s = np.array([1.5,0.9]) 
d = np.array([2.8,1.2])  
plot_spec_line(s, d, length=0.2, srctext="a", dsttext="b", color="gray", lw=2.5) 

s = np.array([1,2]) 
d = np.array([2,1.9])  
plot_spec_line(s, d, length=0.7, srctext="X", dsttext="Y", textcolor="limegreen", 
       reccolor="palegreen", color="limegreen") 

plt.margins(0.2) 
plt.gca().set_aspect("equal") 
plt.show() 

enter image description here

+0

Dank, dass genau das, was ich brauchte. – Doc

+0

Obwohl es schön wäre zu wissen, wie man dasselbe zeichnet, ohne gefüllt zu werden. Was könnte ein Ansatz sein? – Doc

+1

Hier ist der Trick, eine Linie zu verwenden, die per Definition "gefüllt" ist. Wenn Sie ein ungefülltes Rechteck wünschen, haben Sie zwei Möglichkeiten: (a) Verwenden Sie ein 'Rectangle' und drehen Sie es oder (b), um ein' PathPatch' zu verwenden. Im ersten Fall besteht die Herausforderung darin, den Drehpunkt zu finden, im zweiten Fall müssen die Koordinaten der Eckpunkte berechnet werden. Ich könnte Ihnen mit einer der Lösungen helfen, aber zuerst wollte ich sicherstellen, dass die oben genannte (gefüllte) Lösung nicht das ist, was Sie wollen. – ImportanceOfBeingErnest

Verwandte Themen