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: 0 | MCC | MCNC | eNB_ID | Longitude | Latitude | |
---|---|---|---|---|---|---|
0 | 7489 | 244 | 12 | 2 | 24.607037 | 60.731043 |
1 | 7490 | 244 | 12 | 3 | 24.400345 | 60.997403 |
2 | 7491 | 244 | 12 | 4 | 24.613302 | 60.706910 |
3 | 7492 | 244 | 12 | 5 | 24.499218 | 60.912731 |
4 | 7493 | 244 | 12 | 6 | 24.510986 | 60.884484 |
finland_municipality = gpd.GeoDataFrame.from_file('kunta1000k_2023Polygon.shp')
finland_municipality.head()
kunta | vuosi | nimi | namn | name | geometry | |
---|---|---|---|---|---|---|
0 | 005 | 2023 | Alajärvi | Alajärvi | Alajärvi | POLYGON ((366787.924 7001300.583, 364487.590 6... |
1 | 009 | 2023 | Alavieska | Alavieska | Alavieska | POLYGON ((382543.364 7120022.976, 382899.505 7... |
2 | 010 | 2023 | Alavus | Alavo | Alavus | POLYGON ((343298.204 6961570.195, 343831.847 6... |
3 | 016 | 2023 | Asikkala | Asikkala | Asikkala | POLYGON ((436139.680 6798279.085, 435714.468 6... |
4 | 018 | 2023 | Askola | Askola | Askola | POLYGON ((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: 0 | MCC | MCNC | eNB_ID | Longitude | Latitude | Proj_Lon | Proj_Lat | |
---|---|---|---|---|---|---|---|---|
0 | 7489 | 244 | 12 | 2 | 24.607037 | 60.731043 | 369501.553119 | 6.735208e+06 |
1 | 7490 | 244 | 12 | 3 | 24.400345 | 60.997403 | 359409.547832 | 6.765288e+06 |
2 | 7491 | 244 | 12 | 4 | 24.613302 | 60.706910 | 369745.411927 | 6.732509e+06 |
3 | 7492 | 244 | 12 | 5 | 24.499218 | 60.912731 | 364394.910111 | 6.755654e+06 |
4 | 7493 | 244 | 12 | 6 | 24.510986 | 60.884484 | 364913.374089 | 6.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: 0 | MCC | MCNC | eNB_ID | Longitude | Latitude | Proj_Lon | Proj_Lat | geometry | |
---|---|---|---|---|---|---|---|---|---|
0 | 7489 | 244 | 12 | 2 | 24.607037 | 60.731043 | 369501.553119 | 6.735208e+06 | POINT (369501.553 6735208.061) |
1 | 7490 | 244 | 12 | 3 | 24.400345 | 60.997403 | 359409.547832 | 6.765288e+06 | POINT (359409.548 6765288.274) |
2 | 7491 | 244 | 12 | 4 | 24.613302 | 60.706910 | 369745.411927 | 6.732509e+06 | POINT (369745.412 6732508.849) |
3 | 7492 | 244 | 12 | 5 | 24.499218 | 60.912731 | 364394.910111 | 6.755654e+06 | POINT (364394.910 6755653.753) |
4 | 7493 | 244 | 12 | 6 | 24.510986 | 60.884484 | 364913.374089 | 6.752485e+06 | POINT (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: 0 | MCC | MCNC | eNB_ID | Longitude | Latitude | Proj_Lon | Proj_Lat | geometry | index_right | kunta | vuosi | nimi | namn | name | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7489 | 244 | 12 | 2 | 24.607037 | 60.731043 | 369501.553119 | 6.735208e+06 | POINT (369501.553 6735208.061) | 143.0 | 433 | 2023.0 | Loppi | Loppi | Loppi |
1 | 7490 | 244 | 12 | 3 | 24.400345 | 60.997403 | 359409.547832 | 6.765288e+06 | POINT (359409.548 6765288.274) | 41.0 | 109 | 2023.0 | Hämeenlinna | Tavastehus | Hämeenlinna |
2 | 7491 | 244 | 12 | 4 | 24.613302 | 60.706910 | 369745.411927 | 6.732509e+06 | POINT (369745.412 6732508.849) | 143.0 | 433 | 2023.0 | Loppi | Loppi | Loppi |
3 | 7492 | 244 | 12 | 5 | 24.499218 | 60.912731 | 364394.910111 | 6.755654e+06 | POINT (364394.910 6755653.753) | 54.0 | 165 | 2023.0 | Janakkala | Janakkala | Janakkala |
4 | 7493 | 244 | 12 | 6 | 24.510986 | 60.884484 | 364913.374089 | 6.752485e+06 | POINT (364913.374 6752484.785) | 54.0 | 165 | 2023.0 | Janakkala | Janakkala | Janakkala |
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()
vuosi | nimi | namn | name | geometry | count | |
---|---|---|---|---|---|---|
kunta | ||||||
005 | 2023 | Alajärvi | Alajärvi | Alajärvi | POLYGON ((366787.924 7001300.583, 364487.590 6... | 10 |
010 | 2023 | Alavus | Alavo | Alavus | POLYGON ((343298.204 6961570.195, 343831.847 6... | 18 |
016 | 2023 | Asikkala | Asikkala | Asikkala | POLYGON ((436139.680 6798279.085, 435714.468 6... | 15 |
018 | 2023 | Askola | Askola | Askola | POLYGON ((426631.036 6720528.076, 428821.749 6... | 9 |
019 | 2023 | Aura | Aura | Aura | POLYGON ((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()
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')