在 Matplotlib 中以对数刻度将文本旋转到一行上

编程入门 行业动态 更新时间:2024-10-27 21:24:06
本文介绍了在 Matplotlib 中以对数刻度将文本旋转到一行上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 问题

我正在使用对数标度的数据,并希望将其旋转以适合一条线.我知道该模型,但不确定我应该将哪个角度插入 transform_angles 以恢复正确的旋转.经过一番反复试验后,我知道对于我需要的轴限制,答案大约是 10 度.

MWE

将matplotlib.pylab导入为plt将numpy导入为npplt.clf()plt.yscale('log')plt.ylim((1e-11, 1e-1)) # 通常会绘制其他数据,这些是我需要的范围.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)#我从OLS拟合中获得了这些数字.plt.plot(x_fit,y_ols,'b-',破折号='',标签='__ nolegend__')plt.gca().text(np.min(x_fit),1.2 * y_ols [0],r'$ O(2 ^ {{{{..3} x}})$'.format(-1.23),旋转=-10).set_bbox(dict(facecolor='w', alpha=0.7, edgecolor='k', linewidth=0)) # 还有几行被省略了.

类似问题(

Problem

I am working with data on a logarithmic scale and would like to rotate it to fit a line. I know the model but am unsure quite what angle I should be plugging into transform_angles to recover the correct rotation. After a bit of trial and error I know the answer is around 10 degrees for the axes limits I require.

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.

Similar questions (keeps text rotated in data coordinate system after resizing?) only use linear axes, as do the 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.

Using gradients

It is easy enough to recover the gradient on a logarithmic scale, using a mix of np.gradient and an angle (in radians) using np.arctan, but I can't seem to recover a number close to the 10 degrees (0.17 radians).

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]

gives -1.6radians (approximately -90 degrees), whereas I require a number closer to 0.17radians. Perhaps I should be using a different base, or I am doing this all wrong (hence the post).

Extras - vertical offset

As can be seen in the code, I have added a vertical offset for the anchor point when using 1.2*y_ols[0]. If a solution needs to take this into consideration then all the better.

解决方案

Note that I provided a general purpose class to achieve this as an answer to the original question. This will update itself on axes limits changes or zoom events etc. And it will work with log scales as well.

In the following I will hence only provide a comparisson between between linear and log scale to help understand that there isn't actually any difference between using a log or a linear scale with the approach from the linked matplotlib "text_rotation_relative_to_line" example.

You first calculate the angle in data coordinates. This can easily be done with numpy.arctan2 and the difference of the first two data (or any other pair of close-by data) as arguments. Then you use ax.transData.transform_angles to transform the angle given in data coordinates to the angle in screen coordinates.

Below is an example (taking the data from the other answer) for the same case on a linear and a log scale.

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

更多推荐

在 Matplotlib 中以对数刻度将文本旋转到一行上

本文发布于:2023-07-09 00:24:39,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1082150.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:对数   刻度   中以   文本   Matplotlib

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!