2013-07-15 20 views
10

Mam następujący kod:Jak make „pełniejsze” strzałki osi z matplotlib

from mpl_toolkits.axes_grid.axislines import SubplotZero 
from matplotlib.transforms import BlendedGenericTransform 
import matplotlib.pyplot as plt 
import numpy 

if 1: 
    fig = plt.figure(1) 
    ax = SubplotZero(fig, 111) 
    fig.add_subplot(ax) 

    ax.axhline(linewidth=1.7, color="black") 
    ax.axvline(linewidth=1.7, color="black") 

    plt.xticks([1]) 
    plt.yticks([]) 

    ax.text(0, 1.05, 'y', transform=BlendedGenericTransform(ax.transData, ax.transAxes), ha='center') 
    ax.text(1.05, 0, 'x', transform=BlendedGenericTransform(ax.transAxes, ax.transData), va='center') 

    for direction in ["xzero", "yzero"]: 
     ax.axis[direction].set_axisline_style("-|>") 
     ax.axis[direction].set_visible(True) 

    for direction in ["left", "right", "bottom", "top"]: 
     ax.axis[direction].set_visible(False) 

    x = numpy.linspace(-0.5, 1., 1000) 
    ax.plot(x, numpy.sin(x*numpy.pi), linewidth=1.2, color="black") 

    plt.show() 

która produkuje następujący obraz:

graph

Do groty oś zajrzeć szczątkowe w porównaniu do aktualny wykres. Jak mogę je nieco powiększyć, aby wyglądały normalnie w stosunku do szerokości osi.

Również - trudno tu zobaczyć, ale wnętrze strzałek jest niebieskie - jak zmienić to na czarne?

Odpowiedz

5

Wydaje się być tak, że wezwanie do matplotlib.pyplot.arrow (z dużą dozą kalibracji) można uzyskać wymagane strzały:

plt.arrow(5, -0.003, 0.1, 0, width=0.015, color="k", clip_on=False, head_width=0.12, head_length=0.12) 
plt.arrow(0.003, 5, 0, 0.1, width=0.015, color="k", clip_on=False, head_width=0.12, head_length=0.12) 

Uwaga „0.003” offsety dla współrzędnych, dzieje się tak dlatego, że z jakiegoś powodu plt.arrow nie rysuje strzałki w linii z osią. Naprawdę? Co za ból.

Należy również zwrócić uwagę na clip_on, który pozwala strzałce przekroczyć granice ustawione dla wykresu (np. Plt.xlim (-5, 5)).

to:

from mpl_toolkits.axes_grid.axislines import SubplotZero 
from matplotlib.transforms import BlendedGenericTransform 
from matplotlib import patches 
import matplotlib.pyplot as plt 
import numpy 

if 1: 
    fig = plt.figure(1) 
    ax = SubplotZero(fig, 111) 
    fig.add_subplot(ax) 

    ax.axhline(linewidth=1.7, color="k") 
    ax.axvline(linewidth=1.7, color="k") 

    plt.xticks([]) 
    plt.yticks([]) 

    ax.text(0, 1.05, r'$y$', transform=BlendedGenericTransform(ax.transData, ax.transAxes), ha='center') 
    ax.text(1.03, 0, r'$x$', transform=BlendedGenericTransform(ax.transAxes, ax.transData), va='center') 

    for direction in ["xzero", "yzero"]: 
     ax.axis[direction].set_visible(True) 

    for direction in ["left", "right", "bottom", "top"]: 
     ax.axis[direction].set_visible(False) 

    x = numpy.linspace(-1.499999999, 5, 10000) 

    yy = numpy.log(2*x + 3)/2 + 3 

    ax.plot(x, yy, linewidth=1.2, color="black") 

    plt.ylim(-2, 5) 
    plt.xlim(-5, 5) 

    plt.arrow(5, -0.003, 0.1, 0, width=0.015, color="k", clip_on=False, head_width=0.12, head_length=0.12) 
    plt.arrow(0.003, 5, 0, 0.1, width=0.015, color="k", clip_on=False, head_width=0.12, head_length=0.12) 

    plt.text((numpy.e**(-6) - 3)/2, 0, r'$(\frac{1}{2} (e^{-6} - 3), 0)$', position=((numpy.e**(-6) - 3)/2 + 0.1, 0.1)) 
    plt.plot((numpy.e**(-6) - 3)/2, 0, 'ko') 

    plt.text(0, numpy.log(3)/2 + 3, r'$(0, \frac{1}{2} \log_e{\left (3 \right)} + 3)$', position=(0.1, numpy.log(3)/2 + 3 + 0.1)) 
    plt.plot(0, numpy.log(3)/2 + 3, 'ko') 

    plt.savefig('AnswersSA1a.png') 

produkuje wykres tak: (ignorować złe etykiety osi z osią)

graph

ja tylko umieścić to jako odpowiedź, ponieważ jest to jedyny sposób, w jaki zobacz, jak to zrobić. Z pewnością musi istnieć lepszy sposób niż ręczne opracowanie, że muszę kompensować strzałki o 0,003. To nie jest w porządku.

+0

ma ktoś znaleziono żadnych eleganckie rozwiązanie tego problemu? – Cobry

8

Moje rozwiązanie jest zasadniczo takie samo jak w przypadku nebffa. Stworzyłem minimalny przykład, który oblicza szerokość i długość grota strzałki dla osi y, aby dopasować ją do określonej dla osi X. Mam nadzieję, że może to być pomocne dla kogoś innego.

import pylab as pl 

fig = pl.figure() 
ax = fig.add_subplot(111) 

x = pl.arange(-5,5,0.1) 
ax.plot(x, x**2-8.8) 

xmin, xmax = ax.get_xlim() 
ymin, ymax = ax.get_ylim() 

# removing the default axis on all sides: 
for side in ['bottom','right','top','left']: 
    ax.spines[side].set_visible(False) 

# removing the axis ticks 
pl.xticks([]) # labels 
pl.yticks([]) 
ax.xaxis.set_ticks_position('none') # tick markers 
ax.yaxis.set_ticks_position('none') 

# wider figure for demonstration 
fig.set_size_inches(4,2.2) 

# get width and height of axes object to compute 
# matching arrowhead length and width 
dps = fig.dpi_scale_trans.inverted() 
bbox = ax.get_window_extent().transformed(dps) 
width, height = bbox.width, bbox.height 

# manual arrowhead width and length 
hw = 1./20.*(ymax-ymin) 
hl = 1./20.*(xmax-xmin) 
lw = 1. # axis line width 
ohg = 0.3 # arrow overhang 

# compute matching arrowhead length and width 
yhw = hw/(ymax-ymin)*(xmax-xmin)* height/width 
yhl = hl/(xmax-xmin)*(ymax-ymin)* width/height 

# draw x and y axis 
ax.arrow(xmin, 0, xmax-xmin, 0., fc='k', ec='k', lw = lw, 
     head_width=hw, head_length=hl, overhang = ohg, 
     length_includes_head= True, clip_on = False) 

ax.arrow(0, ymin, 0., ymax-ymin, fc='k', ec='k', lw = lw, 
     head_width=yhw, head_length=yhl, overhang = ohg, 
     length_includes_head= True, clip_on = False) 

# clip_on = False if only positive x or y values. 

pl.savefig('arrow_axis.png', dpi = 300) 

Produkuje:

enter image description here

Powiązane problemy