Skip to content

foliumap module

Adds custom Map class that extends the folium Map class.

Map

Bases: Map

A custom Map class that extends folium.Map.

Source code in landcalc/foliumap.py
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
class Map(folium.Map):
    """A custom Map class that extends folium.Map."""

    def __init__(self, center=(0, 0), zoom=2, **kwargs):
        """Initializes the Map object.

        Args:
            center (tuple, optional): The initial center of the map as (latitude, longitude). Defaults to (0, 0).
            zoom (int, optional): The initial zoom level of the map. Defaults to 2.
            **kwargs: Additional keyword arguments for the folium.Map class.
        """
        super().__init__(location=center, zoom_start=zoom, **kwargs)

    def add_geojson(
        self,
        data,
        zoom_to_layer=True,
        hover_style=None,
        **kwargs,
    ):
        """Adds a GeoJSON layer to the map.

        Args:
            data (str or dict): The GeoJSON data. Can be a file path (str) or a dictionary.
            zoom_to_layer (bool, optional): Whether to zoom to the layer's bounds. Defaults to True.
            hover_style (dict, optional): Style to apply when hovering over features. Defaults to {"color": "yellow", "fillOpacity": 0.2}.
            **kwargs: Additional keyword arguments for the folium.GeoJson layer.

        Raises:
            ValueError: If the data type is invalid.
        """
        import geopandas as gpd

        if hover_style is None:
            hover_style = {"color": "yellow", "fillOpacity": 0.2}

        if isinstance(data, str):
            gdf = gpd.read_file(data)
            geojson = gdf.__geo_interface__
        elif isinstance(data, dict):
            geojson = data

        geojson = folium.GeoJson(data=geojson, **kwargs)
        geojson.add_to(self)

    def add_shp(self, data, **kwargs):
        """Adds a shapefile to the map.

        Args:
            data (str): The file path to the shapefile.
            **kwargs: Additional keyword arguments for the GeoJSON layer.
        """
        import geopandas as gpd

        gdf = gpd.read_file(data)
        gdf = gdf.to_crs(epsg=4326)
        geojson = gdf.__geo_interface__
        self.add_geojson(geojson, **kwargs)

    def add_gdf(self, gdf, **kwargs):
        """Adds a GeoDataFrame to the map.

        Args:
            gdf (geopandas.GeoDataFrame): The GeoDataFrame to add.
            **kwargs: Additional keyword arguments for the GeoJSON layer.
        """
        gdf = gdf.to_crs(epsg=4326)
        geojson = gdf.__geo_interface__
        self.add_geojson(geojson, **kwargs)

    def add_vector(self, data, **kwargs):
        """Adds vector data to the map.

        Args:
            data (str, geopandas.GeoDataFrame, or dict): The vector data. Can be a file path, GeoDataFrame, or GeoJSON dictionary.
            **kwargs: Additional keyword arguments for the GeoJSON layer.

        Raises:
            ValueError: If the data type is invalid.
        """
        import geopandas as gpd

        if isinstance(data, str):
            gdf = gpd.read_file(data)
            self.add_gdf(gdf, **kwargs)
        elif isinstance(data, gpd.GeoDataFrame):
            self.add_gdf(data, **kwargs)
        elif isinstance(data, dict):
            self.add_geojson(data, **kwargs)
        else:
            raise ValueError("Invalid data type")

    def add_layer_control(self):
        """Adds a layer control widget to the map."""
        folium.LayerControl().add_to(self)

    def add_split_map(self, left="openstreetmap", right="cartodbpositron", **kwargs):
        """Adds a split map to the map.

        Args:
            left (str, optional): The tile layer for the left side of the split map. Defaults to "openstreetmap".
            right (str, optional): The tile layer for the right side of the split map. Defaults to "cartodbpositron".
        """
        from localtileserver import get_folium_tile_layer

        if left.startswith("http") or os.path.exists(left):
            layer_left = get_folium_tile_layer(left, **kwargs)
        else:
            layer_left = folium.TileLayer(left, overlay=True, **kwargs)
        if right.startswith("http") or os.path.exists(right):
            layer_right = get_folium_tile_layer(right, **kwargs)
        else:
            layer_right = folium.TileLayer(right, overlay=True, **kwargs)

        sbs = folium.plugins.SideBySideLayers(
            layer_left=layer_left, layer_right=layer_right
        )

        layer_left.add_to(self)
        layer_right.add_to(self)
        sbs.add_to(self)

    def add_basemap(self, basemap="OpenStreetMap", **kwargs):
        """Adds a basemap to the map using a known provider name.

        Args:
            basemap (str): The name of the basemap to add.
            **kwargs: Additional keyword arguments for the folium.TileLayer.
        Raises:
            ValueError: If the basemap name is not recognized.
        """

        basemaps = {
            "OpenStreetMap": {
                "tiles": "OpenStreetMap",
                "attr": "© OpenStreetMap contributors",
            },
            "Esri.WorldImagery": {
                "tiles": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
                "attr": "Tiles © Esri",
            },
            "OpenTopoMap": {
                "tiles": "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
                "attr": "© OpenTopoMap contributors",
            },
            "CartoDB.Positron": {
                "tiles": "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
                "attr": "© CartoDB",
            },
            "Stamen.Terrain": {
                "tiles": "https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.jpg",
                "attr": "Map tiles by Stamen Design, CC BY 3.0",
            },
        }

        if basemap not in basemaps:
            raise ValueError(f"Unsupported basemap: {basemap}")

        tile_info = basemaps[basemap]
        tile_layer = folium.TileLayer(
            tiles=tile_info["tiles"],
            attr=tile_info["attr"],
            name=basemap,
            control=True,
            **kwargs,
        )
        tile_layer.add_to(self)

__init__(center=(0, 0), zoom=2, **kwargs)

Initializes the Map object.

Parameters:

Name Type Description Default
center tuple

The initial center of the map as (latitude, longitude). Defaults to (0, 0).

(0, 0)
zoom int

The initial zoom level of the map. Defaults to 2.

2
**kwargs

Additional keyword arguments for the folium.Map class.

{}
Source code in landcalc/foliumap.py
13
14
15
16
17
18
19
20
21
def __init__(self, center=(0, 0), zoom=2, **kwargs):
    """Initializes the Map object.

    Args:
        center (tuple, optional): The initial center of the map as (latitude, longitude). Defaults to (0, 0).
        zoom (int, optional): The initial zoom level of the map. Defaults to 2.
        **kwargs: Additional keyword arguments for the folium.Map class.
    """
    super().__init__(location=center, zoom_start=zoom, **kwargs)

add_basemap(basemap='OpenStreetMap', **kwargs)

Adds a basemap to the map using a known provider name.

Parameters:

Name Type Description Default
basemap str

The name of the basemap to add.

'OpenStreetMap'
**kwargs

Additional keyword arguments for the folium.TileLayer.

{}
Source code in landcalc/foliumap.py
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def add_basemap(self, basemap="OpenStreetMap", **kwargs):
    """Adds a basemap to the map using a known provider name.

    Args:
        basemap (str): The name of the basemap to add.
        **kwargs: Additional keyword arguments for the folium.TileLayer.
    Raises:
        ValueError: If the basemap name is not recognized.
    """

    basemaps = {
        "OpenStreetMap": {
            "tiles": "OpenStreetMap",
            "attr": "© OpenStreetMap contributors",
        },
        "Esri.WorldImagery": {
            "tiles": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
            "attr": "Tiles © Esri",
        },
        "OpenTopoMap": {
            "tiles": "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
            "attr": "© OpenTopoMap contributors",
        },
        "CartoDB.Positron": {
            "tiles": "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
            "attr": "© CartoDB",
        },
        "Stamen.Terrain": {
            "tiles": "https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.jpg",
            "attr": "Map tiles by Stamen Design, CC BY 3.0",
        },
    }

    if basemap not in basemaps:
        raise ValueError(f"Unsupported basemap: {basemap}")

    tile_info = basemaps[basemap]
    tile_layer = folium.TileLayer(
        tiles=tile_info["tiles"],
        attr=tile_info["attr"],
        name=basemap,
        control=True,
        **kwargs,
    )
    tile_layer.add_to(self)

add_gdf(gdf, **kwargs)

Adds a GeoDataFrame to the map.

Parameters:

Name Type Description Default
gdf GeoDataFrame

The GeoDataFrame to add.

required
**kwargs

Additional keyword arguments for the GeoJSON layer.

{}
Source code in landcalc/foliumap.py
69
70
71
72
73
74
75
76
77
78
def add_gdf(self, gdf, **kwargs):
    """Adds a GeoDataFrame to the map.

    Args:
        gdf (geopandas.GeoDataFrame): The GeoDataFrame to add.
        **kwargs: Additional keyword arguments for the GeoJSON layer.
    """
    gdf = gdf.to_crs(epsg=4326)
    geojson = gdf.__geo_interface__
    self.add_geojson(geojson, **kwargs)

add_geojson(data, zoom_to_layer=True, hover_style=None, **kwargs)

Adds a GeoJSON layer to the map.

Parameters:

Name Type Description Default
data str or dict

The GeoJSON data. Can be a file path (str) or a dictionary.

required
zoom_to_layer bool

Whether to zoom to the layer's bounds. Defaults to True.

True
hover_style dict

Style to apply when hovering over features. Defaults to {"color": "yellow", "fillOpacity": 0.2}.

None
**kwargs

Additional keyword arguments for the folium.GeoJson layer.

{}

Raises:

Type Description
ValueError

If the data type is invalid.

Source code in landcalc/foliumap.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def add_geojson(
    self,
    data,
    zoom_to_layer=True,
    hover_style=None,
    **kwargs,
):
    """Adds a GeoJSON layer to the map.

    Args:
        data (str or dict): The GeoJSON data. Can be a file path (str) or a dictionary.
        zoom_to_layer (bool, optional): Whether to zoom to the layer's bounds. Defaults to True.
        hover_style (dict, optional): Style to apply when hovering over features. Defaults to {"color": "yellow", "fillOpacity": 0.2}.
        **kwargs: Additional keyword arguments for the folium.GeoJson layer.

    Raises:
        ValueError: If the data type is invalid.
    """
    import geopandas as gpd

    if hover_style is None:
        hover_style = {"color": "yellow", "fillOpacity": 0.2}

    if isinstance(data, str):
        gdf = gpd.read_file(data)
        geojson = gdf.__geo_interface__
    elif isinstance(data, dict):
        geojson = data

    geojson = folium.GeoJson(data=geojson, **kwargs)
    geojson.add_to(self)

add_layer_control()

Adds a layer control widget to the map.

Source code in landcalc/foliumap.py
102
103
104
def add_layer_control(self):
    """Adds a layer control widget to the map."""
    folium.LayerControl().add_to(self)

add_shp(data, **kwargs)

Adds a shapefile to the map.

Parameters:

Name Type Description Default
data str

The file path to the shapefile.

required
**kwargs

Additional keyword arguments for the GeoJSON layer.

{}
Source code in landcalc/foliumap.py
55
56
57
58
59
60
61
62
63
64
65
66
67
def add_shp(self, data, **kwargs):
    """Adds a shapefile to the map.

    Args:
        data (str): The file path to the shapefile.
        **kwargs: Additional keyword arguments for the GeoJSON layer.
    """
    import geopandas as gpd

    gdf = gpd.read_file(data)
    gdf = gdf.to_crs(epsg=4326)
    geojson = gdf.__geo_interface__
    self.add_geojson(geojson, **kwargs)

add_split_map(left='openstreetmap', right='cartodbpositron', **kwargs)

Adds a split map to the map.

Parameters:

Name Type Description Default
left str

The tile layer for the left side of the split map. Defaults to "openstreetmap".

'openstreetmap'
right str

The tile layer for the right side of the split map. Defaults to "cartodbpositron".

'cartodbpositron'
Source code in landcalc/foliumap.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def add_split_map(self, left="openstreetmap", right="cartodbpositron", **kwargs):
    """Adds a split map to the map.

    Args:
        left (str, optional): The tile layer for the left side of the split map. Defaults to "openstreetmap".
        right (str, optional): The tile layer for the right side of the split map. Defaults to "cartodbpositron".
    """
    from localtileserver import get_folium_tile_layer

    if left.startswith("http") or os.path.exists(left):
        layer_left = get_folium_tile_layer(left, **kwargs)
    else:
        layer_left = folium.TileLayer(left, overlay=True, **kwargs)
    if right.startswith("http") or os.path.exists(right):
        layer_right = get_folium_tile_layer(right, **kwargs)
    else:
        layer_right = folium.TileLayer(right, overlay=True, **kwargs)

    sbs = folium.plugins.SideBySideLayers(
        layer_left=layer_left, layer_right=layer_right
    )

    layer_left.add_to(self)
    layer_right.add_to(self)
    sbs.add_to(self)

add_vector(data, **kwargs)

Adds vector data to the map.

Parameters:

Name Type Description Default
data str, geopandas.GeoDataFrame, or dict

The vector data. Can be a file path, GeoDataFrame, or GeoJSON dictionary.

required
**kwargs

Additional keyword arguments for the GeoJSON layer.

{}

Raises:

Type Description
ValueError

If the data type is invalid.

Source code in landcalc/foliumap.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
def add_vector(self, data, **kwargs):
    """Adds vector data to the map.

    Args:
        data (str, geopandas.GeoDataFrame, or dict): The vector data. Can be a file path, GeoDataFrame, or GeoJSON dictionary.
        **kwargs: Additional keyword arguments for the GeoJSON layer.

    Raises:
        ValueError: If the data type is invalid.
    """
    import geopandas as gpd

    if isinstance(data, str):
        gdf = gpd.read_file(data)
        self.add_gdf(gdf, **kwargs)
    elif isinstance(data, gpd.GeoDataFrame):
        self.add_gdf(data, **kwargs)
    elif isinstance(data, dict):
        self.add_geojson(data, **kwargs)
    else:
        raise ValueError("Invalid data type")