2016-05-29 18 views
10

qual è il modo giusto per disegnare una freccia che torna indietro per puntare alla sua origine in matplotlib? ho provato:come creare la freccia che esegue il loop in matplotlib?

plt.figure() 
plt.xlim([0, 1]) 
plt.ylim([0, 1]) 
plt.annotate("", xy=(0.6, 0.9), 
      xycoords="figure fraction", 
      xytext = (0.6, 0.8), 
      textcoords="figure fraction", 
      fontsize = 10, \ 
      color = "k", 
      arrowprops=dict(edgecolor='black', 
          connectionstyle="angle,angleA=-180,angleB=45", 
          arrowstyle = '<|-', 
          facecolor="k", 
          linewidth=1, 
          shrinkA = 0, 
          shrinkB = 0)) 
plt.show() 

questo non dà il risultato giusto:

arrow

le connectionstyle argomenti sono difficili da seguire da questa pagina (http://matplotlib.org/users/annotations_guide.html).

sto cercando è qualcosa di simile this o this:

loopy arrow

aggiornamento: la risposta legata al non mostra come farlo con plt.annotate che ha altre caratteristiche che voglio usare. la proposta di utilizzare il marcatore $\circlearrowleft$ non è una soluzione reale.

risposta

3

sembra che il modo più semplice per creare una freccia looping facilmente modificabile è quello di utilizzare patches. Ho incollato il codice per farlo qui sotto. Cambia le variabili nella sezione delle variabili e le cose dovrebbero ruotare e scalare insieme. Puoi giocare con la patch che crea la freccia per creare una forma diversa, anche se sospetto che questo triangolo sia il più facile.

%matplotlib inline 
# from __future__ import division #Uncomment for python2.7 
import matplotlib.pyplot as plt 
from matplotlib.patches import Arc, RegularPolygon 
import numpy as np 
from numpy import radians as rad 

fig = plt.figure(figsize=(9,9)) 
ax = plt.gca() 
def drawCirc(ax,radius,centX,centY,angle_,theta2_,color_='black'): 
    #========Line 
    arc = Arc([centX,centY],radius,radius,angle=angle_, 
      theta1=0,theta2=theta2_,capstyle='round',linestyle='-',lw=10,color=color_) 
    ax.add_patch(arc) 


    #========Create the arrow head 
    endX=centX+(radius/2)*np.cos(rad(theta2_+angle_)) #Do trig to determine end position 
    endY=centY+(radius/2)*np.sin(rad(theta2_+angle_)) 

    ax.add_patch(     #Create triangle as arrow head 
     RegularPolygon(
      (endX, endY),   # (x,y) 
      3,      # number of vertices 
      radius/9,    # radius 
      rad(angle_+theta2_),  # orientation 
      color=color_ 
     ) 
    ) 
    ax.set_xlim([centX-radius,centY+radius]) and ax.set_ylim([centY-radius,centY+radius]) 
    # Make sure you keep the axes scaled or else arrow will distort 

drawCirc(ax,1,1,1,0,250) 
drawCirc(ax,2,1,1,90,330,color_='blue') 
plt.show()  

enter image description here

3

Prova questo:

import matplotlib.pyplot as plt 

fig = plt.figure() 
ax = fig.add_subplot(1,1,1) 
ax.set_xlim(1,3) 
ax.set_ylim(1,3) 
ax.plot([2.5],[2.5],marker=r'$\circlearrowleft$',ms=100) 
plt.show() 

enter image description here

+1

Mi piacerebbe utilizzare gli stili di freccia in '' plt.annotate'', non questa freccia. anche questo non offre alcuna flessibilità in merito all'angolo o alla dimensione della freccia, ecc. la tua soluzione si basa anche su tex e sui font tex. – mvd

3

Il mio suggerimento usa solo il comando plot

import matplotlib.pyplot as plt 
import numpy as np 


def circarrowdraw(x0, y0, radius=1, aspect=1, direction=270, closingangle=-330, 
        arrowheadrelativesize=0.3, arrowheadopenangle=30, *args): 
    """ 
    Circular arrow drawing. x0 and y0 are the anchor points. 
    direction gives the angle of the circle center relative to the anchor 
    in degrees. closingangle indicates how much of the circle is drawn 
    in degrees with positive being counterclockwise and negative being 
    clockwise. aspect is important to make the aspect of the arrow 
    fit the current figure. 
    """ 

    xc = x0 + radius * np.cos(direction * np.pi/180) 
    yc = y0 + aspect * radius * np.sin(direction * np.pi/180) 

    headcorrectionangle = 5 

    if closingangle < 0: 
     step = -1 
    else: 
     step = 1 
    x = [xc + radius * np.cos((ang + 180 + direction) * np.pi/180) 
     for ang in np.arange(0, closingangle, step)] 
    y = [yc + aspect * radius * np.sin((ang + 180 + direction) * np.pi/180) 
     for ang in np.arange(0, closingangle, step)] 

    plt.plot(x, y, *args) 

    xlast = x[-1] 
    ylast = y[-1] 

    l = radius * arrowheadrelativesize 

    headangle = (direction + closingangle + (90 - headcorrectionangle) * 
       np.sign(closingangle)) 

    x = [xlast + 
     l * np.cos((headangle + arrowheadopenangle) * np.pi/180), 
     xlast, 
     xlast + 
     l * np.cos((headangle - arrowheadopenangle) * np.pi/180)] 
    y = [ylast + 
     aspect * l * np.sin((headangle + arrowheadopenangle) * np.pi/180), 
     ylast, 
     ylast + 
     aspect * l * np.sin((headangle - arrowheadopenangle) * np.pi/180)] 

    plt.plot(x, y, *args) 

per testarlo:

plt.figure() 
plt.plot(np.arange(10)**2, 'b.') 
bb = plt.gca().axis() 
asp = (bb[3] - bb[2])/(bb[1] - bb[0]) 
circarrowdraw(6, 36 , radius=0.4, aspect=asp, direction=90) 
plt.grid() 
plt.show() 

enter image description here

7

trovo alcun modo per fare un ciclo usando plt.annotate solo una volta, ma utilizzando quattro volte così:

import matplotlib.pyplot as plt 

fig,ax = plt.subplots() 

# coordinates of the center of the loop 
x_center = 0.5 
y_center = 0.5 

radius = 0.2 
# linewidth of the arrow 
linewidth = 1 

ax.annotate("", (x_center + radius, y_center), (x_center, y_center + radius), 
      arrowprops=dict(arrowstyle="-", 
          shrinkA=10, # creates a gap between the start point and end point of the arrow 
          shrinkB=0, 
          linewidth=linewidth, 
          connectionstyle="angle,angleB=-90,angleA=180,rad=10"))  

ax.annotate("", (x_center, y_center - radius), (x_center + radius, y_center), 
      arrowprops=dict(arrowstyle="-", 
          shrinkA=0, 
          shrinkB=0, 
          linewidth=linewidth, 
          connectionstyle="angle,angleB=180,angleA=-90,rad=10"))  

ax.annotate("", (x_center - radius, y_center), (x_center, y_center - radius), 
      arrowprops=dict(arrowstyle="-", 
          shrinkA=0, 
          shrinkB=0, 
          linewidth=linewidth, 
          connectionstyle="angle,angleB=-90,angleA=180,rad=10"))  
ax.annotate("", (x_center, y_center + radius), (x_center - radius, y_center), 
      arrowprops=dict(arrowstyle="-|>", 
          facecolor="k", 
          linewidth=linewidth, 
          shrinkA=0, 
          shrinkB=0, 
          connectionstyle="angle,angleB=180,angleA=-90,rad=10")) 


plt.show() 

enter image description here

1

Un'altra possibilità è quella di utilizzare tikz per generare figura:

\documentclass {minimal} 
    \usepackage {tikz} 
    \begin{document} 
    \usetikzlibrary {arrows} 
    \begin {tikzpicture}[scale=1.8] 
    \draw[-angle 90, line width=5.0mm, rounded corners=20pt] 
    (0.25,0)-- (1.0, 0.0) -- (1.0, -3.0) -- (-3.0, -3.0) -- (-3.0, 0) --(-1,0); 
    \end{tikzpicture} 
    \end{document} 

Questo è il risultato: enter image description here

c'è un backg di pgf/tikz in matplotlib che è possibile d genera l'output matplotlib sul codice tikz che può essere elaborato da pdflatex o lualatex. In questo modo, penso, potresti inserire perfettamente la figura looparrow in la tua figura matplotlib. Vedere ad esempio: http://matplotlib.org/users/whats_new.html#pgf-tikz-backend

Problemi correlati