Matplotlib 中的自定义墨卡托纬度比例

PythonPythonBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

Matplotlib 是一个功能强大的用于 Python 的数据可视化库。它提供了许多用于绘制数据的内置比例,但有时你可能需要针对特定用例创建自定义比例。在本实验中,我们将向你展示如何创建一个使用墨卡托投影(Mercator projection)处理纬度数据的自定义比例。

虚拟机使用提示

虚拟机启动完成后,点击左上角切换到“笔记本”标签页,以访问 Jupyter Notebook 进行练习。

有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作验证无法自动化。

如果你在学习过程中遇到问题,随时向 Labby 提问。课程结束后提供反馈,我们将立即为你解决问题。

导入必要的库

我们将从导入必要的库开始。

import numpy as np
from numpy import ma

from matplotlib import scale as mscale
from matplotlib import transforms as mtransforms
from matplotlib.ticker import FixedLocator, FuncFormatter

定义 MercatorLatitudeScale 类

接下来,我们将定义实现自定义比例的 MercatorLatitudeScale 类。这个类将继承自 mscale.ScaleBase

class MercatorLatitudeScale(mscale.ScaleBase):
    """
    使用在墨卡托(Mercator__)投影中用于缩放纬度的系统,将范围在 -pi/2 到 pi/2(-90 到 90 度)的数据进行缩放。

    缩放函数:
      ln(tan(y) + sec(y))

    逆缩放函数:
      atan(sinh(y))

    由于墨卡托比例在 +/- 90 度时趋于无穷大,
    因此有一个用户定义的阈值,高于和低于该阈值的数据将不会被绘制。
    此阈值默认为 +/- 85 度。

    __ https://en.wikipedia.org/wiki/Mercator_projection
    """

实现 MercatorLatitudeTransform 类

MercatorLatitudeScale 类内部,我们将定义实际转换数据的 MercatorLatitudeTransform 类。这个类将继承自 mtransforms.Transform

    class MercatorLatitudeTransform(mtransforms.Transform):
        ## 有两个值成员必须定义。
        ## ``input_dims`` 和 ``output_dims`` 指定转换的输入维度数和输出维度数。
        ## 转换框架使用这些来进行一些错误检查,并防止不兼容的转换连接在一起。
        ## 当为一个比例定义转换时,根据定义,这些转换是可分离的且只有一个维度,
        ## 这些成员应该始终设置为 1。
        input_dims = output_dims = 1

        def __init__(self, thresh):
            mtransforms.Transform.__init__(self)
            self.thresh = thresh

        def transform_non_affine(self, a):
            """
            此转换接受一个 numpy 数组并返回一个转换后的副本。
            由于墨卡托比例的范围受用户指定的阈值限制,
            输入数组必须进行掩码处理,以仅包含有效值。
            Matplotlib 将处理掩码数组并从绘图中删除超出范围的数据。
            但是,返回的数组 *必须* 与输入数组具有相同的形状,
            因为这些值需要与另一维度中的值保持同步。
            """
            masked = ma.masked_where((a < -self.thresh) | (a > self.thresh), a)
            if masked.mask.any():
                return ma.log(np.abs(ma.tan(masked) + 1 / ma.cos(masked)))
            else:
                return np.log(np.abs(np.tan(a) + 1 / np.cos(a)))

        def inverted(self):
            """
            重写此方法,以便 Matplotlib 知道如何获取此转换的逆转换。
            """
            return MercatorLatitudeScale.InvertedMercatorLatitudeTransform(
                self.thresh)

实现 InvertedMercatorLatitudeTransform 类

我们还将定义 InvertedMercatorLatitudeTransform 类,该类将用于获取此比例的逆变换。

    class InvertedMercatorLatitudeTransform(mtransforms.Transform):
        input_dims = output_dims = 1

        def __init__(self, thresh):
            mtransforms.Transform.__init__(self)
            self.thresh = thresh

        def transform_non_affine(self, a):
            return np.arctan(np.sinh(a))

        def inverted(self):
            return MercatorLatitudeScale.MercatorLatitudeTransform(self.thresh)

注册自定义比例

我们将使用 mscale.register_scale 向 Matplotlib 注册自定义比例。

mscale.register_scale(MercatorLatitudeScale)

使用自定义比例

现在我们可以在绘图中使用自定义比例了。以下是在墨卡托投影中对纬度数据使用自定义比例的示例。

if __name__ == '__main__':
    import matplotlib.pyplot as plt

    t = np.arange(-180.0, 180.0, 0.1)
    s = np.radians(t)/2.

    plt.plot(t, s, '-', lw=2)
    plt.yscale('mercator')

    plt.xlabel('Longitude')
    plt.ylabel('Latitude')
    plt.title('Mercator projection')
    plt.grid(True)

    plt.show()

总结

在本实验中,我们学习了如何使用墨卡托投影为纬度数据在 Matplotlib 中创建自定义比例。我们定义了 MercatorLatitudeScaleMercatorLatitudeTransform 类,并使用 mscale.register_scale 向 Matplotlib 注册了自定义比例。我们还展示了在墨卡托投影中对纬度数据使用自定义比例的示例。