Просто для протокола, вы определенно прыгаете прямо в глубокий конец пула, если вы все еще новичок в 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}
Теперь есть несколько проблем с этим:
- Вещи не центрированы по оси должным образом
- Патч осей может быть масштабирован aнемного больше, чтобы правильно занять комнату в осях.
- Мы рисуем линии сетки для полного шара, а затем обрезаем их.Было бы эффективнее рисовать их только внутри нашего «нижнего» клина.
Однако, когда мы посмотрим, как структурирована HammerAxes
, вы заметите, что таких вещей много (особенно центрирование пятна оси) эффективно жестко запрограммированы в преобразования.(Как они упоминают в комментариях, это должен быть «игрушечный» пример, а допущение, что вы всегда имеете дело с полным глобусом, значительно упрощает математику в преобразованиях.)
Если вычтобы исправить это, вам нужно настроить несколько различных преобразований в HammerAxes._set_lim_and_transforms
.
Тем не менее, он работает достаточно хорошо, как есть, поэтому я оставлю это в качестве упражнения для читателя.:) (Имейте в виду, что эта часть немного сложнее, так как требует детального знания преобразований matplotlib.)