在matplotlib中具有各种角度和偏心率的椭圆

时间:2012-07-05 02:44:28

标签: python matplotlib

我想制作一个带有省略号作为标记的情节。下面是一个示例代码,它创建了一个大椭圆,现在实际上是一个圆形。

#! /usr/bin/env python3.2
import numpy as np
import pylab
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
from matplotlib.patches import Ellipse

PlotFileName="test.pdf"
pdf = PdfPages(PlotFileName)
fig=plt.figure(1)
ax1=fig.add_subplot(111)
x_lim=3
plt.xlim([0,x_lim])
plt.ylim([0,x_lim])

F=pylab.gcf()
DefSize = F.get_size_inches()

#These lines have a true angle of 45 degrees, only as a reference:
offset_along_x=x_lim-(x_lim/ax_ratio)
ax1.plot([offset_along_x/2, x_lim-(offset_along_x/2)], [0, x_lim], "b")
ax1.plot([offset_along_x/2, x_lim-(offset_along_x/2)], [x_lim, 0], "b")

e=0.0
theta=0
maj_ax=2
min_ax=maj_ax*np.sqrt(1-e**2)
xconst=(DefSize[1]/DefSize[0])*np.cos(theta*np.pi/180)-np.sin(theta*np.pi/180)
yconst=np.cos(theta*np.pi/180)+(DefSize[1]/DefSize[0])*np.sin(theta*np.pi/180)
print("xconstant= {}".format(xconst))
print("yconstant= {}".format(yconst))
ax1.add_artist(Ellipse((x_lim/2, x_lim/2), xconst*maj_ax, yconst*min_ax, angle=theta, facecolor="green", edgecolor="black",zorder=2, alpha=0.5))

pdf.savefig(fig)
pdf.close()
plt.close()

虽然在这个简化的情况下,ax1.axis("equal")会给出一个纯圆,但在我的最终情节中,这个命令会破坏整个情节(尺度不相等)。所以我想在不使用ax1.axis("equal")的情况下制作通用椭圆工具。如您所见,您可以在此程序中设置主轴的偏心率和倾斜角度。

问题: 问题似乎是我不明白matplotlib如何旋转其图像。如果您将theta此处的值更改为0或90以外的值,则该对象将不再是圆形。使用ax1.axis("equal"),输出是一个圆,现在与theta的值相关。所以我的第一个问题是:在更改theta时,我应该怎么做才能将输出保持为圆形。我假设一旦我解决这个问题,它也适用于椭圆。有人可以帮我这个吗?我真的很感激。

1 个答案:

答案 0 :(得分:3)

在matplotlib中,通过首先缩放到高度和宽度然后围绕它的中心旋转然后平移到所需位置来设置日食位置和形式。因此,旋转和缩放高度并使用之前可以进行mork(就像在脚本中一样),但很难完全正确(您可能必须缩放并反转旋转,但我的转换数学生锈)。

如果要正确缩放椭圆的形式,则需要对Ellipse类进行子类化并重新定义_recompute_transform函数:

from matplotlib import transforms

class TransformedEllipse(Ellipse):

    def __init__(self, xy, width, height, angle=0.0, fix_x = 1.0, **kwargs):
        Ellipse.__init__(self, xy, width, height, angle, **kwargs)

        self.fix_x = fix_x

    def _recompute_transform(self):

        center = (self.convert_xunits(self.center[0]),
                  self.convert_yunits(self.center[1]))
        width = self.convert_xunits(self.width)
        height = self.convert_yunits(self.height)
        self._patch_transform = transforms.Affine2D() \
            .scale(width * 0.5, height * 0.5) \
            .rotate_deg(self.angle) \
            .scale(self.fix_x, 1) \
            .translate(*center)

并像这样使用它:

fix_x = DefSize[1]/DefSize[0]/ax_ratio

ellipse = TransformedEllipse((x_lim/2.0, x_lim/2.0), maj_ax, min_ax, angle=theta, facecolor="green", edgecolor="black",zorder=2, alpha=0.5, fix_x = fix_x)

P.S。我假设ax_ratioy_lim / x_lim