Map dimensions change when highlighting a country with Geopandas

Viewed 31

I create a world map using Geopandas and matplotlib in python. When I try to highlight a certain country, the map dimensions change. How can I preserve the map dimensions?

import matplotlib
from matplotlib import pyplot
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.collections import PatchCollection
from matplotlib.figure import Figure
import geopandas as gpd
import pandas

self.figure = Figure()
self.canvas = FigureCanvas(self, -1, self.figure)
self.axes = self.figure.add_axes([0, 0, 1, 1])
self.axes.margins(0.0)
self.world_data = gpd.read_file(WORLD)

self.axes.clear()
self.axes.axis('off')
self.figure.set_facecolor(WATER)


self.map_plot = self.world_data.to_crs(epsg=4326).plot(ax=self.axes, color=LAND)

if country_highlight:
            self.world_data[self.world_data.ISO_A2_EH ==country_code].plot(edgecolor=u'gray', color='#fa8a48', ax=self.map_plot)

self.canvas.draw()

I attached a runnable below. Each time the user left clicks on the map, a random country is selected. But at each click, map dimensions change. What's wrong here? "ne_110m_admin_0_countries.shp" map file can be downloaded from: this page. You should put the sample code inside the map file directory.

import wx
import matplotlib
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
import geopandas as gpd
import random
import pathlib
import os


this_directory = print(pathlib.Path(__file__).parent.resolve())

WORLDX  = os.path.join(this_directory, "ne_110m_admin_0_countries.shp") 
WATER = '#defafc'
LAND = '#807e7e'
LEFT_MOUSE = matplotlib.backend_bases.MouseButton.LEFT


class MapFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Map",
                          style=wx.DEFAULT_FRAME_STYLE,
                          size=wx.Size(1200, 900))
        self.main_panel = MapPanel(self)
        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnClose(self, _event):
        self.Destroy()
        wx.Exit()

class  MapPanel(wx.Panel):

    def __init__(self, parent):

        wx.Panel.__init__(self, parent)
        self.SetDoubleBuffered(True)


        self.figure = Figure()
        self.result_frame = parent
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.axes = self.figure.add_axes([0, 0, 1, 1])
        self.axes.margins(0.0)
        self.axes.set_anchor('C')

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)
        self.Fit()
        self.Layout()
        self.countries = ["US", "FR", "GB", "BR", "IN", "AU", "NZ", "IT", "DE"]
        self.gdf = None
        self.canvas.mpl_connect('button_press_event', self.onLeftClick)
        self.world_data = gpd.read_file(WORLDX)
        self.map_plot = None
        self.drawMap()

    def drawMap(self, country_highlight=None):
        """Draw the map on the canvas. """
        self.axes.clear()
        self.axes.axis('off')
        self.figure.set_facecolor(WATER)
        self.map_plot = self.world_data.to_crs(epsg=4326).plot(ax=self.axes, color=LAND)
        print("country highlight: ", country_highlight)
        if country_highlight:
            ylim = self.map_plot.get_ylim()
            xlim = self.map_plot.get_xlim()
            self.world_data[self.world_data.ISO_A2_EH == country_highlight].plot(edgecolor=u'gray', color='#fa8a48', ax=self.map_plot)
            self.map_plot.set_ylim(*ylim)
            self.map_plot.set_xlim(*xlim)

        self.canvas.draw()

    def onLeftClick(self, event):
        if event.button == LEFT_MOUSE:
            self.drawMap(random.choice(self.countries))


class MyApp(wx.App):
    def OnInit(self):
        frame = MapFrame()
        frame.Show()
        return True

if __name__ == "__main__":
    app = MyApp()
    app.MainLoop()
1 Answers

If you want to hold the map extent for an axis constant after a certain point, you can save them and re-enforce them later:

# I'll drop references to `self` for the rest of the answer for clarity
ax = self.axes
world_data = self.world_data

world_data.to_crs(epsg=4326).plot(ax=ax, color=LAND)

ylim = ax.get_ylim()
xlim = ax.get_xlim()

if country_highlight:
    self.world_data[
        world_data.ISO_A2_EH == country_code
    ].plot(edgecolor=u'gray', color='#fa8a48', ax=ax)

ax.set_ylim(*ylim)
ax.set_xlim(*xlim)
Related