Foliumatic module¶
Foliumatic (Map)
¶
Source code in bassmap/Foliumatic.py
class Foliumatic(folium.Map):
def __init__(self):
self.map = folium.Map()
def __init__(self, lat=0, lon=0, zoom_start=2):
self.map = folium.Map(location=[lat, lon], zoom_start=zoom_start)
def add_tile_layers(self, tile_layers):
for tile_name, tile_url in tile_layers.items():
folium.TileLayer(tiles=tile_url, name=tile_name).add_to(self.map)
folium.LayerControl().add_to(self.map)
return self.map
def add_basemap(self, basemap_name):
"""
Adds a basemap to the map using a predefined URL template for XYZ tile services.
Parameters:
basemap_name (str): The name of the basemap to add.
"""
basemap_urls = {
'OpenStreetMap': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'Mapbox Satellite': 'https://api.mapbox.com/styles/v1/mapbox/satellite-v9/tiles/{z}/{x}/{y}?access_token=<your-access-token>',
'Esri.WorldImagery': 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
'OpenTopoMap': 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
'Esri.NatGeoWorldMap': 'https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}',
'CartoDB.Positron': 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
}
url_template = basemap_urls.get(basemap_name)
if url_template is None:
raise ValueError(f'Unknown basemap name: {basemap_name}')
new_layer = folium.TileLayer(
tiles=url_template,
name=basemap_name,
attr=' '.join([basemap_name, 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors']),
overlay=True,
control=True
)
self.add_child(new_layer)
def add_shp(self, data, **kwargs):
gdf = gpd.read_file(data)
geojson = gdf.__geo_interface__
self.add_geojson(geojson, **kwargs)
def add_geojson(self, geojson_data):
"""
Adds a GeoJSON layer to the map.
Parameters:
geojson_data (str or dict): The GeoJSON file path, HTTP URL or dictionary to add to the map.
"""
if isinstance(geojson_data, str):
# Load GeoJSON from file or HTTP URL
if geojson_data.startswith(('http://', 'https://')):
response = requests.get(geojson_data)
geojson_layer = folium.GeoJson(data=response.content.decode())
else:
with open(geojson_data, 'r') as f:
geojson_layer = folium.GeoJson(data=json.load(f))
elif isinstance(geojson_data, dict):
# Load GeoJSON from dictionary
geojson_layer = folium.GeoJson(data=geojson_data)
else:
raise ValueError('Invalid input format. Must be GeoJSON file path, HTTP URL or dictionary.')
geojson_layer.add_to(self)
def __init__(self, **kwargs):
"""
Initializes a new instance of the Foliumatic class, which inherits from the folium.Map class.
Args:
**kwargs: Keyword arguments that can be passed to the folium.Map constructor.
"""
super().__init__(**kwargs)
self.bounds = []
def add_vector(self, vector_data):
"""
Adds vector data to the map.
The supported data types include file paths, URLs, GeoJSON dictionaries, and GeoDataFrames.
Args:
vector_data: The vector data to add to the map. Can be a file path, a URL, a GeoJSON dictionary, or a GeoDataFrame.
Raises:
ValueError: If the input data type is not supported or the shapefile is missing necessary files.
"""
if isinstance(vector_data, str):
# vector_data is a file path or a URL
if vector_data.startswith('http'):
# vector_data is a URL
r = requests.get(vector_data)
if zipfile.is_zipfile(io.BytesIO(r.content)):
# vector_data is a zipped shapefile
with zipfile.ZipFile(io.BytesIO(r.content)) as z:
filenames = [y for y in sorted(z.namelist()) for ending in ['dbf', 'prj', 'shp', 'shx'] if y.endswith(ending) ]
if not filenames:
raise ValueError("Zip file does not contain .shp file.")
if len(filenames) < 4:
raise ValueError("Zip file does not contain all necessary files for a shapefile (shp, dbf, shx, prj).")
# Read the shapefile using geopandas and convert it to GeoJSON
gdf = gpd.read_file(io.BytesIO(z.read(filenames[0])))
geojson = gdf.to_crs(epsg='4326').to_json()
else:
# vector_data is a GeoJSON URL
geojson = requests.get(vector_data).json()
else:
# vector_data is a file path
if zipfile.is_zipfile(vector_data):
# vector_data is a zipped shapefile
with zipfile.ZipFile(vector_data) as z:
filenames = [y for y in sorted(z.namelist()) for ending in ['dbf', 'prj', 'shp', 'shx'] if y.endswith(ending) ]
if not filenames:
raise ValueError("Zip file does not contain .shp file.")
if len(filenames) < 4:
raise ValueError("Zip file does not contain all necessary files for a shapefile (shp, dbf, shx, prj).")
# Read the shapefile using geopandas and convert it to GeoJSON
gdf = gpd.read_file(io.BytesIO(z.read(filenames[0])))
geojson = gdf.to_crs(epsg='4326').to_json()
else:
# vector_data is a file path to a GeoJSON file or a shapefile
gdf = gpd.read_file(vector_data)
geojson = gdf.to_crs(epsg='4326').to_json()
elif isinstance(vector_data, dict):
# vector_data is a GeoJSON dictionary
geojson = vector_data
elif isinstance(vector_data, gpd.GeoDataFrame):
# vector_data is a GeoDataFrame
geojson = vector_data.to_crs(epsg='4326').to_json()
else:
raise ValueError("Invalid input data type. Supported data types include file paths, URLs, GeoJSON dictionaries, and GeoDataFrames.")
folium.GeoJson(
geojson,
name="geojson"
).add_to(self)
folium.LayerControl().add_to(self)
__init__(self, **kwargs)
special
¶
Initializes a new instance of the Foliumatic class, which inherits from the folium.Map class.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
**kwargs |
Keyword arguments that can be passed to the folium.Map constructor. |
{} |
Source code in bassmap/Foliumatic.py
def __init__(self, **kwargs):
"""
Initializes a new instance of the Foliumatic class, which inherits from the folium.Map class.
Args:
**kwargs: Keyword arguments that can be passed to the folium.Map constructor.
"""
super().__init__(**kwargs)
self.bounds = []
add_basemap(self, basemap_name)
¶
Adds a basemap to the map using a predefined URL template for XYZ tile services.
basemap_name (str): The name of the basemap to add.
Source code in bassmap/Foliumatic.py
def add_basemap(self, basemap_name):
"""
Adds a basemap to the map using a predefined URL template for XYZ tile services.
Parameters:
basemap_name (str): The name of the basemap to add.
"""
basemap_urls = {
'OpenStreetMap': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'Mapbox Satellite': 'https://api.mapbox.com/styles/v1/mapbox/satellite-v9/tiles/{z}/{x}/{y}?access_token=<your-access-token>',
'Esri.WorldImagery': 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
'OpenTopoMap': 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
'Esri.NatGeoWorldMap': 'https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}',
'CartoDB.Positron': 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
}
url_template = basemap_urls.get(basemap_name)
if url_template is None:
raise ValueError(f'Unknown basemap name: {basemap_name}')
new_layer = folium.TileLayer(
tiles=url_template,
name=basemap_name,
attr=' '.join([basemap_name, 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors']),
overlay=True,
control=True
)
self.add_child(new_layer)
add_geojson(self, geojson_data)
¶
Adds a GeoJSON layer to the map.
geojson_data (str or dict): The GeoJSON file path, HTTP URL or dictionary to add to the map.
Source code in bassmap/Foliumatic.py
def add_geojson(self, geojson_data):
"""
Adds a GeoJSON layer to the map.
Parameters:
geojson_data (str or dict): The GeoJSON file path, HTTP URL or dictionary to add to the map.
"""
if isinstance(geojson_data, str):
# Load GeoJSON from file or HTTP URL
if geojson_data.startswith(('http://', 'https://')):
response = requests.get(geojson_data)
geojson_layer = folium.GeoJson(data=response.content.decode())
else:
with open(geojson_data, 'r') as f:
geojson_layer = folium.GeoJson(data=json.load(f))
elif isinstance(geojson_data, dict):
# Load GeoJSON from dictionary
geojson_layer = folium.GeoJson(data=geojson_data)
else:
raise ValueError('Invalid input format. Must be GeoJSON file path, HTTP URL or dictionary.')
geojson_layer.add_to(self)
add_vector(self, vector_data)
¶
Adds vector data to the map.
The supported data types include file paths, URLs, GeoJSON dictionaries, and GeoDataFrames.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
vector_data |
The vector data to add to the map. Can be a file path, a URL, a GeoJSON dictionary, or a GeoDataFrame. |
required |
Exceptions:
Type | Description |
---|---|
ValueError |
If the input data type is not supported or the shapefile is missing necessary files. |
Source code in bassmap/Foliumatic.py
def add_vector(self, vector_data):
"""
Adds vector data to the map.
The supported data types include file paths, URLs, GeoJSON dictionaries, and GeoDataFrames.
Args:
vector_data: The vector data to add to the map. Can be a file path, a URL, a GeoJSON dictionary, or a GeoDataFrame.
Raises:
ValueError: If the input data type is not supported or the shapefile is missing necessary files.
"""
if isinstance(vector_data, str):
# vector_data is a file path or a URL
if vector_data.startswith('http'):
# vector_data is a URL
r = requests.get(vector_data)
if zipfile.is_zipfile(io.BytesIO(r.content)):
# vector_data is a zipped shapefile
with zipfile.ZipFile(io.BytesIO(r.content)) as z:
filenames = [y for y in sorted(z.namelist()) for ending in ['dbf', 'prj', 'shp', 'shx'] if y.endswith(ending) ]
if not filenames:
raise ValueError("Zip file does not contain .shp file.")
if len(filenames) < 4:
raise ValueError("Zip file does not contain all necessary files for a shapefile (shp, dbf, shx, prj).")
# Read the shapefile using geopandas and convert it to GeoJSON
gdf = gpd.read_file(io.BytesIO(z.read(filenames[0])))
geojson = gdf.to_crs(epsg='4326').to_json()
else:
# vector_data is a GeoJSON URL
geojson = requests.get(vector_data).json()
else:
# vector_data is a file path
if zipfile.is_zipfile(vector_data):
# vector_data is a zipped shapefile
with zipfile.ZipFile(vector_data) as z:
filenames = [y for y in sorted(z.namelist()) for ending in ['dbf', 'prj', 'shp', 'shx'] if y.endswith(ending) ]
if not filenames:
raise ValueError("Zip file does not contain .shp file.")
if len(filenames) < 4:
raise ValueError("Zip file does not contain all necessary files for a shapefile (shp, dbf, shx, prj).")
# Read the shapefile using geopandas and convert it to GeoJSON
gdf = gpd.read_file(io.BytesIO(z.read(filenames[0])))
geojson = gdf.to_crs(epsg='4326').to_json()
else:
# vector_data is a file path to a GeoJSON file or a shapefile
gdf = gpd.read_file(vector_data)
geojson = gdf.to_crs(epsg='4326').to_json()
elif isinstance(vector_data, dict):
# vector_data is a GeoJSON dictionary
geojson = vector_data
elif isinstance(vector_data, gpd.GeoDataFrame):
# vector_data is a GeoDataFrame
geojson = vector_data.to_crs(epsg='4326').to_json()
else:
raise ValueError("Invalid input data type. Supported data types include file paths, URLs, GeoJSON dictionaries, and GeoDataFrames.")
folium.GeoJson(
geojson,
name="geojson"
).add_to(self)
folium.LayerControl().add_to(self)