21  Interactive Maps - Point Data

Note

Let’s first load in the dataset we will be working with.

import pandas as pd
import geopandas

gp_list = pd.read_csv("https://github.com/hsma-programme/h6_3b_advanced_qgis_mapping_python/raw/main/h6_3b_advanced_qgis_and_mapping_in_python/example_code/gp_surgery_locations_plus_patient_list_size.csv")

gp_list_gdf = geopandas.GeoDataFrame(
    gp_list, # Our pandas dataframe
    geometry = geopandas.points_from_xy(
        gp_list['result_eastings'], # Our 'x' column (horizontal position of points)
        gp_list['result_northings'] # Our 'y' column (vertical position of points)
        ),
    crs = 'EPSG:27700'
    )

# Convert to 4326 (lat/long) for working with Folium
gp_list_gdf = gp_list_gdf.to_crs('EPSG:4326')

# Filter out instances with no 'list' (e.g. things like specialist clinics)
gp_list = gp_list[~gp_list['Total List Size'].isna()]

# reduce to the southwest to not overload Folium
xmin, xmax = -6.449974,-2.717735
ymin, ymax =  49.814737,51.246969
gp_list_gdf_sw = gp_list_gdf.cx[xmin:xmax, ymin:ymax]

To load in point data we 1. Filter out instances in our dataframe with no geometry (they’ll cause problems!)

  1. Make a list from the geometry column to iterate through

  2. Use a for loop at add markers to our empty folium map

Let’s do step 1 and 2 first - the data prep steps.

# Filter out instances with no geometry
gp_list_gdf_sw = gp_list_gdf_sw[~gp_list_gdf_sw['geometry'].is_empty]

# Create a geometry list from the GeoDataFrame
geo_df_list = [[point.xy[1][0], point.xy[0][0]] for point in gp_list_gdf_sw.geometry]

Now let’s make the map.

import folium

# Make the empty map
gp_map_interactive = folium.Map(
    location=[50.7, -4.2],
    zoom_start=8,
    tiles='openstreetmap',
    )

# Add markers to the map
for coordinates in geo_df_list:
     gp_map_interactive = gp_map_interactive.add_child(
        folium.Marker(
            location=coordinates
            )
     )

gp_map_interactive
Make this Notebook Trusted to load map: File -> Trust Notebook

21.1 Custom markers

21.1.1 Web markers

We can pass in a custom marker from the fontawesome library in the for loop.

gp_map_web_icon = folium.Map(
    location=[50.7, -4.2],
    zoom_start=8,
    tiles='openstreetmap',
    )

for coordinates in geo_df_list:
     gp_map_web_icon = gp_map_web_icon.add_child(
        folium.Marker(
            location=coordinates,
            icon=folium.Icon(icon="user-md", prefix='fa', color="black")
            )
     )

gp_map_web_icon
Make this Notebook Trusted to load map: File -> Trust Notebook
Warning

As of Feb 2024, this only supports fontawesome v4 - this link will show you all available icons: https://fontawesome.com/v4/icons/

21.1.2 Markers stored locally

If we want to use an icon stored on our local machine, we have to do it slightly differently.

While it seems inefficient to remake the icon each time inside the loop, it won’t work otherwise!

gp_map_local_icon = folium.Map(
    location=[50.7, -4.2],
    zoom_start=8,
    tiles='openstreetmap',
    )

for coordinates in geo_df_list:
    custom_icon = folium.features.CustomIcon(
        "resources/logos/hsma_logo_transparent_background_small.png",
        icon_size=(48,48)
    )

    gp_map_local_icon = gp_map_local_icon.add_child(
        folium.Marker(
            location=coordinates,
            icon=custom_icon
            )
     )

gp_map_local_icon
Make this Notebook Trusted to load map: File -> Trust Notebook