{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualization of Airport Data on Map.\n", "\n", "The idea and the airport's data for this demo was found in the \"Towards Data Science\" article [How to Visualize Data on top of a Map in Python using the Geoviews library](https://towardsdatascience.com/how-to-visualize-data-on-top-of-a-map-in-python-using-the-geoviews-library-c4f444ca2929) by [Christos Zeglis](https://medium.com/@christoszeglis).\n", "\n", "The paper demonstrates how to make a plot to visualize the passengers volume for the busiest airports in Greece, and the neighbor country, Turkey, for comparison reasons.\n", "\n", "The author uses Geoviews and Bokeh libraries to achieve such visualisation. We are going to use the [Lets-Plot](https://github.com/JetBrains/lets-plot/blob/master/README.md) library solely to do the same job and, on top of it, fill both countries boundaries with semi-transparent colors.\n", "\n", "The tasks completed in this tutorial:\n", "\n", "- Configuring map-tiles for the interactive base-map layer.\n", "- Obtaining boundaries of Greece and Turkey using Lets-Plot geo-coding module.\n", "- Creating a proportional symbols map by combining base-map, polygons and point layers.\n", "- Castomizing the tooltip contents." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T12:18:12.355054Z", "iopub.status.busy": "2024-04-26T12:18:12.355054Z", "iopub.status.idle": "2024-04-26T12:18:13.363227Z", "shell.execute_reply": "2024-04-26T12:18:13.363227Z" } }, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "\n", "from lets_plot import *" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T12:18:13.363227Z", "iopub.status.busy": "2024-04-26T12:18:13.363227Z", "iopub.status.idle": "2024-04-26T12:18:13.378989Z", "shell.execute_reply": "2024-04-26T12:18:13.378989Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "LetsPlot.setup_html()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Configuring the basemap.\n", "\n", "For the purposes of this tutorial, we are going to use \"CityLights 2012\" map-tiles [© NASA Global Imagery Browse Services (GIBS)](https://earthdata.nasa.gov/eosdis/science-system-description/eosdis-components/gibs)." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T12:18:13.394608Z", "iopub.status.busy": "2024-04-26T12:18:13.394608Z", "iopub.status.idle": "2024-04-26T12:18:13.425950Z", "shell.execute_reply": "2024-04-26T12:18:13.425950Z" } }, "outputs": [], "source": [ "LetsPlot.set(maptiles_zxy(\n", " url='https://gibs.earthdata.nasa.gov/wmts/epsg3857/best/VIIRS_CityLights_2012/default//GoogleMapsCompatible_Level8/{z}/{y}/{x}.jpg',\n", " attribution='© NASA Global Imagery Browse Services (GIBS)',\n", " max_zoom=8\n", "))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Loading the \"airports\" dataset.\n", "\n", "The \"airports\" dataset is already cleaned and only contains data on Greece and Turkey airports." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T12:18:13.425950Z", "iopub.status.busy": "2024-04-26T12:18:13.425950Z", "iopub.status.idle": "2024-04-26T12:18:13.724373Z", "shell.execute_reply": "2024-04-26T12:18:13.724373Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
IATAcitylatitudelongitudepassengerscountry
0ATHAthens37.935423.943724.13GR
1HERHeraklion35.340025.17538.00GR
2SKGThessaloniki40.523022.97676.67GR
\n", "
" ], "text/plain": [ " IATA city latitude longitude passengers country\n", "0 ATH Athens 37.9354 23.9437 24.13 GR\n", "1 HER Heraklion 35.3400 25.1753 8.00 GR\n", "2 SKG Thessaloniki 40.5230 22.9767 6.67 GR" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "airports = pd.read_csv(\"https://raw.githubusercontent.com/JetBrains/lets-plot-docs/master/data/airports.csv\")\n", "airports.head(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Obtaining boundaries (or polygons) of Greece and Turkey.\n", "\n", "On this step we are using built-in geo-coding capabilities of the Lets-Plot library." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T12:18:13.726384Z", "iopub.status.busy": "2024-04-26T12:18:13.726384Z", "iopub.status.idle": "2024-04-26T12:18:14.150157Z", "shell.execute_reply": "2024-04-26T12:18:14.149265Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The geodata is provided by © OpenStreetMap contributors and is made available here under the Open Database License (ODbL).\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idcountryfound namecentroidpositionlimit
0192307GRGreece[21.5772458904778, 39.6987419575453][20.0085201859474, 37.6486940681934, 26.635576...[19.3734280765057, 34.8015573620796, 29.645195...
1174737TRTurkey[35.4993526199025, 38.95283639431][26.0636124014854, 35.807680785656, 44.8176634...[25.6654492020607, 35.807680785656, 44.8176634...
\n", "
" ], "text/plain": [ " id country found name centroid \\\n", "0 192307 GR Greece [21.5772458904778, 39.6987419575453] \n", "1 174737 TR Turkey [35.4993526199025, 38.95283639431] \n", "\n", " position \\\n", "0 [20.0085201859474, 37.6486940681934, 26.635576... \n", "1 [26.0636124014854, 35.807680785656, 44.8176634... \n", "\n", " limit \n", "0 [19.3734280765057, 34.8015573620796, 29.645195... \n", "1 [25.6654492020607, 35.807680785656, 44.8176634... " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from lets_plot.geo_data import *\n", "\n", "countries_gcoder = geocode_countries(['GR', 'TR'])\n", "countries_gcoder.get_geocodes()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Showing the data on map.\n", "\n", "- Add an interactive base-map layer with custom initial location and zoom level.\n", "- Add polygons layer to fill the country boundaries with semi-transparent colors.\n", "- Add points layer marking the airports location with the point size proportional to the airport's passengers volume.\n", "- Customize tooltip on the points layer to show all the airport data.\n", "- Use the 'scale_fill_manual()' function in order to fill polygons and points with blue and red colors.\n", "- Setup the desired marker's size using the 'scale_size()' function." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2024-04-26T12:18:14.155785Z", "iopub.status.busy": "2024-04-26T12:18:14.150157Z", "iopub.status.idle": "2024-04-26T12:18:14.480044Z", "shell.execute_reply": "2024-04-26T12:18:14.480044Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(ggplot() \n", " + geom_livemap(location=[26.65, 38.61],\n", " zoom=6)\n", " + geom_polygon(aes(fill='country'), \n", " data=countries_gcoder.inc_res().get_boundaries(),\n", " size=0,\n", " alpha=.2)\n", " + geom_point(aes('longitude', 'latitude', fill='country', size='passengers'),\n", " data=airports,\n", " shape=21,\n", " alpha=.7,\n", " color='white',\n", " tooltips=layer_tooltips()\n", " .format('passengers', '{.1f} m' )\n", " .format('^x', '.2f').format('^y', '.2f')\n", " .line('@|@IATA')\n", " .line('Passengers|@passengers') \n", " .line('City|@city') \n", " .line('Country|@country') \n", " .line('Longitude|^x')\n", " .line('Latitude|^y'))\n", " + scale_fill_manual(values=['#30a2da', '#fc4f30'])\n", " + scale_size(range=[10, 40], trans='sqrt')\n", " + theme(legend_position='none')\n", " + ggsize(900, 520)\n", ")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.13" } }, "nbformat": 4, "nbformat_minor": 4 }