Matplotlib:在对数-对数图中绘制一条竖直箭头

10

我无法在以下对数对数图中绘制一个简单的垂直箭头:

#!/usr/bin/python2

import matplotlib.pyplot as plt
import matplotlib as mpl

plt.yscale('log')
plt.xscale('log')
plt.ylim((1e-20,1e-10))
plt.xlim((1e-12,1))

plt.arrow(0.00006666, 1e-20, 0, 1e-8 - 1e-20, length_includes_head=True)

plt.savefig('test.pdf')

它只是不显示。从文档中可以看出,所有参数,如width、height等都与轴的比例相关。这非常不直观。我尝试使用axisartist包的twin()函数,在我的轴上定义一个顶部轴,并设置限制为(0,1),(0,1),以更好地控制箭头的参数,但我无法弄清如何在主轴上完全独立地定义另一个轴。

有什么想法吗?


1
似乎有一个关于matplotlib的问题。尝试使用plt.arrow(6e-4, 1e-4, 0.1, 0.2, length_includes_head=True),并将视图移动到较高的y值。您会看到箭头线从约10-4开始。但是,如果您使用较低的值(即x和y的1e-5),则线条会消失,您只能看到小箭头头部大部分在之前的相同位置上。(显然,您应该使用plt.show()来执行此操作) - joaquin
如果我知道的话,我会写一个答案 ;-). 但现在至少你知道箭头在那里了... - joaquin
@janoliver:我终于想通了 - 它比我想象的要容易得多(回想起来,这些事情通常都是如此!)- 请看下面我的答案。 - jmetz
3个回答

7
我在寻找这个问题的答案时,找到了一个有用的答案!你可以将任何“mathtext”字符(matplotlib版本的LaTeX)指定为标记。试试: plt.plot(x,y,'ko',marker = r'$\downarrow$',markersize = 20)
这将在位置(x,y)处绘制一个向下指向的黑色箭头,在任何图中都看起来很好(甚至是对数-对数)。请参见:matplotlib.org/users/mathtext.html#mathtext-tutorial 以获取更多可用的符号。

6

分图方法

创建分图后,请执行以下操作:

  • 对齐位置。
  • 使用set_axis_off()关闭轴(刻度、标签等)。
  • 绘制箭头!

这样只需几行代码就可以得到所需的结果!

例如:

#!/usr/bin/python2

import matplotlib.pyplot as plt

hax = plt.subplot(1,2,1)
plt.yscale('log')
plt.xscale('log')
plt.ylim((1e-20,1e-10))
plt.xlim((1e-12,1))

hax2 = plt.subplot(1,2,2)
plt.arrow(0.1, 1, 0, 1, length_includes_head=True)

hax.set_position([0.1, 0.1, 0.8, 0.8])
hax2.set_position([0.1, 0.1, 0.8, 0.8])

hax2.set_axis_off()

plt.savefig('test.pdf')

重新缩放数据

另一种可能更简单的方法是重新缩放数据,尽管轴标签可能会有些棘手。

例如:

import numpy 

# Other import commands and data input

plt.plot(numpy.log10(x), numpy.log10(y))) 

虽然不是最好的解决方案,但如果你能处理刻度标签,那么这是一个不错的结果!


嗨,我需要为此单独设置x轴和y轴,因为它们都在主轴上以对数比例尺进行缩放。axisartists的“twin”函数始终在主轴和寄生轴之间使用转换函数。我不希望它们以任何方式相连。由于这些东西的文档非常差,我找不到(可能是非脏的)方法来实现这一点。如果不容易做到,我可能只会用inkscape之类的工具插入箭头。 - janoliver
覆盖层。我无法弄清楚如何在彼此之上有两个完全独立的图,每个都有自己的x和y轴等。 - janoliver
那为什么不直接绘制 log(x)log(y) 的线性图呢?这样画箭头就变得非常简单了。 - jmetz
1
是的,但那样我就得自己调整所有刻度线等等。所以,使用inkscape确实更容易。我之所以问这个问题,是因为我无法相信matplotlib在绘制简单箭头时会让人如此困扰。不过还是谢谢你的帮助! - janoliver
@janoliver - 抱歉让你等了这么久,但我终于弄明白了! - jmetz

4

我知道这个帖子已经很久没有更新了,但是我认为发布我的解决方案可能有助于其他人更有效地绘制对数比例图上的箭头。

作为其他人已经发布内容的替代方案,您可以使用一个转换对象,将箭头坐标输入到“轴坐标”的(线性)尺度上,而不是原始坐标轴的尺度。 我所说的轴坐标是指在[0,1](水平范围)和[0,1](垂直范围)之间标准化的坐标系,其中点(0,0)是左下角,点(1,1) 是右上角等等。 然后,您可以通过以下方式简单地包含一个箭头:

plt.arrow(0.1, 0.1, 0.9, 0.9, transform=plot1.transAxes, length_includes_head=True)

这将在图的水平和垂直范围的4/5上方斜跨箭头,从左下到右上(其中plot1是子图名称)。
如果您想在一般情况下执行此操作,可以在对数空间中为箭头指定精确坐标(x0,y0)(x1,y1),只需编写两个函数fx(x)fy(y)即可将原始坐标转换为这些“轴”坐标。下面是如何修改OP发布的原始代码以实现此目的的示例(抱歉,我没有所需的声望来包含代码生成的图像)。
#!/usr/bin/python3

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

# functions fx and fy take log-scale coordinates to 'axes' coordinates
ax = 1E-12 # [ax,bx] is range of horizontal axis 
bx = 1E0
def fx(x):
    return (np.log(x) - np.log(ax))/(np.log(bx) - np.log(ax))

ay = 1E-20 # [ay,by] is range of vertical axis
by = 1E-10
def fy(y):
    return (np.log(y) - np.log(ay))/(np.log(by) - np.log(ay))

plot1 = plt.subplot(111)
plt.xscale('log')
plt.yscale('log')
plt.xlim(ax, bx)
plt.ylim(ay, by)

# transformed coordinates for arrow from (1E-10,1E-18) to (1E-4,1E-16)
x0 = fx(1E-10)
y0 = fy(1E-18)
x1 = fx(1E-4) - fx(1E-10)
y1 = fy(1E-16) - fy(1E-18)

plt.arrow(
          x0, y0, x1, y1, # input transformed arrow coordinates 
          transform = plot1.transAxes, # tell matplotlib to use axes coordinates   
          facecolor = 'black',
          length_includes_head=True
         )

plt.grid(True)
plt.savefig('test.pdf')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接