【问题标题】:matplotlib: custom projection for hemisphere/wedgematplotlib:半球/楔形的自定义投影
【发布时间】:2012-03-30 03:32:34
【问题描述】:

我正在查看 matplotlib 库中的 custom projection 示例——我正在尝试修改它以仅绘制南半球。我已将必要的 [-pi/2,pi/2] 限制调整为 [-pi/2,0]。现在我一直在看:

def _gen_axes_patch(self):
    """
    Override this method to define the shape that is used for the
    background of the plot.  It should be a subclass of Patch.

    In this case, it is a Circle (that may be warped by the axes
    transform into an ellipse).  Any data and gridlines will be
    clipped to this shape.
    """
    #return Circle((0.5, 0.5), 0.5)
    return Wedge((0.5,0.5), 0.5, 180, 360)

def _gen_axes_spines(self):
    return {'custom_hammer':mspines.Spine.circular_spine(self,
                                                  (0.5, 0.5), 0.25)}

如您所见,我已将圆形补丁替换为楔形。这是投影图当前的样子:

脊椎仍然跟随圆/椭圆——如何指定我希望脊椎跟随楔形的边界?

我不确定如何最好地修改脊椎,因此非常感谢任何帮助!

谢谢,

亚历克斯

【问题讨论】:

  • 哦,只是要指出——我还是python的新手,所以任何方法的解释都会非常有用!谢谢!

标签: python matplotlib projection axes


【解决方案1】:

为了记录,如果您还是 python 新手,那么您肯定会直接跳入池子的深处。 (感谢你直接进入!)

您正在做的事情需要对 matplotlib 的内部工作有相当详细的了解,这是一个相当复杂的库。

话虽如此,这是一个快速学习的好方法!

对于这样的事情,您需要了解事物结构的内部架构,而不仅仅是“公共”api。

对于大部分内容,您必须深入挖掘并“使用源代码”。对于任何项目,内部工作的文档就是代码本身。

话虽如此,对于一个简单的案例来说,这很简单。

import numpy as np
from matplotlib.projections.geo import HammerAxes
import matplotlib.projections as mprojections
from matplotlib.axes import Axes
from matplotlib.patches import Wedge
import matplotlib.spines as mspines

class LowerHammerAxes(HammerAxes):
    name = 'lower_hammer'
    def cla(self):
        HammerAxes.cla(self)
        Axes.set_xlim(self, -np.pi, np.pi)
        Axes.set_ylim(self, -np.pi / 2.0, 0)

    def _gen_axes_patch(self):
        return Wedge((0.5, 0.5), 0.5, 180, 360)

    def _gen_axes_spines(self):
        path = Wedge((0, 0), 1.0, 180, 360).get_path()
        spine = mspines.Spine(self, 'circle', path)
        spine.set_patch_circle((0.5, 0.5), 0.5)
        return {'wedge':spine}

mprojections.register_projection(LowerHammerAxes)

if __name__ == '__main__':
    import matplotlib.pyplot as plt
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='lower_hammer')
    ax.grid(True)
    plt.show()

让我们深入研究一下_get_axes_spines 方法:

def _gen_axes_spines(self):
    """Return the spines for the axes."""
    # Make the path for the spines
    # We need the path, rather than the patch, thus the "get_path()"
    # The path is expected to be centered at 0,0, with radius of 1
    # It will be transformed by `Spine` when we initialize it
    path = Wedge((0, 0), 1.0, 180, 360).get_path()

    # We can fake a "wedge" spine without subclassing `Spine` by initializing 
    # it as a circular spine with the wedge path. 
    spine = mspines.Spine(self, 'circle', path)

    # This sets some attributes of the patch object. In this particular 
    # case, what it sets happens to be approriate for our "wedge spine"
    spine.set_patch_circle((0.5, 0.5), 0.5)

    # Spines in matplotlib are handled in a dict (normally, you'd have top,
    # left, right, and bottom, instead of just wedge). The name is arbitrary
    return {'wedge':spine}

现在有几个问题:

  1. 事物没有正确地在轴内居中
  2. 可以将坐标区补丁放大一点,以适当地占用坐标区内的空间。
  3. 我们正在为整个地球绘制网格线,然后对其进行剪裁。将它们仅绘制在我们的“下”楔形内会更有效。

但是,当我们查看HammerAxes 的结构时,您会注意到很多这些东西(尤其是轴补丁的居中)被有效地硬编码到变换中。 (正如他们在 cmets 中提到的,它是一个“玩具”示例,并且假设您总是在处理整个地球,这使得转换中的数学变得更加简单。)

如果您想解决这些问题,您需要调整HammerAxes._set_lim_and_transforms 中的几个不同的转换。

但是,它按原样工作得相当好,所以我将把它作为练习留给读者。 :)(请注意,这部分有点难,因为它需要详细了解 matplotlib 的转换。)

【讨论】:

  • 谢谢乔——这是一个非常有用的答案! (我承认到目前为止我或多或少地坚持使用公共 api,直到我需要更多定制的东西)!感谢您对 get_axes_spines 的分解解释。那么,通过使用“路径”,我理论上可以定义一个脊椎以遵循任意形状? (虽然转换会更复杂)。我将更详细地阅读 matplotlib 文档的必要页面,但我同意,玩弄代码可能是有启发性的!再次感谢!
  • 您可以为脊椎定义或多或少的任意路径。对于真正任意的路径,您需要将Spine 子类化,但在这种情况下,它足够接近一个圆(就居中等而言),我们可以将其视为圆形脊柱。没有像子类化Axes 那样子类化Spine 的详细指南,因此您必须深入挖掘并四处寻找。无论如何,祝你好运!
猜你喜欢
  • 2014-11-27
  • 2011-04-12
  • 2021-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多