2013-07-15 29 views
10

Tôi có đoạn mã sau:Làm thế nào để làm cho 'đầy đủ' mũi tên trục với 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() 

trong đó sản xuất hình ảnh sau:

graph

Các mũi tên trục trông thoái hóa so với đồ thị thực tế. Làm thế nào để tôi kích thước chúng lên một chút để chúng trông bình thường đối với chiều rộng của các trục.

Ngoài ra - rất khó để thấy ở đây, nhưng bên trong mũi tên có màu xanh dương - làm cách nào để thay đổi màu đen?

Trả lời

5

Nó có vẻ là trường hợp mà một cuộc gọi đến matplotlib.pyplot.arrow (với một số lượng hợp lý của hiệu chuẩn) có thể nhận được các mũi tên yêu cầu:

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) 

Lưu ý "0,003" offsets cho các tọa độ, điều này là vì một số lý do plt.arrow không vẽ mũi tên theo trục. Có thật không? Thật là một nỗi đau.

Cũng lưu ý là clip_on cho phép mũi tên mở rộng qua các ranh giới được đặt cho biểu đồ (như plt.xlim (-5, 5)).

này:

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') 

tạo ra một biểu đồ như sau: (bỏ qua các nhãn trục-đánh chặn nghèo)

graph

tôi chỉ đặt này như một câu trả lời vì đó là cách duy nhất tôi xem làm thế nào để làm điều đó. Chắc chắn phải có một cách tốt hơn so với làm việc bằng tay ra rằng tôi cần phải được bù đắp mũi tên bằng 0,003. Điều đó không cảm thấy đúng.

+0

có ai tìm thấy bất kỳ giải pháp thanh lịch cho vấn đề này? – Cobry

8

Giải pháp của tôi về cơ bản giống như của nebffa. Tôi đã tạo một ví dụ tối thiểu để tính chiều rộng và chiều dài đầu mũi tên cho trục y để khớp với trục được chỉ định cho trục x. Tôi hy vọng rằng điều này có thể hữu ích cho người khác.

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) 

Tạo:

enter image description here

Các vấn đề liên quan