matplotlib: пользовательская проекция для полушария / клина - PullRequest
3 голосов
/ 13 марта 2012

Я смотрю на пример пользовательской проекции в галерее matplotlib - я пытаюсь изменить его для отображения только южного полушария. Я установил необходимые пределы [-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)}

Как видите, я заменил патч Circle на Wedge. Вот как выглядит проекционный график: projection plot

Позвоночник все еще следует за окружностью / эллипсом - как я могу указать, что я хочу, чтобы позвоночник следовал за границей клина?

Я не уверен, как лучше всего изменить позвоночник, поэтому любая помощь будет очень признательна!

Спасибо

Alex

1 Ответ

5 голосов
/ 14 марта 2012

Просто для протокола, вы определенно прыгаете прямо в глубокий конец пула, если вы все еще новичок в 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()

enter image description here

Давайте немного углубимся в метод _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. Патч осей может быть масштабирован aнемного больше, чтобы правильно занять комнату в осях.
  3. Мы рисуем линии сетки для полного шара, а затем обрезаем их.Было бы эффективнее рисовать их только внутри нашего «нижнего» клина.

Однако, когда мы посмотрим, как структурирована HammerAxes, вы заметите, что таких вещей много (особенно центрирование пятна оси) эффективно жестко запрограммированы в преобразования.(Как они упоминают в комментариях, это должен быть «игрушечный» пример, а допущение, что вы всегда имеете дело с полным глобусом, значительно упрощает математику в преобразованиях.)

Если вычтобы исправить это, вам нужно настроить несколько различных преобразований в HammerAxes._set_lim_and_transforms.

Тем не менее, он работает достаточно хорошо, как есть, поэтому я оставлю это в качестве упражнения для читателя.:) (Имейте в виду, что эта часть немного сложнее, так как требует детального знания преобразований matplotlib.)

...