首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Matplotlib中将文本旋转到日志比例尺上的一行上

在Matplotlib中将文本旋转到日志比例尺上的一行上
EN

Stack Overflow用户
提问于 2018-10-22 11:32:28
回答 2查看 1.2K关注 0票数 3

问题

我正在处理对数比例的数据,并希望将其旋转以适应一条直线。我知道模型,但不确定我应该插入到transform_angles中以恢复正确的旋转角度。经过一些尝试和错误,我知道答案是在10度左右的轴线限制,我需要。

米维

代码语言:javascript
复制
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. 

类似的问题(调整大小后,在数据坐标系中保持文本旋转?)只使用线性轴,matplotlib演示也是如此。

关于回答注释的情节的注释

  • 在我的完整绘图中,我使用了带有twinx()特性的双轴(都在日志尺度上)。所有数据都是在ax1上绘制的,它使用的是log-10比例尺(如图所示)。(我可以更明确地写yscale('log', basey=10).)最终我想要一个基座-10轴。
  • 用于制作y_ols的模型来自于对一些原始数据的回归拟合,并且需要基-2。在一个日志尺度上,在任何需要的基础上恢复梯度是非常容易的。

使用梯度

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

代码语言:javascript
复制
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]时为锚点添加了一个垂直偏移量。如果一个解决方案需要考虑到这一点,那么就更好了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-11-02 00:40:15

注意,我提供了一个通用类来实现这一点,作为对原始问题的回答。这将更新自己的轴线,限制,变化或缩放事件等。它将与日志规模以及工作。

因此,在下面的文章中,我将只提供线性标度和日志标度之间的比较,以帮助理解用链接“行”示例的方法使用日志或线性标度实际上没有任何区别。

首先以数据坐标计算角度。这可以很容易地以numpy.arctan2和前两个数据(或任何其他接近的数据)的差异作为参数来完成。

然后使用ax.transData.transform_angles将数据坐标中给定的角度转换为屏幕坐标中的角度。

下面是一个示例(从另一个答案中获取数据),用于线性和日志尺度上的相同情况。

代码语言:javascript
复制
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()

票数 6
EN

Stack Overflow用户

发布于 2018-11-01 23:07:55

对于textbox来说,使用哪种轴并不重要。您只需将其角度调整为figure属性即可。为了更好地演示它,我将稍微修改一下您的MWE。我将使用y(x)=10^(2-x)函数,在对数尺度上,它应该提供-45度斜率的线性函数。如果您检查网格值,情况就是如此(每个单元的功能下降了十年)。但是,由于图形的高宽比是变形的,视角是不同的(对于两个单位只有一个平方),所以您需要调整它。因此,对于给定的数字,斜率的正确值是-26.259度。请参阅代码中adjusted_slope的值。

至于textbox的垂直偏移量,您可以选择提供最佳视觉效果的值。

代码语言:javascript
复制
# you can set whatever size you need
plt.figure(figsize=(6, 4))

# these are the original settings
plt.yscale('log')
plt.ylim((1e-11, 1e-1))  
plt.xlim((-0.2, 7.2))

x_fit = np.linspace(0.8, 6.2, 100)
slope = -1.0
# a slight change in the function
y_ols = (lambda x: 10**(( -2 + slope * x)))(x_fit)  

plt.plot(x_fit, y_ols, 'b-', dashes='', label='__nolegend__')

# estimate the "right" slope 
calc_slope = np.mean(np.gradient(np.log10(y_ols), np.mean(np.diff(x_fit))))

# get current figure properties
x_min, x_max = plt.xlim()
y_min, y_max = plt.ylim()
x_sz, y_sz = plt.gcf().get_size_inches()
x_factor = x_sz / (x_max - x_min)
y_factor = y_sz / (np.log10(y_max) - np.log10(y_min))  # adjust to logarithmic values 

# calculate adjustment
adjusted_slope = (calc_slope * y_factor / x_factor)  # in radians

plt.gca().text(np.min(x_fit), 1.2*y_ols[0], r'$O(10^{{ {:.3}x }})$'.format(slope),
            rotation_mode='anchor', rotation=np.arctan(adjusted_slope)*180/np.pi).set_bbox(
                dict(facecolor='w', alpha=0.7, edgecolor='k', linewidth=0)) 

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52928360

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档