logo elektroda
logo elektroda
X
logo elektroda

Custom hosting and API of official maps on Raspberry Pi - State Register of Borders - Python

p.kaczmarek2  3 444 Cool? (+5)
📢 Listen (AI):
Map of Poland with borders of 16 voivodeships and a control panel on the left
Some time ago I presented how reverse geocoding (converting geographic coordinates into address data) can be run locally based on the Nominatim service from OpenStreetMap. Here I will show a similar system, this time realised manually in Python based on ready-made libraries and ready-made official maps of administrative units provided by the State Boundary Office (PRG). These include the boundaries of the state, provinces, counties, municipalities and units and registration precincts. The whole thing will be light enough to run the server on a Raspberry Pi 4.

Previous topic in the series:
How to run OpenStreetMap locally? Reverse geocoding without limits on your computer

State Register of Boundaries
The State Register of Borders (PRG) is the official database describing the boundaries and administrative division of the country, used by other spatial information systems. It contains data on municipalities, counties, provinces, administrative units and addresses along with their location and basic descriptions (e.g. name, TERYT code).
Data on boundaries and areas of administrative units are updated once a year according to the status as at 1 January on the basis of legal acts or changes in the land register. Information on addresses is supplemented on an ongoing basis according to changes made by the municipal offices.
The source data for the experiment can be downloaded on the Geoportal . There we have a choice of data for each year separately - also the historical ones, 2004 - 2024.

Format of data provided
PRG data are provided in ESRI Shapefile format, i.e. for a single layer you get a set of several files (including .shp, .dbf, .shx, .prj) that together describe the geometry and attributes of objects.
These files contain vector data, mainly polygons of administrative boundaries.
Shapefile packages for voivodeships and counties in Windows file explorer
The files are not that large at all and have the potential to run even on a single-board computer. The situation is further simplified when we dispense with the smallest administrative unit - the precincts, something that is unlikely to be of practical use to us. The precincts take up 300 MB and the next layer (units) only 100 MB. Units are, to simplify, already villages or thereabouts, although towns often consist of several units. I will show this later in the screenshots.
Screenshot of PRG folder with 2024 Shapefile administrative boundary data


Technologies used
For the project I used Python 3 with the Flask libraries (HTTP backend) and GeoPandas and Shapely to handle the GIS data in ESRI Shapefile format.
The visual part (frontend) was realised in the browser using Leaflet.js with an OpenStreetMap backend.

Shapefile service and custom server on Raspberry Pi
The simplest and also most cross-platform method of handling ESRI Shapefiles is the GeoPandas library available in Python. It is an overlay for Pandas, extended to support geometry (Shapely) and GIS formats.
GeoPandas runs easily on Linux (also ARM - Raspberry Pi), Windows and macOS. In practice, all you need is Python 3.x and a few system dependencies (gdal, proj), which on the Raspberry Pi are available in repositories.
The command that installs the dependencies on the Raspberry Pi 4:

apt update
apt install -y \
  python3-pip \
  python3-dev \
  python3-geopandas \
  gdal-bin \
  libgdal-dev \
  libgeos-dev \
  libproj-dev

Example screenshot of the installation:
Installing GIS and Python packages on Raspberry Pi 4 in a terminal window
The Flask framework was used to set up the server itself - it allows you to create a simple HTTP server and handle incoming requests and queries.


Handling PRG data in Python
Each PRG layer (countries, provinces, counties, municipalities, etc.) is loaded into a separate GeoDataFrame object.
In the example, each geometry is assigned a simple numerical uid, which is later used in the web interface.
Code: Python
Log in, to see the code

All layers are stored in the LAYERS dictionary, allowing dynamic switching between administrative levels.

Page presentation
The page is a simple interface for viewing PRG boundaries in a browser. On the left we have a panel: layer selection, search engine, checkboxes and "Show all / Hide all" buttons. On the right, the Leaflet map with OSM underlay.
Just please don't confuse PRG with OSM here - OSM is just a pad/background, the borders go from PRG, from files on disk. The backend does not use OSM at all!
Clicking on an entity in the list or on the map turns its border on/off, which is drawn in a random colour. The number of visible objects updates dynamically and the map adapts the view to the polygons displayed, so up to several thousand shapes can be displayed at once.

Screenshots - Poland:
Map interface showing Poland's border with control panel on the left
Provinces (16 polygons):
Web interface showing a map of Poland with boundaries of 16 voivodeships displayed Counties (380 polygons)
Counties (380 polygons):
Map interface with Poland's county borders, 380 colored polygons over OSM background
Municipalities (2476 polygons):
Poland map interface with 2476 municipality boundaries in random colors
Units (3212 polygons):
Map of Polish cadastral units with colorful administrative boundary outlines Units
Circles (53925 polygons):
Map of Poland with colorful boundary polygons and a control panel on the left
There are already too many of these to show everything....
Browser error message indicating Out of Memory

Presentation of the API
We already have Flask to handle HTTP, and we have already loaded data from Shapefile into separate layers. Now it's easy to add support for simple queries for information about what's at a given latitude and longitude. For the sake of clarity, I have opted for a GET query format, because then the arguments can be seen in the URL itself. Optionally, you can provide the name of the layer to be queried. Example endpoint:
Code: Python
Log in, to see the code

JSON response from local reverse geocoding for Warsaw coordinates
Browser screenshot showing reverse geocoding API response for Mazowieckie voivodeship. Browser interface showing reverse geocoding response for Warsaw coordinates Reverse geocoding query result from local Flask server using cadastral units layer

Demonstration code
For review and commissioning:
Code: Python
Log in, to see the code

Screenshot of the tests (but without the hoops) on the Raspberry:
System monitor htop on Raspberry Pi with PRG Python script running


Summary
With this simple Flask server and Shapefile support from GeoPandas, I was able to run my own reverse geocoding for zones from PRG, all with no limits and up-to-date data. The whole thing lends itself well to a variety of experiments and services, as long as all you need is a map of our country and you don't need accurate address data (streets, etc.), as PRG doesn't have it.
In addition, I enriched the system with a simple control/test panel running in the browser thanks to the Leaflet library - I use layers from OpenStreetMap as a background there, which is already downloaded directly from the Internet, but I don't consider it a problem. The main thing is that the actual reverse geocoding works just fine on the Raspberry.
Now you can use this for your own projects, without worrying about limits - the free Nominatim API for reverse geocoding has a limit of 1 query per second and doesn't allow for bulk querying, and here we can explore the map to our heart's content, as much as our CPU will allow.
Have you used a map API such as OSM or similar, and if so, for what?

About Author
p.kaczmarek2
p.kaczmarek2 wrote 13640 posts with rating 11469 , helped 622 times. Been with us since 2014 year.

Comments

krzbor 30 Dec 2025 23:07

Minor correction - it is supposed to be administrative precincts. For those who are "not in geodesy" - a registration unit is mostly equal to a municipality, but for urban-rural municipalities we have... [Read more]

gulson 01 Jan 2026 12:10

Is it somehow possible to get development plans out of this? Soon a huge number of plots of land will be unbuildable, the Wuzetts are coming to an end. [Read more]

krzbor 01 Jan 2026 20:19

It is not possible - PRG is only the boundaries of provinces, counties, municipalities and registration units and registration precincts. The data is aggregated by GUGiK (Central Office of Geodesy and... [Read more]

%}