Coordinates projection with Python


Coordinates reference system tells Python how the coordinates related to places on the Earth, different coordinates projection could have different registry or EPSG geodetic parameter dataset. The most commonly used Global Positioning System which uses latitude/longitude coordinate system based on the Earth’s center of mass, it has EPSG code as EPSG:4326.

EPSG:3067 is the code for the projected coordinate system for Finland, in this note we will see how can we transform the different CRS.

Data Preparation

National Land Servey of Finland (https://www.maanmittauslaitos.fi/en) provides the latest shapefile for the Finnish administration boarders, which includes the municipalities.

OpenCellID (https://opencellid.org/) is a collaborative community project that collects GPS positions of cell towers and their corresponding location area identity.

When download the dataset which contains the cell towers’ GPS information, it is in EPSG:4326 coded. While the shapefile for Finnish municipality, the CRS is EPSG:3067.

import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt
import contextily as ctx
from geopandas import GeoDataFrame
from shapely.geometry import Point
import pyproj
import warnings
warnings.filterwarnings('ignore')
dna_cell_tower = pd.read_csv('dna_lte.csv')
dna_cell_tower.head()

Unnamed: 0MCCMCNCeNB_IDLongitudeLatitude
0748924412224.60703760.731043
1749024412324.40034560.997403
2749124412424.61330260.706910
3749224412524.49921860.912731
4749324412624.51098660.884484
finland_municipality = gpd.GeoDataFrame.from_file('kunta1000k_2023Polygon.shp')
finland_municipality.head()

kuntavuosiniminamnnamegeometry
00052023AlajärviAlajärviAlajärviPOLYGON ((366787.924 7001300.583, 364487.590 6...
10092023AlavieskaAlavieskaAlavieskaPOLYGON ((382543.364 7120022.976, 382899.505 7...
20102023AlavusAlavoAlavusPOLYGON ((343298.204 6961570.195, 343831.847 6...
30162023AsikkalaAsikkalaAsikkalaPOLYGON ((436139.680 6798279.085, 435714.468 6...
40182023AskolaAskolaAskolaPOLYGON ((426631.036 6720528.076, 428821.749 6...

We can use geopandas to review the shapefile’s coordinate reference system.

finland_municipality.crs
<Projected CRS: EPSG:3067>
Name: ETRS89 / TM35FIN(E,N)
Axis Info [cartesian]:
- E[east]: Easting (metre)
- N[north]: Northing (metre)
Area of Use:
- name: Finland - onshore and offshore.
- bounds: (19.08, 58.84, 31.59, 70.09)
Coordinate Operation:
- name: TM35FIN
- method: Transverse Mercator
Datum: European Terrestrial Reference System 1989 ensemble
- Ellipsoid: GRS 1980
- Prime Meridian: Greenwich

Data Wrangling

In the following we will transform the GPS (WGS84 or EPSG:4326) to EPSG3067, and then merge two datasets and count the number of cell towers per municipality.

wgs84 = pyproj.Proj(projparams = 'epsg:4326')
finProj = pyproj.Proj(projparams = 'epsg:3067')

def crs_transformer(x, y):
    return pyproj.transform(wgs84,finProj, y, x)

def transformed_x(x,y):
    return crs_transformer(x,y)[0]

def transformed_y(x,y):
    return crs_transformer(x,y)[1]
dna_cell_tower['Proj_Lon'] = dna_cell_tower.apply(lambda x: transformed_x(x['Longitude'], x['Latitude']), axis=1)
dna_cell_tower['Proj_Lat'] = dna_cell_tower.apply(lambda x: transformed_y(x['Longitude'], x['Latitude']), axis=1)

dna_cell_tower.head()

Unnamed: 0MCCMCNCeNB_IDLongitudeLatitudeProj_LonProj_Lat
0748924412224.60703760.731043369501.5531196.735208e+06
1749024412324.40034560.997403359409.5478326.765288e+06
2749124412424.61330260.706910369745.4119276.732509e+06
3749224412524.49921860.912731364394.9101116.755654e+06
4749324412624.51098660.884484364913.3740896.752485e+06
dna_cell_tower_gdf = gpd.GeoDataFrame(dna_cell_tower, geometry=gpd.points_from_xy(dna_cell_tower['Proj_Lon'], dna_cell_tower['Proj_Lat'], crs='EPSG:3067'))
dna_cell_tower_gdf.head()

Unnamed: 0MCCMCNCeNB_IDLongitudeLatitudeProj_LonProj_Latgeometry
0748924412224.60703760.731043369501.5531196.735208e+06POINT (369501.553 6735208.061)
1749024412324.40034560.997403359409.5478326.765288e+06POINT (359409.548 6765288.274)
2749124412424.61330260.706910369745.4119276.732509e+06POINT (369745.412 6732508.849)
3749224412524.49921860.912731364394.9101116.755654e+06POINT (364394.910 6755653.753)
4749324412624.51098660.884484364913.3740896.752485e+06POINT (364913.374 6752484.785)
dna_cell_tower_gdf.crs
<Projected CRS: EPSG:3067>
Name: ETRS89 / TM35FIN(E,N)
Axis Info [cartesian]:
- E[east]: Easting (metre)
- N[north]: Northing (metre)
Area of Use:
- name: Finland - onshore and offshore.
- bounds: (19.08, 58.84, 31.59, 70.09)
Coordinate Operation:
- name: TM35FIN
- method: Transverse Mercator
Datum: European Terrestrial Reference System 1989 ensemble
- Ellipsoid: GRS 1980
- Prime Meridian: Greenwich
merge_gdf = dna_cell_tower_gdf.sjoin(finland_municipality, how='left')
merge_gdf.head()

Unnamed: 0MCCMCNCeNB_IDLongitudeLatitudeProj_LonProj_Latgeometryindex_rightkuntavuosiniminamnname
0748924412224.60703760.731043369501.5531196.735208e+06POINT (369501.553 6735208.061)143.04332023.0LoppiLoppiLoppi
1749024412324.40034560.997403359409.5478326.765288e+06POINT (359409.548 6765288.274)41.01092023.0HämeenlinnaTavastehusHämeenlinna
2749124412424.61330260.706910369745.4119276.732509e+06POINT (369745.412 6732508.849)143.04332023.0LoppiLoppiLoppi
3749224412524.49921860.912731364394.9101116.755654e+06POINT (364394.910 6755653.753)54.01652023.0JanakkalaJanakkalaJanakkala
4749324412624.51098660.884484364913.3740896.752485e+06POINT (364913.374 6752484.785)54.01652023.0JanakkalaJanakkalaJanakkala
finland_municipality = finland_municipality.set_index('kunta')
cell_tower_count = merge_gdf.groupby(['kunta']).count()['namn'].rename('count')

finland_municipality_cell = pd.merge(finland_municipality, cell_tower_count, left_index=True, right_index=True)
finland_municipality_cell.head()

vuosiniminamnnamegeometrycount
kunta
0052023AlajärviAlajärviAlajärviPOLYGON ((366787.924 7001300.583, 364487.590 6...10
0102023AlavusAlavoAlavusPOLYGON ((343298.204 6961570.195, 343831.847 6...18
0162023AsikkalaAsikkalaAsikkalaPOLYGON ((436139.680 6798279.085, 435714.468 6...15
0182023AskolaAskolaAskolaPOLYGON ((426631.036 6720528.076, 428821.749 6...9
0192023AuraAuraAuraPOLYGON ((263938.323 6730398.827, 263060.935 6...3

Data Visualization

finland_municipality_cell.plot(column='count', scheme="quantiles",figsize=(25, 15),legend=True,cmap='coolwarm', k=10)
plt.title('DNA LTE Cell Towers Number by Municipalities',fontsize=20)
plt.show()

DNA LTE Cell Towers Number by Municipalities

finland_municipality_cell_new = finland_municipality_cell.to_crs(epsg=3857)
ax = finland_municipality_cell_new.plot(column='count',figsize=(25, 15), alpha=0.5, edgecolor='k' ,cmap='coolwarm',legend=True,scheme="quantiles", k=10)
#Add background tiles to plot
ctx.add_basemap(ax)
plt.title('DNA LTE Cell Towers Number by Municipalities',fontsize=20)
Text(0.5, 1.0, 'DNA LTE Cell Towers Number by Municipalities')

DNA LTE Cell Towers Number by Municipalities with Basemap


Author: wenvenn
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source wenvenn !