python - 在 Matplotlib 中将文本旋转到对数刻度上的一条线上

标签 python matplotlib rotation logarithm

问题

我正在处理对数刻度的数据,并想旋转它以适合一条线。我知道这个模型,但不确定我应该将什么角度插入 transform_angles 以恢复正确的旋转。经过一些试验和错误后,我知道对于我需要的轴限制,答案是大约 10 度。

MWE

import matplotlib.pylab as plt
import numpy as np

plt.clf()
plt.yscale('log')
plt.ylim((1e-11, 1e-1))  # Other data is usually plotted and these are the ranges I need. 
plt.xlim((-0.2, 7.2))
x_fit = np.linspace(0.8, 3.2, 1000)
y_ols = (lambda x: np.exp(np.log(2)*(-20.8 + -1.23 * x)))(x_fit)  # I get these numbers from OLS fitting. 
plt.plot(x_fit, y_ols, 'b-', dashes='', label='__nolegend__')
plt.gca().text(np.min(x_fit), 1.2*y_ols[0], r'$O(2^{{ {:.3}x }})$'.format(-1.23), rotation=-10).set_bbox(dict(facecolor='w', alpha=0.7, edgecolor='k', linewidth=0))  # There are several others lines which have been omitted. 

enter image description here

类似的问题 ( keeps text rotated in data coordinate system after resizing? ) 仅使用线性轴, matplotlib demos 也是如此。 .

Remarks on the plot to answer comments


  • In my full plot I use a dual axis (both on log scales) with the twinx() feature. All the data are plotted on ax1 which uses a log-10 scale (as shown). (I could be more explicit and write yscale('log', basey=10)...). Ultimately I want a base-10 axis.
  • The model used in making y_ols comes from a regression fit to some original data and requires base-2. On a log scale it is easy enough to recover the gradient in any required base.

使用渐变

使用 np.gradient 和使用 np.arctan 的角度(以弧度表示)的混合,可以很容易地恢复对数尺度的梯度,但是我似乎无法恢复接近 10 度(0.17 弧度)的数字。

transData.transform_angles(np.array((np.mean(np.gradient(np.log10(y_ols), np.mean(np.diff(x_fit)))),)), np.array([np.min(x_fit), 1.2*y_ols[0]]).reshape((1, 2)), radians=True)[0]

给出 -1.6 弧度(大约 -90 度),而我需要一个接近 0.17 弧度的数字。也许我应该使用不同的基础,或者我做错了(因此该帖子)。

额外 - 垂直偏移

从代码中可以看出,我在使用 1.2*y_ols[0] 时为 anchor 添加了垂直偏移。如果解决方案需要考虑到这一点,那就更好了。

最佳答案

请注意,我提供了一个通用类来实现此目的,作为对 original question 的回答。 .这将在轴限制更改或缩放事件等上自行更新。它也适用于对数刻度。


因此,在下文中,我将仅提供线性和对数刻度之间的比较,以帮助理解使用链接 matplotlib "text_rotation_relative_to_line" example 中的方法使用对数或线性刻度之间实际上没有任何区别。 .

您首先计算数据坐标中的角度。这可以通过 numpy.arctan2 轻松完成。以及前两个数据(或任何其他一对附近数据)的差异作为参数。
然后你使用 ax.transData.transform_angles将数据坐标中给定的角度转换为屏幕坐标中的角度。

下面是同一案例的线性和对数刻度示例(从其他答案中获取数据)。

import matplotlib.pyplot as plt
import numpy as np

fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(6, 4), sharex=True)

ax2.set_yscale('log')
ax2.set(ylim=(1e-11, 1e-1), xlim=(-0.2, 7.2))

x = np.linspace(0.8, 6.2, 100)
y = (lambda x: 10**(( -2 - x)))(x)  

# angle in data coordinates
angle_data = np.rad2deg(np.arctan2(y[1]-y[0], x[1]-x[0]))

# Apply the exact same code to linear and log axes
for ax in (ax1, ax2):

    ax.plot(x, y, 'b-')

    # angle in screen coordinates
    angle_screen = ax.transData.transform_angles(np.array((angle_data,)), 
                                              np.array([x[0], y[0]]).reshape((1, 2)))[0]

    # using `annotate` allows to specify an offset in units of points
    ax.annotate("Text", xy=(x[0],y[0]), xytext=(2,2), textcoords="offset points", 
                rotation_mode='anchor', rotation=angle_screen)

plt.show()

enter image description here

关于python - 在 Matplotlib 中将文本旋转到对数刻度上的一条线上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52928360/

相关文章:

iphone - 旋转 iPhone 并改变 View

swift - SCNNode 枢轴位置

python - 如何获取当前的 IPython/Jupyter Notebook 名称

将原始输入变量除以数字时出现 Python TypeError

python - 使用 Pandas/Python 为列中的重复项生成唯一值

python - 如何在 python 中将 pocketsphinx (5prealpha) 与 gstreamer-1.0 一起使用?

python - 不能从 python3 使用 matplotlib

android - 无法在youtubeplayerview android中旋转 View

python - 使用一堆不同颜色的二维数组绘制 pcolormesh

python - matplotlib imshow 为每种颜色添加标签并将它们放入图例中