Как добавить зеброподобных клещей в геоосадки картопы, используя python? - PullRequest
0 голосов
/ 27 января 2020

Я пытаюсь реализовать стиль зебры для графиков cartopy-matplotlib.

Это обычный стиль построения графиков, используемый для создания географических карт. Несколько информационных систем Geographi c уже реализовали этот стиль. Тем не менее, Python не обладает этим.

Мне удалось сгенерировать функцию, которая добавляет зеброподобных тиков в геоосях данного картопа.

Тем не менее, несмотря на мои попытки обновить алгоритм, я был не в состоянии разрешить автоматическое c обновление координат зебры. Это обновление позволит решить такие проблемы, как операции event.callbacks.connect (например, масштабирование, уменьшение или перетаскивание), когда тики типа зебры теряют свои позиции в осях.

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

Я пытался реализовать концепцию классов для метода callbacks.connect в файле matplotlib, как описано здесь и там .

Здесь приведен скрипт:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature

import matplotlib.patches as mpatches
from matplotlib.offsetbox import AnchoredText

from cartopy.mpl.geoaxes import GeoAxesSubplot

class zebra_ticks():

    def __init__(self, ax=None, 
             projection = ccrs.PlateCarree(), 
             drawlicense=True,
             pad=2):

        if not isinstance(ax, GeoAxesSubplot):

            self.fig = plt.figure(figsize=(9,7))
            self.ax = plt.axes(projection=projection)


            # Put a background image on for nice sea rendering.
        self.ax.stock_img()

        # Create a feature for States/Admin 1 regions at 1:50m from Natural Earth
        states_provinces = cfeature.NaturalEarthFeature(
            category='cultural',
            name='admin_1_states_provinces_lines',
            scale='50m',
            facecolor='none')

        SOURCE = 'Natural Earth'
        LICENSE = 'public domain'

        self.ax.add_feature(cfeature.LAND)
        self.ax.add_feature(cfeature.COASTLINE)
        self.ax.add_feature(states_provinces, edgecolor='gray')

        # Add a text annotation for the license information to the
        # the bottom right corner.

        if drawlicense:

            text = AnchoredText(r'$\mathcircled{{c}}$ {}; license: {}'
                                ''.format(SOURCE, LICENSE),
                                loc='right',
                                bbox_transform=self.ax.transAxes,
                                bbox_to_anchor=(1.01, -0.11), 
                                prop={'size': 8}, 
                                frameon=False)

            self.ax.add_artist(text)

        self.gridliner = self.ax.gridlines(draw_labels=True)
        self.pad = pad
        self.zebras = self.add_zebra()


        plt.show()

        self.ax.callbacks.connect('xlim_changed', lambda x: self.update_zebra)
        self.ax.callbacks.connect('ylim_changed', lambda x: self.update_zebra)



    def add_zebra(self):
        '''
        Description:

            This function add a zebra line border around a cartopy's geoaxes.

            It uses the coordinates tick position to evaluate the zebra blocks.


        returns (dict): {'horizontal:'horizontal_zebras, 'vertical':vertical_zebras}

        '''


        self.fig.canvas.draw()   

        lon0, lon1, lat0, lat1 = self.ax.get_extent(crs=self.ax.projection)

        ysegs = self.gridliner.yline_artists[0].get_segments()
        yticks = [yseg[0,1] for yseg in ysegs]

        xsegs = self.gridliner.xline_artists[0].get_segments()
        xticks = [xseg[0,0] for xseg in xsegs]
        xticks.append(lon1)

        i = 0

        colors_wk = ['white', 'black']


        horizontal_zebras={'north':[],
                           'south':[]}


        vertical_zebras={'east':[],
                           'west':[]}


        for lon, position in zip([lon0, lon1 - self.pad], ['east', 'west']):
            y0 = xticks[0]
            for enum, y in enumerate(yticks[1:]):

                color = colors_wk[i]

                delta_coor = (y - y0)

                vertical_rect = mpatches.Rectangle( (lon, y0), self.pad , delta_coor, 
                                          transform=self.ax.transData,
                                          facecolor=color, zorder=1000)

                vertical_zebras[position].append(vertical_rect)

                i = 1 - i
                y0 = y

                self.ax.add_patch(vertical_rect)


        for lat, position in zip([lat0, lat1 - self.pad], ['south', 'north']):
            x0 = xticks[0]

            for x in xticks[1:]:

                color = colors_wk[i]

                delta_coor = (x - x0)


                horizontal_rect = mpatches.Rectangle( (x0, lat), delta_coor, self.pad ,
                                          transform=self.ax.transData,
                                          facecolor=color, zorder=1000)


                horizontal_zebras[position].append(horizontal_rect)


                x0 = x

                i = 1 - i

                self.ax.add_patch(horizontal_rect)





        if self.ax.projection.proj4_params.get('units', 'None') == 'None':

            if not (lon0 <=-180 or lon1 >= 180 or lat0>=90 or lat0<=-90):

                self.ax.set_extent((lon0-self.pad, 
                                    lon1+self.pad, 
                                    lat0-self.pad, 
                                    lat1+self.pad))

        return {'horizontal':horizontal_zebras, 
                'vertical':vertical_zebras}


    def update_zebra(self, event):
        axes = event.axes
        # trigger the outline and background patches to be re-clipped
        axes.outline_patch.reclip = True
        axes.background_patch.reclip = True

        lon0, lon1, lat0, lat1 = self.ax.get_extent(crs=self.ax.projection)

        ysegs = self.gridliner.yline_artists[0].get_segments()
        yticks = [yseg[0,1] for yseg in ysegs]

        xsegs = self.gridliner.xline_artists[0].get_segments()
        xticks = [xseg[0,0] for xseg in xsegs]
        xticks.append(lon1)

        for Vzebras in self.zebras['vertical']:
            for zebra in Vzebras:

                for lon, position in zip([lon0, lon1 - self.pad], ['east', 'west']):
                    y0 = xticks[0]
                    for enum, y in enumerate(yticks[1:]):

                        delta_coor = (y - y0)

                        zebra.set_bounds( lon, y0, self.pad , delta_coor)

                        y0 = y


        for Hzebras in self.zebras['vertical']:
            for zebra in Hzebras:

                for lat, position in zip([lat0, lat1 - self.pad], ['south', 'north']):
                    x0 = xticks[0]

                    for x in xticks[1:]:

                        delta_coor = (x - x0)


                        zebra.set_bounds( x0, lat, 
                                         delta_coor, 
                                         self.pad )


                        x0 = y



if '__main__' == __name__:

    Z = zebra_ticks()

Я благодарен за любую помощь в отношении функций "event.callback" в matplotlib для решения этой проблемы.

С уважением,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...