common module¶
This module contains some common functions for both folium and ipyleaflet.
PlanetaryComputerEndpoint (TitilerEndpoint)
¶
This class contains the methods for the Microsoft Planetary Computer endpoint.
Source code in leafmap/common.py
class PlanetaryComputerEndpoint(TitilerEndpoint):
"""This class contains the methods for the Microsoft Planetary Computer endpoint."""
def __init__(
self,
endpoint="https://planetarycomputer.microsoft.com/api/data/v1",
name="item",
TileMatrixSetId="WebMercatorQuad",
):
"""Initialize the PlanetaryComputerEndpoint object.
Args:
endpoint (str, optional): The endpoint of the titiler server. Defaults to "https://planetarycomputer.microsoft.com/api/data/v1".
name (str, optional): The name to be used in the file path. Defaults to "item".
TileMatrixSetId (str, optional): The TileMatrixSetId to be used in the file path. Defaults to "WebMercatorQuad".
"""
super().__init__(endpoint, name, TileMatrixSetId)
def url_for_stac_collection(self):
return f"{self.endpoint}/collection/{self.TileMatrixSetId}/tilejson.json"
def url_for_collection_assets(self):
return f"{self.endpoint}/collection/assets"
def url_for_collection_bounds(self):
return f"{self.endpoint}/collection/bounds"
def url_for_collection_info(self):
return f"{self.endpoint}/collection/info"
def url_for_collection_info_geojson(self):
return f"{self.endpoint}/collection/info.geojson"
def url_for_collection_pixel_value(self, lon, lat):
return f"{self.endpoint}/collection/point/{lon},{lat}"
def url_for_collection_wmts(self):
return f"{self.endpoint}/collection/{self.TileMatrixSetId}/WMTSCapabilities.xml"
def url_for_collection_lat_lon_assets(self, lng, lat):
return f"{self.endpoint}/collection/{lng},{lat}/assets"
def url_for_collection_bbox_assets(self, minx, miny, maxx, maxy):
return f"{self.endpoint}/collection/{minx},{miny},{maxx},{maxy}/assets"
def url_for_stac_mosaic(self, searchid):
return f"{self.endpoint}/mosaic/{searchid}/{self.TileMatrixSetId}/tilejson.json"
def url_for_mosaic_info(self, searchid):
return f"{self.endpoint}/mosaic/{searchid}/info"
def url_for_mosaic_lat_lon_assets(self, searchid, lon, lat):
return f"{self.endpoint}/mosaic/{searchid}/{lon},{lat}/assets"
__init__(self, endpoint='https://planetarycomputer.microsoft.com/api/data/v1', name='item', TileMatrixSetId='WebMercatorQuad')
special
¶
Initialize the PlanetaryComputerEndpoint object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
endpoint |
str |
The endpoint of the titiler server. Defaults to "https://planetarycomputer.microsoft.com/api/data/v1". |
'https://planetarycomputer.microsoft.com/api/data/v1' |
name |
str |
The name to be used in the file path. Defaults to "item". |
'item' |
TileMatrixSetId |
str |
The TileMatrixSetId to be used in the file path. Defaults to "WebMercatorQuad". |
'WebMercatorQuad' |
Source code in leafmap/common.py
def __init__(
self,
endpoint="https://planetarycomputer.microsoft.com/api/data/v1",
name="item",
TileMatrixSetId="WebMercatorQuad",
):
"""Initialize the PlanetaryComputerEndpoint object.
Args:
endpoint (str, optional): The endpoint of the titiler server. Defaults to "https://planetarycomputer.microsoft.com/api/data/v1".
name (str, optional): The name to be used in the file path. Defaults to "item".
TileMatrixSetId (str, optional): The TileMatrixSetId to be used in the file path. Defaults to "WebMercatorQuad".
"""
super().__init__(endpoint, name, TileMatrixSetId)
TitilerEndpoint
¶
This class contains the methods for the titiler endpoint.
Source code in leafmap/common.py
class TitilerEndpoint:
"""This class contains the methods for the titiler endpoint."""
def __init__(
self,
endpoint="https://titiler.xyz",
name="stac",
TileMatrixSetId="WebMercatorQuad",
):
"""Initialize the TitilerEndpoint object.
Args:
endpoint (str, optional): The endpoint of the titiler server. Defaults to "https://titiler.xyz".
name (str, optional): The name to be used in the file path. Defaults to "stac".
TileMatrixSetId (str, optional): The TileMatrixSetId to be used in the file path. Defaults to "WebMercatorQuad".
"""
self.endpoint = endpoint
self.name = name
self.TileMatrixSetId = TileMatrixSetId
def url_for_stac_item(self):
return f"{self.endpoint}/{self.name}/{self.TileMatrixSetId}/tilejson.json"
def url_for_stac_assets(self):
return f"{self.endpoint}/{self.name}/assets"
def url_for_stac_bounds(self):
return f"{self.endpoint}/{self.name}/bounds"
def url_for_stac_info(self):
return f"{self.endpoint}/{self.name}/info"
def url_for_stac_info_geojson(self):
return f"{self.endpoint}/{self.name}/info.geojson"
def url_for_stac_statistics(self):
return f"{self.endpoint}/{self.name}/statistics"
def url_for_stac_pixel_value(self, lon, lat):
return f"{self.endpoint}/{self.name}/point/{lon},{lat}"
def url_for_stac_wmts(self):
return (
f"{self.endpoint}/{self.name}/{self.TileMatrixSetId}/WMTSCapabilities.xml"
)
__init__(self, endpoint='https://titiler.xyz', name='stac', TileMatrixSetId='WebMercatorQuad')
special
¶
Initialize the TitilerEndpoint object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
endpoint |
str |
The endpoint of the titiler server. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
name |
str |
The name to be used in the file path. Defaults to "stac". |
'stac' |
TileMatrixSetId |
str |
The TileMatrixSetId to be used in the file path. Defaults to "WebMercatorQuad". |
'WebMercatorQuad' |
Source code in leafmap/common.py
def __init__(
self,
endpoint="https://titiler.xyz",
name="stac",
TileMatrixSetId="WebMercatorQuad",
):
"""Initialize the TitilerEndpoint object.
Args:
endpoint (str, optional): The endpoint of the titiler server. Defaults to "https://titiler.xyz".
name (str, optional): The name to be used in the file path. Defaults to "stac".
TileMatrixSetId (str, optional): The TileMatrixSetId to be used in the file path. Defaults to "WebMercatorQuad".
"""
self.endpoint = endpoint
self.name = name
self.TileMatrixSetId = TileMatrixSetId
WhiteboxTools (WhiteboxTools)
¶
This class inherits the whitebox WhiteboxTools class.
Source code in leafmap/common.py
class WhiteboxTools(whitebox.WhiteboxTools):
"""This class inherits the whitebox WhiteboxTools class."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
__install_from_github(url)
¶
Install a package from a GitHub repository.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
The URL of the GitHub repository. |
required |
Source code in leafmap/common.py
def __install_from_github(url):
"""Install a package from a GitHub repository.
Args:
url (str): The URL of the GitHub repository.
"""
try:
download_dir = os.path.join(os.path.expanduser("~"), "Downloads")
if not os.path.exists(download_dir):
os.makedirs(download_dir)
repo_name = os.path.basename(url)
zip_url = os.path.join(url, "archive/master.zip")
filename = repo_name + "-master.zip"
download_from_url(
url=zip_url, out_file_name=filename, out_dir=download_dir, unzip=True
)
pkg_dir = os.path.join(download_dir, repo_name + "-master")
pkg_name = os.path.basename(url)
work_dir = os.getcwd()
os.chdir(pkg_dir)
print("Installing {}...".format(pkg_name))
cmd = "pip install ."
os.system(cmd)
os.chdir(work_dir)
print("{} has been installed successfully.".format(pkg_name))
# print("\nPlease comment out 'install_from_github()' and restart the kernel to take effect:\nJupyter menu -> Kernel -> Restart & Clear Output")
except Exception as e:
raise Exception(e)
adjust_longitude(in_fc)
¶
Adjusts longitude if it is less than -180 or greater than 180.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_fc |
dict |
The input dictionary containing coordinates. |
required |
Returns:
Type | Description |
---|---|
dict |
A dictionary containing the converted longitudes |
Source code in leafmap/common.py
def adjust_longitude(in_fc):
"""Adjusts longitude if it is less than -180 or greater than 180.
Args:
in_fc (dict): The input dictionary containing coordinates.
Returns:
dict: A dictionary containing the converted longitudes
"""
try:
keys = in_fc.keys()
if "geometry" in keys:
coordinates = in_fc["geometry"]["coordinates"]
if in_fc["geometry"]["type"] == "Point":
longitude = coordinates[0]
if longitude < -180:
longitude = 360 + longitude
elif longitude > 180:
longitude = longitude - 360
in_fc["geometry"]["coordinates"][0] = longitude
elif in_fc["geometry"]["type"] == "Polygon":
for index1, item in enumerate(coordinates):
for index2, element in enumerate(item):
longitude = element[0]
if longitude < -180:
longitude = 360 + longitude
elif longitude > 180:
longitude = longitude - 360
in_fc["geometry"]["coordinates"][index1][index2][0] = longitude
elif in_fc["geometry"]["type"] == "LineString":
for index, element in enumerate(coordinates):
longitude = element[0]
if longitude < -180:
longitude = 360 + longitude
elif longitude > 180:
longitude = longitude - 360
in_fc["geometry"]["coordinates"][index][0] = longitude
elif "type" in keys:
coordinates = in_fc["coordinates"]
if in_fc["type"] == "Point":
longitude = coordinates[0]
if longitude < -180:
longitude = 360 + longitude
elif longitude > 180:
longitude = longitude - 360
in_fc["coordinates"][0] = longitude
elif in_fc["type"] == "Polygon":
for index1, item in enumerate(coordinates):
for index2, element in enumerate(item):
longitude = element[0]
if longitude < -180:
longitude = 360 + longitude
elif longitude > 180:
longitude = longitude - 360
in_fc["coordinates"][index1][index2][0] = longitude
elif in_fc["type"] == "LineString":
for index, element in enumerate(coordinates):
longitude = element[0]
if longitude < -180:
longitude = 360 + longitude
elif longitude > 180:
longitude = longitude - 360
in_fc["coordinates"][index][0] = longitude
return in_fc
except Exception as e:
print(e)
return None
basemap_xyz_tiles()
¶
Returns a dictionary containing a set of basemaps that are XYZ tile layers.
Returns:
Type | Description |
---|---|
dict |
A dictionary of XYZ tile layers. |
Source code in leafmap/common.py
def basemap_xyz_tiles():
"""Returns a dictionary containing a set of basemaps that are XYZ tile layers.
Returns:
dict: A dictionary of XYZ tile layers.
"""
from .leafmap import basemaps
layers_dict = {}
keys = dict(basemaps).keys()
for key in keys:
if isinstance(basemaps[key], ipyleaflet.WMSLayer):
pass
else:
layers_dict[key] = basemaps[key]
return layers_dict
bbox_to_gdf(bbox, crs='EPSG:4326')
¶
Converts a bounding box to a GeoDataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
bbox |
tuple |
A bounding box in the form of a tuple (minx, miny, maxx, maxy). |
required |
crs |
str |
The coordinate reference system of the bounding box to convert to. Defaults to "EPSG:4326". |
'EPSG:4326' |
Returns:
Type | Description |
---|---|
geopandas.GeoDataFrame |
A GeoDataFrame containing the bounding box. |
Source code in leafmap/common.py
def bbox_to_gdf(bbox, crs="EPSG:4326"):
"""Converts a bounding box to a GeoDataFrame.
Args:
bbox (tuple): A bounding box in the form of a tuple (minx, miny, maxx, maxy).
crs (str, optional): The coordinate reference system of the bounding box to convert to. Defaults to "EPSG:4326".
Returns:
geopandas.GeoDataFrame: A GeoDataFrame containing the bounding box.
"""
check_package(name="geopandas", URL="https://geopandas.org")
from shapely.geometry import box
import geopandas as gpd
minx, miny, maxx, maxy = bbox
geometry = box(minx, miny, maxx, maxy)
d = {"geometry": [geometry]}
gdf = gpd.GeoDataFrame(d, crs="EPSG:4326")
gdf.to_crs(crs=crs, inplace=True)
return gdf
bbox_to_geojson(bounds)
¶
Convert coordinates of a bounding box to a geojson.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
bounds |
list |
A list of coordinates representing [left, bottom, right, top]. |
required |
Returns:
Type | Description |
---|---|
dict |
A geojson feature. |
Source code in leafmap/common.py
def bbox_to_geojson(bounds):
"""Convert coordinates of a bounding box to a geojson.
Args:
bounds (list): A list of coordinates representing [left, bottom, right, top].
Returns:
dict: A geojson feature.
"""
return {
"geometry": {
"type": "Polygon",
"coordinates": [
[
[bounds[0], bounds[3]],
[bounds[0], bounds[1]],
[bounds[2], bounds[1]],
[bounds[2], bounds[3]],
[bounds[0], bounds[3]],
]
],
},
"type": "Feature",
}
cesium_to_streamlit(html, width=800, height=600, responsive=True, scrolling=False, token_name=None, token_value=None, **kwargs)
¶
Renders an cesium HTML file in a Streamlit app. This method is a static Streamlit Component, meaning, no information is passed back from Leaflet on browser interaction.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
html |
str |
The HTML file to render. It can a local file path or a URL. |
required |
width |
int |
Width of the map. Defaults to 800. |
800 |
height |
int |
Height of the map. Defaults to 600. |
600 |
responsive |
bool |
Whether to make the map responsive. Defaults to True. |
True |
scrolling |
bool |
Whether to allow the map to scroll. Defaults to False. |
False |
token_name |
str |
The name of the token in the HTML file to be replaced. Defaults to None. |
None |
token_value |
str |
The value of the token to pass to the HTML file. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
streamlit.components |
components.html object. |
Source code in leafmap/common.py
def cesium_to_streamlit(
html,
width=800,
height=600,
responsive=True,
scrolling=False,
token_name=None,
token_value=None,
**kwargs,
):
"""Renders an cesium HTML file in a Streamlit app. This method is a static Streamlit Component, meaning, no information is passed back from Leaflet on browser interaction.
Args:
html (str): The HTML file to render. It can a local file path or a URL.
width (int, optional): Width of the map. Defaults to 800.
height (int, optional): Height of the map. Defaults to 600.
responsive (bool, optional): Whether to make the map responsive. Defaults to True.
scrolling (bool, optional): Whether to allow the map to scroll. Defaults to False.
token_name (str, optional): The name of the token in the HTML file to be replaced. Defaults to None.
token_value (str, optional): The value of the token to pass to the HTML file. Defaults to None.
Returns:
streamlit.components: components.html object.
"""
if token_name is None:
token_name = "your_access_token"
if token_value is None:
token_value = os.environ.get("CESIUM_TOKEN")
html_to_streamlit(
html, width, height, responsive, scrolling, token_name, token_value
)
check_cmap(cmap)
¶
Check the colormap and return a list of colors.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
cmap |
str | list | Box |
The colormap to check. |
required |
Returns:
Type | Description |
---|---|
list |
A list of colors. |
Source code in leafmap/common.py
def check_cmap(cmap):
"""Check the colormap and return a list of colors.
Args:
cmap (str | list | Box): The colormap to check.
Returns:
list: A list of colors.
"""
from box import Box
from .colormaps import get_palette
if isinstance(cmap, str):
try:
return get_palette(cmap)
except Exception as e:
raise Exception(f"{cmap} is not a valid colormap.")
elif isinstance(cmap, Box):
return list(cmap["default"])
elif isinstance(cmap, list) or isinstance(cmap, tuple):
return cmap
else:
raise Exception(f"{cmap} is not a valid colormap.")
check_color(in_color)
¶
Checks the input color and returns the corresponding hex color code.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_color |
str or tuple |
It can be a string (e.g., 'red', '#ffff00') or tuple (e.g., (255, 127, 0)). |
required |
Returns:
Type | Description |
---|---|
str |
A hex color code. |
Source code in leafmap/common.py
def check_color(in_color):
"""Checks the input color and returns the corresponding hex color code.
Args:
in_color (str or tuple): It can be a string (e.g., 'red', '#ffff00') or tuple (e.g., (255, 127, 0)).
Returns:
str: A hex color code.
"""
import colour
out_color = "#000000" # default black color
if isinstance(in_color, tuple) and len(in_color) == 3:
if all(isinstance(item, int) for item in in_color):
rescaled_color = [x / 255.0 for x in in_color]
out_color = colour.Color(rgb=tuple(rescaled_color))
return out_color.hex_l
else:
print(
"RGB color must be a tuple with three integer values ranging from 0 to 255."
)
return
else:
try:
out_color = colour.Color(in_color)
return out_color.hex_l
except Exception as e:
print("The provided color is invalid. Using the default black color.")
print(e)
return out_color
check_dir(dir_path, make_dirs=True)
¶
Checks if a directory exists and creates it if it does not.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
dir_path |
[str |
The path to the directory. |
required |
make_dirs |
bool |
Whether to create the directory if it does not exist. Defaults to True. |
True |
Exceptions:
Type | Description |
---|---|
FileNotFoundError |
If the directory could not be found. |
TypeError |
If the input directory path is not a string. |
Returns:
Type | Description |
---|---|
str |
The path to the directory. |
Source code in leafmap/common.py
def check_dir(dir_path, make_dirs=True):
"""Checks if a directory exists and creates it if it does not.
Args:
dir_path ([str): The path to the directory.
make_dirs (bool, optional): Whether to create the directory if it does not exist. Defaults to True.
Raises:
FileNotFoundError: If the directory could not be found.
TypeError: If the input directory path is not a string.
Returns:
str: The path to the directory.
"""
if isinstance(dir_path, str):
if dir_path.startswith("~"):
dir_path = os.path.expanduser(dir_path)
else:
dir_path = os.path.abspath(dir_path)
if not os.path.exists(dir_path) and make_dirs:
os.makedirs(dir_path)
if os.path.exists(dir_path):
return dir_path
else:
raise FileNotFoundError("The provided directory could not be found.")
else:
raise TypeError("The provided directory path must be a string.")
check_file_path(file_path, make_dirs=True)
¶
Gets the absolute file path.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
file_path |
str |
The path to the file. |
required |
make_dirs |
bool |
Whether to create the directory if it does not exist. Defaults to True. |
True |
Exceptions:
Type | Description |
---|---|
FileNotFoundError |
If the directory could not be found. |
TypeError |
If the input directory path is not a string. |
Returns:
Type | Description |
---|---|
str |
The absolute path to the file. |
Source code in leafmap/common.py
def check_file_path(file_path, make_dirs=True):
"""Gets the absolute file path.
Args:
file_path (str): The path to the file.
make_dirs (bool, optional): Whether to create the directory if it does not exist. Defaults to True.
Raises:
FileNotFoundError: If the directory could not be found.
TypeError: If the input directory path is not a string.
Returns:
str: The absolute path to the file.
"""
if isinstance(file_path, str):
if file_path.startswith("~"):
file_path = os.path.expanduser(file_path)
else:
file_path = os.path.abspath(file_path)
file_dir = os.path.dirname(file_path)
if not os.path.exists(file_dir) and make_dirs:
os.makedirs(file_dir)
return file_path
else:
raise TypeError("The provided file path must be a string.")
check_titiler_endpoint(titiler_endpoint=None)
¶
Returns the default titiler endpoint.
Returns:
Type | Description |
---|---|
object |
A titiler endpoint. |
Source code in leafmap/common.py
def check_titiler_endpoint(titiler_endpoint=None):
"""Returns the default titiler endpoint.
Returns:
object: A titiler endpoint.
"""
if titiler_endpoint is None:
if os.environ.get("TITILER_ENDPOINT") == "planetary-computer":
titiler_endpoint = PlanetaryComputerEndpoint()
else:
titiler_endpoint = TitilerEndpoint()
elif titiler_endpoint in ["planetary-computer", "pc"]:
titiler_endpoint = PlanetaryComputerEndpoint()
return titiler_endpoint
classify(data, column, cmap=None, colors=None, labels=None, scheme='Quantiles', k=5, legend_kwds=None, classification_kwds=None)
¶
Classify a dataframe column using a variety of classification schemes.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
str | pd.DataFrame | gpd.GeoDataFrame |
The data to classify. It can be a filepath to a vector dataset, a pandas dataframe, or a geopandas geodataframe. |
required |
column |
str |
The column to classify. |
required |
cmap |
str |
The name of a colormap recognized by matplotlib. Defaults to None. |
None |
colors |
list |
A list of colors to use for the classification. Defaults to None. |
None |
labels |
list |
A list of labels to use for the legend. Defaults to None. |
None |
scheme |
str |
Name of a choropleth classification scheme (requires mapclassify). Name of a choropleth classification scheme (requires mapclassify). A mapclassify.MapClassifier object will be used under the hood. Supported are all schemes provided by mapclassify (e.g. 'BoxPlot', 'EqualInterval', 'FisherJenks', 'FisherJenksSampled', 'HeadTailBreaks', 'JenksCaspall', 'JenksCaspallForced', 'JenksCaspallSampled', 'MaxP', 'MaximumBreaks', 'NaturalBreaks', 'Quantiles', 'Percentiles', 'StdMean', 'UserDefined'). Arguments can be passed in classification_kwds. |
'Quantiles' |
k |
int |
Number of classes (ignored if scheme is None or if column is categorical). Default to 5. |
5 |
legend_kwds |
dict |
Keyword arguments to pass to :func: |
None |
classification_kwds |
dict |
Keyword arguments to pass to mapclassify. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
pd.DataFrame, dict |
A pandas dataframe with the classification applied and a legend dictionary. |
Source code in leafmap/common.py
def classify(
data,
column,
cmap=None,
colors=None,
labels=None,
scheme="Quantiles",
k=5,
legend_kwds=None,
classification_kwds=None,
):
"""Classify a dataframe column using a variety of classification schemes.
Args:
data (str | pd.DataFrame | gpd.GeoDataFrame): The data to classify. It can be a filepath to a vector dataset, a pandas dataframe, or a geopandas geodataframe.
column (str): The column to classify.
cmap (str, optional): The name of a colormap recognized by matplotlib. Defaults to None.
colors (list, optional): A list of colors to use for the classification. Defaults to None.
labels (list, optional): A list of labels to use for the legend. Defaults to None.
scheme (str, optional): Name of a choropleth classification scheme (requires mapclassify).
Name of a choropleth classification scheme (requires mapclassify).
A mapclassify.MapClassifier object will be used
under the hood. Supported are all schemes provided by mapclassify (e.g.
'BoxPlot', 'EqualInterval', 'FisherJenks', 'FisherJenksSampled',
'HeadTailBreaks', 'JenksCaspall', 'JenksCaspallForced',
'JenksCaspallSampled', 'MaxP', 'MaximumBreaks',
'NaturalBreaks', 'Quantiles', 'Percentiles', 'StdMean',
'UserDefined'). Arguments can be passed in classification_kwds.
k (int, optional): Number of classes (ignored if scheme is None or if column is categorical). Default to 5.
legend_kwds (dict, optional): Keyword arguments to pass to :func:`matplotlib.pyplot.legend` or `matplotlib.pyplot.colorbar`. Defaults to None.
Keyword arguments to pass to :func:`matplotlib.pyplot.legend` or
Additional accepted keywords when `scheme` is specified:
fmt : string
A formatting specification for the bin edges of the classes in the
legend. For example, to have no decimals: ``{"fmt": "{:.0f}"}``.
labels : list-like
A list of legend labels to override the auto-generated labblels.
Needs to have the same number of elements as the number of
classes (`k`).
interval : boolean (default False)
An option to control brackets from mapclassify legend.
If True, open/closed interval brackets are shown in the legend.
classification_kwds (dict, optional): Keyword arguments to pass to mapclassify. Defaults to None.
Returns:
pd.DataFrame, dict: A pandas dataframe with the classification applied and a legend dictionary.
"""
import warnings
import numpy as np
import pandas as pd
import geopandas as gpd
import matplotlib as mpl
import matplotlib.pyplot as plt
try:
import mapclassify
except ImportError:
raise ImportError(
"mapclassify is required for this function. Install with `pip install mapclassify`."
)
if isinstance(data, gpd.GeoDataFrame) or isinstance(data, pd.DataFrame):
df = data
else:
try:
df = gpd.read_file(data)
except Exception:
raise TypeError(
"Data must be a GeoDataFrame or a path to a file that can be read by geopandas.read_file()."
)
if df.empty:
warnings.warn(
"The GeoDataFrame you are attempting to plot is "
"empty. Nothing has been displayed.",
UserWarning,
)
return
columns = df.columns.values.tolist()
if column not in columns:
raise ValueError(
f"{column} is not a column in the GeoDataFrame. It must be one of {columns}."
)
# Convert categorical data to numeric
init_column = None
value_list = None
if np.issubdtype(df[column].dtype, np.object0):
value_list = df[column].unique().tolist()
value_list.sort()
df["category"] = df[column].replace(value_list, range(0, len(value_list)))
init_column = column
column = "category"
k = len(value_list)
if legend_kwds is not None:
legend_kwds = legend_kwds.copy()
# To accept pd.Series and np.arrays as column
if isinstance(column, (np.ndarray, pd.Series)):
if column.shape[0] != df.shape[0]:
raise ValueError(
"The dataframe and given column have different number of rows."
)
else:
values = column
# Make sure index of a Series matches index of df
if isinstance(values, pd.Series):
values = values.reindex(df.index)
else:
values = df[column]
values = df[column]
nan_idx = np.asarray(pd.isna(values), dtype="bool")
if cmap is None:
cmap = "Blues"
cmap = plt.cm.get_cmap(cmap, k)
if colors is None:
colors = [mpl.colors.rgb2hex(cmap(i))[1:] for i in range(cmap.N)]
colors = ["#" + i for i in colors]
elif isinstance(colors, list):
colors = [check_color(i) for i in colors]
elif isinstance(colors, str):
colors = [check_color(colors)] * k
allowed_schemes = [
"BoxPlot",
"EqualInterval",
"FisherJenks",
"FisherJenksSampled",
"HeadTailBreaks",
"JenksCaspall",
"JenksCaspallForced",
"JenksCaspallSampled",
"MaxP",
"MaximumBreaks",
"NaturalBreaks",
"Quantiles",
"Percentiles",
"StdMean",
"UserDefined",
]
if scheme.lower() not in [s.lower() for s in allowed_schemes]:
raise ValueError(
f"{scheme} is not a valid scheme. It must be one of {allowed_schemes}."
)
if classification_kwds is None:
classification_kwds = {}
if "k" not in classification_kwds:
classification_kwds["k"] = k
binning = mapclassify.classify(
np.asarray(values[~nan_idx]), scheme, **classification_kwds
)
df["category"] = binning.yb
df["color"] = [colors[i] for i in df["category"]]
if legend_kwds is None:
legend_kwds = {}
if "interval" not in legend_kwds:
legend_kwds["interval"] = True
if "fmt" not in legend_kwds:
if np.issubdtype(df[column].dtype, np.floating):
legend_kwds["fmt"] = "{:.2f}"
else:
legend_kwds["fmt"] = "{:.0f}"
if labels is None:
# set categorical to True for creating the legend
if legend_kwds is not None and "labels" in legend_kwds:
if len(legend_kwds["labels"]) != binning.k:
raise ValueError(
"Number of labels must match number of bins, "
"received {} labels for {} bins".format(
len(legend_kwds["labels"]), binning.k
)
)
else:
labels = list(legend_kwds.pop("labels"))
else:
# fmt = "{:.2f}"
if legend_kwds is not None and "fmt" in legend_kwds:
fmt = legend_kwds.pop("fmt")
labels = binning.get_legend_classes(fmt)
if legend_kwds is not None:
show_interval = legend_kwds.pop("interval", False)
else:
show_interval = False
if not show_interval:
labels = [c[1:-1] for c in labels]
if init_column is not None:
labels = value_list
elif isinstance(labels, list):
if len(labels) != len(colors):
raise ValueError("The number of labels must match the number of colors.")
else:
raise ValueError("labels must be a list or None.")
legend_dict = dict(zip(labels, colors))
df["category"] = df["category"] + 1
return df, legend_dict
clip_image(image, mask, output)
¶
Clip an image by mask.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
image |
str |
Path to the image file in GeoTIFF format. |
required |
mask |
str | list | dict |
The mask used to extract the image. It can be a path to vector datasets (e.g., GeoJSON, Shapefile), a list of coordinates, or m.user_roi. |
required |
output |
str |
Path to the output file. |
required |
Exceptions:
Type | Description |
---|---|
ImportError |
If the fiona or rasterio package is not installed. |
FileNotFoundError |
If the image is not found. |
ValueError |
If the mask is not a valid GeoJSON or raster file. |
FileNotFoundError |
If the mask file is not found. |
Source code in leafmap/common.py
def clip_image(image, mask, output):
"""Clip an image by mask.
Args:
image (str): Path to the image file in GeoTIFF format.
mask (str | list | dict): The mask used to extract the image. It can be a path to vector datasets (e.g., GeoJSON, Shapefile), a list of coordinates, or m.user_roi.
output (str): Path to the output file.
Raises:
ImportError: If the fiona or rasterio package is not installed.
FileNotFoundError: If the image is not found.
ValueError: If the mask is not a valid GeoJSON or raster file.
FileNotFoundError: If the mask file is not found.
"""
try:
import json
import fiona
import rasterio
import rasterio.mask
except ImportError as e:
raise ImportError(e)
if not os.path.exists(image):
raise FileNotFoundError(f"{image} does not exist.")
if not output.endswith(".tif"):
raise ValueError("Output must be a tif file.")
output = check_file_path(output)
if isinstance(mask, str):
if not os.path.exists(mask):
raise FileNotFoundError(f"{mask} does not exist.")
elif isinstance(mask, list) or isinstance(mask, dict):
if isinstance(mask, list):
geojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {"type": "Polygon", "coordinates": [mask]},
}
],
}
else:
geojson = {
"type": "FeatureCollection",
"features": [mask],
}
mask = temp_file_path(".geojson")
with open(mask, "w") as f:
json.dump(geojson, f)
with fiona.open(mask, "r") as shapefile:
shapes = [feature["geometry"] for feature in shapefile]
with rasterio.open(image) as src:
out_image, out_transform = rasterio.mask.mask(src, shapes, crop=True)
out_meta = src.meta
out_meta.update(
{
"driver": "GTiff",
"height": out_image.shape[1],
"width": out_image.shape[2],
"transform": out_transform,
}
)
with rasterio.open(output, "w", **out_meta) as dest:
dest.write(out_image)
cog_bands(url, titiler_endpoint='https://titiler.xyz')
¶
Get band names of a Cloud Optimized GeoTIFF (COG).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif |
required |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
Returns:
Type | Description |
---|---|
list |
A list of band names |
Source code in leafmap/common.py
def cog_bands(url, titiler_endpoint="https://titiler.xyz"):
"""Get band names of a Cloud Optimized GeoTIFF (COG).
Args:
url (str): HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
Returns:
list: A list of band names
"""
r = requests.get(
f"{titiler_endpoint}/cog/info",
params={
"url": url,
},
).json()
bands = [b[0] for b in r["band_descriptions"]]
return bands
cog_bounds(url, titiler_endpoint='https://titiler.xyz')
¶
Get the bounding box of a Cloud Optimized GeoTIFF (COG).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif |
required |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
Returns:
Type | Description |
---|---|
list |
A list of values representing [left, bottom, right, top] |
Source code in leafmap/common.py
def cog_bounds(url, titiler_endpoint="https://titiler.xyz"):
"""Get the bounding box of a Cloud Optimized GeoTIFF (COG).
Args:
url (str): HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
Returns:
list: A list of values representing [left, bottom, right, top]
"""
r = requests.get(f"{titiler_endpoint}/cog/bounds", params={"url": url}).json()
if "bounds" in r.keys():
bounds = r["bounds"]
else:
bounds = None
return bounds
cog_center(url, titiler_endpoint='https://titiler.xyz')
¶
Get the centroid of a Cloud Optimized GeoTIFF (COG).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif |
required |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
Returns:
Type | Description |
---|---|
tuple |
A tuple representing (longitude, latitude) |
Source code in leafmap/common.py
def cog_center(url, titiler_endpoint="https://titiler.xyz"):
"""Get the centroid of a Cloud Optimized GeoTIFF (COG).
Args:
url (str): HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
Returns:
tuple: A tuple representing (longitude, latitude)
"""
bounds = cog_bounds(url, titiler_endpoint)
center = ((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2) # (lat, lon)
return center
cog_info(url, titiler_endpoint='https://titiler.xyz', return_geojson=False)
¶
Get band statistics of a Cloud Optimized GeoTIFF (COG).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif |
required |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
Returns:
Type | Description |
---|---|
list |
A dictionary of band info. |
Source code in leafmap/common.py
def cog_info(url, titiler_endpoint="https://titiler.xyz", return_geojson=False):
"""Get band statistics of a Cloud Optimized GeoTIFF (COG).
Args:
url (str): HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
Returns:
list: A dictionary of band info.
"""
info = "info"
if return_geojson:
info = "info.geojson"
r = requests.get(
f"{titiler_endpoint}/cog/{info}",
params={
"url": url,
},
).json()
return r
cog_mosaic(links, titiler_endpoint='https://titiler.xyz', username='anonymous', layername=None, overwrite=False, verbose=True, **kwargs)
¶
Creates a COG mosaic from a list of COG URLs.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
links |
list |
A list containing COG HTTP URLs. |
required |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
username |
str |
User name for the titiler endpoint. Defaults to "anonymous". |
'anonymous' |
layername |
[type] |
Layer name to use. Defaults to None. |
None |
overwrite |
bool |
Whether to overwrite the layer name if existing. Defaults to False. |
False |
verbose |
bool |
Whether to print out descriptive information. Defaults to True. |
True |
Exceptions:
Type | Description |
---|---|
Exception |
If the COG mosaic fails to create. |
Returns:
Type | Description |
---|---|
str |
The tile URL for the COG mosaic. |
Source code in leafmap/common.py
def cog_mosaic(
links,
titiler_endpoint="https://titiler.xyz",
username="anonymous",
layername=None,
overwrite=False,
verbose=True,
**kwargs,
):
"""Creates a COG mosaic from a list of COG URLs.
Args:
links (list): A list containing COG HTTP URLs.
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
username (str, optional): User name for the titiler endpoint. Defaults to "anonymous".
layername ([type], optional): Layer name to use. Defaults to None.
overwrite (bool, optional): Whether to overwrite the layer name if existing. Defaults to False.
verbose (bool, optional): Whether to print out descriptive information. Defaults to True.
Raises:
Exception: If the COG mosaic fails to create.
Returns:
str: The tile URL for the COG mosaic.
"""
if layername is None:
layername = "layer_" + random_string(5)
try:
if verbose:
print("Creating COG masaic ...")
# Create token
r = requests.post(
f"{titiler_endpoint}/tokens/create",
json={"username": username, "scope": ["mosaic:read", "mosaic:create"]},
).json()
token = r["token"]
# Create mosaic
requests.post(
f"{titiler_endpoint}/mosaicjson/create",
json={
"username": username,
"layername": layername,
"files": links,
# "overwrite": overwrite
},
params={
"access_token": token,
},
).json()
r2 = requests.get(
f"{titiler_endpoint}/mosaicjson/{username}.{layername}/tilejson.json",
).json()
return r2["tiles"][0]
except Exception as e:
raise Exception(e)
cog_mosaic_from_file(filepath, skip_rows=0, titiler_endpoint='https://titiler.xyz', username='anonymous', layername=None, overwrite=False, verbose=True, **kwargs)
¶
Creates a COG mosaic from a csv/txt file stored locally for through HTTP URL.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filepath |
str |
Local path or HTTP URL to the csv/txt file containing COG URLs. |
required |
skip_rows |
int |
The number of rows to skip in the file. Defaults to 0. |
0 |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
username |
str |
User name for the titiler endpoint. Defaults to "anonymous". |
'anonymous' |
layername |
[type] |
Layer name to use. Defaults to None. |
None |
overwrite |
bool |
Whether to overwrite the layer name if existing. Defaults to False. |
False |
verbose |
bool |
Whether to print out descriptive information. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
str |
The tile URL for the COG mosaic. |
Source code in leafmap/common.py
def cog_mosaic_from_file(
filepath,
skip_rows=0,
titiler_endpoint="https://titiler.xyz",
username="anonymous",
layername=None,
overwrite=False,
verbose=True,
**kwargs,
):
"""Creates a COG mosaic from a csv/txt file stored locally for through HTTP URL.
Args:
filepath (str): Local path or HTTP URL to the csv/txt file containing COG URLs.
skip_rows (int, optional): The number of rows to skip in the file. Defaults to 0.
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
username (str, optional): User name for the titiler endpoint. Defaults to "anonymous".
layername ([type], optional): Layer name to use. Defaults to None.
overwrite (bool, optional): Whether to overwrite the layer name if existing. Defaults to False.
verbose (bool, optional): Whether to print out descriptive information. Defaults to True.
Returns:
str: The tile URL for the COG mosaic.
"""
import urllib
links = []
if filepath.startswith("http"):
data = urllib.request.urlopen(filepath)
for line in data:
links.append(line.decode("utf-8").strip())
else:
with open(filepath) as f:
links = [line.strip() for line in f.readlines()]
links = links[skip_rows:]
# print(links)
mosaic = cog_mosaic(
links, titiler_endpoint, username, layername, overwrite, verbose, **kwargs
)
return mosaic
cog_pixel_value(lon, lat, url, bidx=None, titiler_endpoint='https://titiler.xyz', verbose=True, **kwargs)
¶
Get pixel value from COG.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lon |
float |
Longitude of the pixel. |
required |
lat |
float |
Latitude of the pixel. |
required |
url |
str |
HTTP URL to a COG, e.g., 'https://opendata.digitalglobe.com/events/california-fire-2020/pre-event/2018-02-16/pine-gulch-fire20/1030010076004E00.tif' |
required |
bidx |
str |
Dataset band indexes (e.g bidx=1, bidx=1&bidx=2&bidx=3). Defaults to None. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
'https://titiler.xyz' |
verbose |
bool |
Print status messages. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
list |
A dictionary of band info. |
Source code in leafmap/common.py
def cog_pixel_value(
lon,
lat,
url,
bidx=None,
titiler_endpoint="https://titiler.xyz",
verbose=True,
**kwargs,
):
"""Get pixel value from COG.
Args:
lon (float): Longitude of the pixel.
lat (float): Latitude of the pixel.
url (str): HTTP URL to a COG, e.g., 'https://opendata.digitalglobe.com/events/california-fire-2020/pre-event/2018-02-16/pine-gulch-fire20/1030010076004E00.tif'
bidx (str, optional): Dataset band indexes (e.g bidx=1, bidx=1&bidx=2&bidx=3). Defaults to None.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
verbose (bool, optional): Print status messages. Defaults to True.
Returns:
list: A dictionary of band info.
"""
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
kwargs["url"] = url
if bidx is not None:
kwargs["bidx"] = bidx
r = requests.get(f"{titiler_endpoint}/cog/point/{lon},{lat}", params=kwargs).json()
bands = cog_bands(url, titiler_endpoint)
# if isinstance(titiler_endpoint, str):
# r = requests.get(f"{titiler_endpoint}/cog/point/{lon},{lat}", params=kwargs).json()
# else:
# r = requests.get(
# titiler_endpoint.url_for_stac_pixel_value(lon, lat), params=kwargs
# ).json()
if "detail" in r:
if verbose:
print(r["detail"])
return None
else:
values = r["values"]
result = dict(zip(bands, values))
return result
cog_stats(url, titiler_endpoint='https://titiler.xyz')
¶
Get band statistics of a Cloud Optimized GeoTIFF (COG).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif |
required |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
Returns:
Type | Description |
---|---|
list |
A dictionary of band statistics. |
Source code in leafmap/common.py
def cog_stats(url, titiler_endpoint="https://titiler.xyz"):
"""Get band statistics of a Cloud Optimized GeoTIFF (COG).
Args:
url (str): HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
Returns:
list: A dictionary of band statistics.
"""
r = requests.get(
f"{titiler_endpoint}/cog/statistics",
params={
"url": url,
},
).json()
return r
cog_tile(url, bands=None, titiler_endpoint='https://titiler.xyz', **kwargs)
¶
Get a tile layer from a Cloud Optimized GeoTIFF (COG). Source code adapted from https://developmentseed.org/titiler/examples/notebooks/Working_with_CloudOptimizedGeoTIFF_simple/
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif |
required |
bands |
list |
List of bands to use. Defaults to None. |
None |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
Returns:
Type | Description |
---|---|
tuple |
Returns the COG Tile layer URL and bounds. |
Source code in leafmap/common.py
def cog_tile(url, bands=None, titiler_endpoint="https://titiler.xyz", **kwargs):
"""Get a tile layer from a Cloud Optimized GeoTIFF (COG).
Source code adapted from https://developmentseed.org/titiler/examples/notebooks/Working_with_CloudOptimizedGeoTIFF_simple/
Args:
url (str): HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif
bands (list, optional): List of bands to use. Defaults to None.
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
Returns:
tuple: Returns the COG Tile layer URL and bounds.
"""
kwargs["url"] = url
band_names = cog_bands(url, titiler_endpoint)
if isinstance(bands, str):
bands = [bands]
if bands is None and "bidx" not in kwargs:
if len(band_names) >= 3:
kwargs["bidx"] = [1, 2, 3]
elif isinstance(bands, list) and "bidx" not in kwargs:
if all(isinstance(x, int) for x in bands):
if len(set(bands)) == 1:
bands = bands[0]
kwargs["bidx"] = bands
elif all(isinstance(x, str) for x in bands):
if len(set(bands)) == 1:
bands = bands[0]
kwargs["bidx"] = [band_names.index(x) + 1 for x in bands]
else:
raise ValueError("Bands must be a list of integers or strings.")
if "palette" in kwargs:
kwargs["colormap_name"] = kwargs["palette"].lower()
del kwargs["palette"]
if "rescale" not in kwargs:
stats = cog_stats(url, titiler_endpoint)
if "message" not in stats:
percentile_2 = min([stats[s]["percentile_2"] for s in stats])
percentile_98 = max([stats[s]["percentile_98"] for s in stats])
kwargs["rescale"] = f"{percentile_2},{percentile_98}"
TileMatrixSetId = "WebMercatorQuad"
if "TileMatrixSetId" in kwargs.keys():
TileMatrixSetId = kwargs["TileMatrixSetId"]
kwargs.pop("TileMatrixSetId")
r = requests.get(
f"{titiler_endpoint}/cog/{TileMatrixSetId}/tilejson.json", params=kwargs
).json()
return r["tiles"][0]
cog_tile_vmin_vmax(url, bands=None, titiler_endpoint='https://titiler.xyz', percentile=True, **kwargs)
¶
Get a tile layer from a Cloud Optimized GeoTIFF (COG) and return the minimum and maximum values.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif |
required |
bands |
list |
List of bands to use. Defaults to None. |
None |
titiler_endpoint |
str |
Titiler endpoint. Defaults to "https://titiler.xyz". |
'https://titiler.xyz' |
percentile |
bool |
Whether to use percentiles or not. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
tuple |
Returns the minimum and maximum values. |
Source code in leafmap/common.py
def cog_tile_vmin_vmax(
url, bands=None, titiler_endpoint="https://titiler.xyz", percentile=True, **kwargs
):
"""Get a tile layer from a Cloud Optimized GeoTIFF (COG) and return the minimum and maximum values.
Args:
url (str): HTTP URL to a COG, e.g., https://opendata.digitalglobe.com/events/mauritius-oil-spill/post-event/2020-08-12/105001001F1B5B00/105001001F1B5B00.tif
bands (list, optional): List of bands to use. Defaults to None.
titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://titiler.xyz".
percentile (bool, optional): Whether to use percentiles or not. Defaults to True.
Returns:
tuple: Returns the minimum and maximum values.
"""
stats = cog_stats(url, titiler_endpoint)
if isinstance(bands, str):
bands = [bands]
if bands is not None:
stats = {s: stats[s] for s in stats if s in bands}
if percentile:
vmin = min([stats[s]["percentile_2"] for s in stats])
vmax = max([stats[s]["percentile_98"] for s in stats])
else:
vmin = min([stats[s]["min"] for s in stats])
vmax = max([stats[s]["max"] for s in stats])
return vmin, vmax
cog_validate(source, verbose=False)
¶
Validate Cloud Optimized Geotiff.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
source |
str |
A dataset path or URL. Will be opened in "r" mode. |
required |
verbose |
bool |
Whether to print the output of the validation. Defaults to False. |
False |
Exceptions:
Type | Description |
---|---|
ImportError |
If the rio-cogeo package is not installed. |
FileNotFoundError |
If the provided file could not be found. |
Returns:
Type | Description |
---|---|
tuple |
A tuple containing the validation results (True is src_path is a valid COG, List of validation errors, and a list of validation warnings). |
Source code in leafmap/common.py
def cog_validate(source, verbose=False):
"""Validate Cloud Optimized Geotiff.
Args:
source (str): A dataset path or URL. Will be opened in "r" mode.
verbose (bool, optional): Whether to print the output of the validation. Defaults to False.
Raises:
ImportError: If the rio-cogeo package is not installed.
FileNotFoundError: If the provided file could not be found.
Returns:
tuple: A tuple containing the validation results (True is src_path is a valid COG, List of validation errors, and a list of validation warnings).
"""
try:
from rio_cogeo.cogeo import cog_validate, cog_info
except ImportError:
raise ImportError(
"The rio-cogeo package is not installed. Please install it with `pip install rio-cogeo` or `conda install rio-cogeo -c conda-forge`."
)
if not source.startswith("http"):
source = check_file_path(source)
if not os.path.exists(source):
raise FileNotFoundError("The provided input file could not be found.")
if verbose:
return cog_info(source)
else:
return cog_validate(source)
connect_postgis(database, host='localhost', user=None, password=None, port=5432, use_env_var=False)
¶
Connects to a PostGIS database.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
database |
str |
Name of the database |
required |
host |
str |
Hosting server for the database. Defaults to "localhost". |
'localhost' |
user |
str |
User name to access the database. Defaults to None. |
None |
password |
str |
Password to access the database. Defaults to None. |
None |
port |
int |
Port number to connect to at the server host. Defaults to 5432. |
5432 |
use_env_var |
bool |
Whether to use environment variables. It set to True, user and password are treated as an environment variables with default values user="SQL_USER" and password="SQL_PASSWORD". Defaults to False. |
False |
Exceptions:
Type | Description |
---|---|
ValueError |
If user is not specified. |
ValueError |
If password is not specified. |
Returns:
Type | Description |
---|---|
[type] |
[description] |
Source code in leafmap/common.py
def connect_postgis(
database, host="localhost", user=None, password=None, port=5432, use_env_var=False
):
"""Connects to a PostGIS database.
Args:
database (str): Name of the database
host (str, optional): Hosting server for the database. Defaults to "localhost".
user (str, optional): User name to access the database. Defaults to None.
password (str, optional): Password to access the database. Defaults to None.
port (int, optional): Port number to connect to at the server host. Defaults to 5432.
use_env_var (bool, optional): Whether to use environment variables. It set to True, user and password are treated as an environment variables with default values user="SQL_USER" and password="SQL_PASSWORD". Defaults to False.
Raises:
ValueError: If user is not specified.
ValueError: If password is not specified.
Returns:
[type]: [description]
"""
check_package(name="geopandas", URL="https://geopandas.org")
check_package(
name="sqlalchemy",
URL="https://docs.sqlalchemy.org/en/14/intro.html#installation",
)
from sqlalchemy import create_engine
if use_env_var:
if user is not None:
user = os.getenv(user)
else:
user = os.getenv("SQL_USER")
if password is not None:
password = os.getenv(password)
else:
password = os.getenv("SQL_PASSWORD")
if user is None:
raise ValueError("user is not specified.")
if password is None:
raise ValueError("password is not specified.")
connection_string = f"postgresql://{user}:{password}@{host}:{port}/{database}"
engine = create_engine(connection_string)
return engine
coords_to_geojson(coords)
¶
Convert a list of bbox coordinates representing [left, bottom, right, top] to geojson FeatureCollection.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
coords |
list |
A list of bbox coordinates representing [left, bottom, right, top]. |
required |
Returns:
Type | Description |
---|---|
dict |
A geojson FeatureCollection. |
Source code in leafmap/common.py
def coords_to_geojson(coords):
"""Convert a list of bbox coordinates representing [left, bottom, right, top] to geojson FeatureCollection.
Args:
coords (list): A list of bbox coordinates representing [left, bottom, right, top].
Returns:
dict: A geojson FeatureCollection.
"""
features = []
for bbox in coords:
features.append(bbox_to_geojson(bbox))
return {"type": "FeatureCollection", "features": features}
create_code_cell(code='', where='below')
¶
Creates a code cell in the IPython Notebook.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
code |
str |
Code to fill the new code cell with. Defaults to ''. |
'' |
where |
str |
Where to add the new code cell. It can be one of the following: above, below, at_bottom. Defaults to 'below'. |
'below' |
Source code in leafmap/common.py
def create_code_cell(code="", where="below"):
"""Creates a code cell in the IPython Notebook.
Args:
code (str, optional): Code to fill the new code cell with. Defaults to ''.
where (str, optional): Where to add the new code cell. It can be one of the following: above, below, at_bottom. Defaults to 'below'.
"""
import base64
from IPython.display import Javascript, display
encoded_code = (base64.b64encode(str.encode(code))).decode()
display(
Javascript(
"""
var code = IPython.notebook.insert_cell_{0}('code');
code.set_text(atob("{1}"));
""".format(
where, encoded_code
)
)
)
create_download_link(filename, title='Click here to download: ')
¶
Downloads a file from voila. Adopted from https://github.com/voila-dashboards/voila/issues/578
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filename |
str |
The file path to the file to download |
required |
title |
str |
str. Defaults to "Click here to download: ". |
'Click here to download: ' |
Returns:
Type | Description |
---|---|
str |
HTML download URL. |
Source code in leafmap/common.py
def create_download_link(filename, title="Click here to download: "):
"""Downloads a file from voila. Adopted from https://github.com/voila-dashboards/voila/issues/578
Args:
filename (str): The file path to the file to download
title (str, optional): str. Defaults to "Click here to download: ".
Returns:
str: HTML download URL.
"""
import base64
from IPython.display import HTML
data = open(filename, "rb").read()
b64 = base64.b64encode(data)
payload = b64.decode()
basename = os.path.basename(filename)
html = '<a download="{filename}" href="data:text/csv;base64,{payload}" style="color:#0000FF;" target="_blank">{title}</a>'
html = html.format(payload=payload, title=title + f" {basename}", filename=basename)
return HTML(html)
create_legend(legend_title='Legend', legend_dict=None, legend_keys=None, legend_colors=None, builtin_legend=None, **kwargs)
¶
Create a custom legend.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
legend_title |
str |
Title of the legend. Defaults to 'Legend'. |
'Legend' |
legend_dict |
dict |
A dictionary containing legend items as keys and color as values. If provided, legend_keys and legend_colors will be ignored. Defaults to None. |
None |
legend_keys |
list |
A list of legend keys. Defaults to None. |
None |
legend_colors |
list |
A list of legend colors. Defaults to None. |
None |
builtin_legend |
str |
Name of the builtin legend to add to the map. Defaults to None. |
None |
Source code in leafmap/common.py
def create_legend(
legend_title="Legend",
legend_dict=None,
legend_keys=None,
legend_colors=None,
builtin_legend=None,
**kwargs,
):
"""Create a custom legend.
Args:
legend_title (str, optional): Title of the legend. Defaults to 'Legend'.
legend_dict (dict, optional): A dictionary containing legend items as keys and color as values. If provided, legend_keys and legend_colors will be ignored. Defaults to None.
legend_keys (list, optional): A list of legend keys. Defaults to None.
legend_colors (list, optional): A list of legend colors. Defaults to None.
builtin_legend (str, optional): Name of the builtin legend to add to the map. Defaults to None.
"""
import pkg_resources
from .legends import builtin_legends
pkg_dir = os.path.dirname(pkg_resources.resource_filename("leafmap", "leafmap.py"))
legend_template = os.path.join(pkg_dir, "data/template/legend.html")
# if "min_width" not in kwargs.keys():
# min_width = None
# if "max_width" not in kwargs.keys():
# max_width = None
# else:
# max_width = kwargs["max_width"]
# if "min_height" not in kwargs.keys():
# min_height = None
# else:
# min_height = kwargs["min_height"]
# if "max_height" not in kwargs.keys():
# max_height = None
# else:
# max_height = kwargs["max_height"]
# if "height" not in kwargs.keys():
# height = None
# else:
# height = kwargs["height"]
# if "width" not in kwargs.keys():
# width = None
# else:
# width = kwargs["width"]
# if width is None:
# max_width = "300px"
# if height is None:
# max_height = "400px"
if not os.path.exists(legend_template):
print("The legend template does not exist.")
return
if legend_keys is not None:
if not isinstance(legend_keys, list):
print("The legend keys must be a list.")
return
else:
legend_keys = ["One", "Two", "Three", "Four", "etc"]
if legend_colors is not None:
if not isinstance(legend_colors, list):
print("The legend colors must be a list.")
return
elif all(isinstance(item, tuple) for item in legend_colors):
try:
legend_colors = [rgb_to_hex(x) for x in legend_colors]
except Exception as e:
print(e)
elif all((item.startswith("#") and len(item) == 7) for item in legend_colors):
pass
elif all((len(item) == 6) for item in legend_colors):
pass
else:
print("The legend colors must be a list of tuples.")
return
else:
legend_colors = [
"#8DD3C7",
"#FFFFB3",
"#BEBADA",
"#FB8072",
"#80B1D3",
]
if len(legend_keys) != len(legend_colors):
print("The legend keys and values must be the same length.")
return
allowed_builtin_legends = builtin_legends.keys()
if builtin_legend is not None:
if builtin_legend not in allowed_builtin_legends:
print(
"The builtin legend must be one of the following: {}".format(
", ".join(allowed_builtin_legends)
)
)
return
else:
legend_dict = builtin_legends[builtin_legend]
legend_keys = list(legend_dict.keys())
legend_colors = list(legend_dict.values())
if legend_dict is not None:
if not isinstance(legend_dict, dict):
print("The legend dict must be a dictionary.")
return
else:
legend_keys = list(legend_dict.keys())
legend_colors = list(legend_dict.values())
if all(isinstance(item, tuple) for item in legend_colors):
try:
legend_colors = [rgb_to_hex(x) for x in legend_colors]
except Exception as e:
print(e)
header = []
content = []
footer = []
with open(legend_template) as f:
lines = f.readlines()
lines[3] = lines[3].replace("Legend", legend_title)
header = lines[:6]
footer = lines[11:]
for index, key in enumerate(legend_keys):
color = legend_colors[index]
if not color.startswith("#"):
color = "#" + color
item = " <li><span style='background:{};'></span>{}</li>\n".format(
color, key
)
content.append(item)
legend_html = header + content + footer
legend_text = "".join(legend_html)
return legend_text
csv_points_to_shp(in_csv, out_shp, latitude='latitude', longitude='longitude')
¶
Converts a csv file containing points (latitude, longitude) into a shapefile.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_csv |
str |
File path or HTTP URL to the input csv file. For example, https://raw.githubusercontent.com/giswqs/data/main/world/world_cities.csv |
required |
out_shp |
str |
File path to the output shapefile. |
required |
latitude |
str |
Column name for the latitude column. Defaults to 'latitude'. |
'latitude' |
longitude |
str |
Column name for the longitude column. Defaults to 'longitude'. |
'longitude' |
Source code in leafmap/common.py
def csv_points_to_shp(in_csv, out_shp, latitude="latitude", longitude="longitude"):
"""Converts a csv file containing points (latitude, longitude) into a shapefile.
Args:
in_csv (str): File path or HTTP URL to the input csv file. For example, https://raw.githubusercontent.com/giswqs/data/main/world/world_cities.csv
out_shp (str): File path to the output shapefile.
latitude (str, optional): Column name for the latitude column. Defaults to 'latitude'.
longitude (str, optional): Column name for the longitude column. Defaults to 'longitude'.
"""
if in_csv.startswith("http") and in_csv.endswith(".csv"):
out_dir = os.path.join(os.path.expanduser("~"), "Downloads")
out_name = os.path.basename(in_csv)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
download_from_url(in_csv, out_dir=out_dir)
in_csv = os.path.join(out_dir, out_name)
wbt = whitebox.WhiteboxTools()
in_csv = os.path.abspath(in_csv)
out_shp = os.path.abspath(out_shp)
if not os.path.exists(in_csv):
raise Exception("The provided csv file does not exist.")
with open(in_csv, encoding="utf-8") as csv_file:
reader = csv.DictReader(csv_file)
fields = reader.fieldnames
xfield = fields.index(longitude)
yfield = fields.index(latitude)
wbt.csv_points_to_vector(in_csv, out_shp, xfield=xfield, yfield=yfield, epsg=4326)
csv_to_gdf(in_csv, latitude='latitude', longitude='longitude', encoding='utf-8')
¶
Creates points for a CSV file and converts them to a GeoDataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_csv |
str |
The file path to the input CSV file. |
required |
latitude |
str |
The name of the column containing latitude coordinates. Defaults to "latitude". |
'latitude' |
longitude |
str |
The name of the column containing longitude coordinates. Defaults to "longitude". |
'longitude' |
encoding |
str |
The encoding of characters. Defaults to "utf-8". |
'utf-8' |
Returns:
Type | Description |
---|---|
object |
GeoDataFrame. |
Source code in leafmap/common.py
def csv_to_gdf(in_csv, latitude="latitude", longitude="longitude", encoding="utf-8"):
"""Creates points for a CSV file and converts them to a GeoDataFrame.
Args:
in_csv (str): The file path to the input CSV file.
latitude (str, optional): The name of the column containing latitude coordinates. Defaults to "latitude".
longitude (str, optional): The name of the column containing longitude coordinates. Defaults to "longitude".
encoding (str, optional): The encoding of characters. Defaults to "utf-8".
Returns:
object: GeoDataFrame.
"""
check_package(name="geopandas", URL="https://geopandas.org")
import geopandas as gpd
out_dir = os.getcwd()
out_geojson = os.path.join(out_dir, random_string() + ".geojson")
csv_to_geojson(in_csv, out_geojson, latitude, longitude, encoding)
gdf = gpd.read_file(out_geojson)
os.remove(out_geojson)
return gdf
csv_to_geojson(in_csv, out_geojson=None, latitude='latitude', longitude='longitude', encoding='utf-8')
¶
Creates points for a CSV file and exports data as a GeoJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_csv |
str |
The file path to the input CSV file. |
required |
out_geojson |
str |
The file path to the exported GeoJSON. Default to None. |
None |
latitude |
str |
The name of the column containing latitude coordinates. Defaults to "latitude". |
'latitude' |
longitude |
str |
The name of the column containing longitude coordinates. Defaults to "longitude". |
'longitude' |
encoding |
str |
The encoding of characters. Defaults to "utf-8". |
'utf-8' |
Source code in leafmap/common.py
def csv_to_geojson(
in_csv,
out_geojson=None,
latitude="latitude",
longitude="longitude",
encoding="utf-8",
):
"""Creates points for a CSV file and exports data as a GeoJSON.
Args:
in_csv (str): The file path to the input CSV file.
out_geojson (str): The file path to the exported GeoJSON. Default to None.
latitude (str, optional): The name of the column containing latitude coordinates. Defaults to "latitude".
longitude (str, optional): The name of the column containing longitude coordinates. Defaults to "longitude".
encoding (str, optional): The encoding of characters. Defaults to "utf-8".
"""
import json
import pandas as pd
if out_geojson is not None:
out_dir = os.path.dirname(os.path.abspath(out_geojson))
if not os.path.exists(out_dir):
os.makedirs(out_dir)
df = pd.read_csv(in_csv)
geojson = pandas_to_geojson(
df, latitude=latitude, longitude=longitude, encoding=encoding
)
if out_geojson is None:
return geojson
else:
with open(out_geojson, "w", encoding=encoding) as f:
f.write(json.dumps(geojson))
csv_to_pandas(in_csv, **kwargs)
¶
Converts a CSV file to pandas dataframe.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_csv |
str |
File path to the input CSV. |
required |
Returns:
Type | Description |
---|---|
pd.DataFrame |
pandas DataFrame |
Source code in leafmap/common.py
def csv_to_pandas(in_csv, **kwargs):
"""Converts a CSV file to pandas dataframe.
Args:
in_csv (str): File path to the input CSV.
Returns:
pd.DataFrame: pandas DataFrame
"""
import pandas as pd
try:
return pd.read_csv(in_csv, **kwargs)
except Exception as e:
raise Exception(e)
csv_to_shp(in_csv, out_shp, latitude='latitude', longitude='longitude')
¶
Converts a csv file with latlon info to a point shapefile.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_csv |
str |
The input csv file containing longitude and latitude columns. |
required |
out_shp |
str |
The file path to the output shapefile. |
required |
latitude |
str |
The column name of the latitude column. Defaults to 'latitude'. |
'latitude' |
longitude |
str |
The column name of the longitude column. Defaults to 'longitude'. |
'longitude' |
Source code in leafmap/common.py
def csv_to_shp(in_csv, out_shp, latitude="latitude", longitude="longitude"):
"""Converts a csv file with latlon info to a point shapefile.
Args:
in_csv (str): The input csv file containing longitude and latitude columns.
out_shp (str): The file path to the output shapefile.
latitude (str, optional): The column name of the latitude column. Defaults to 'latitude'.
longitude (str, optional): The column name of the longitude column. Defaults to 'longitude'.
"""
import shapefile as shp
if in_csv.startswith("http") and in_csv.endswith(".csv"):
out_dir = os.path.join(os.path.expanduser("~"), "Downloads")
out_name = os.path.basename(in_csv)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
download_from_url(in_csv, out_dir=out_dir)
in_csv = os.path.join(out_dir, out_name)
out_dir = os.path.dirname(out_shp)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
try:
points = shp.Writer(out_shp, shapeType=shp.POINT)
with open(in_csv, encoding="utf-8") as csvfile:
csvreader = csv.DictReader(csvfile)
header = csvreader.fieldnames
[points.field(field) for field in header]
for row in csvreader:
points.point((float(row[longitude])), (float(row[latitude])))
points.record(*tuple([row[f] for f in header]))
out_prj = out_shp.replace(".shp", ".prj")
with open(out_prj, "w") as f:
prj_str = 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.0174532925199433]] '
f.write(prj_str)
except Exception as e:
raise Exception(e)
delete_shp(in_shp, verbose=False)
¶
Deletes a shapefile.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_shp |
str |
The input shapefile to delete. |
required |
verbose |
bool |
Whether to print out descriptive text. Defaults to True. |
False |
Source code in leafmap/common.py
def delete_shp(in_shp, verbose=False):
"""Deletes a shapefile.
Args:
in_shp (str): The input shapefile to delete.
verbose (bool, optional): Whether to print out descriptive text. Defaults to True.
"""
from pathlib import Path
in_shp = os.path.abspath(in_shp)
in_dir = os.path.dirname(in_shp)
basename = os.path.basename(in_shp).replace(".shp", "")
files = Path(in_dir).rglob(basename + ".*")
for file in files:
filepath = os.path.join(in_dir, str(file))
os.remove(filepath)
if verbose:
print(f"Deleted {filepath}")
dict_to_json(data, file_path, indent=4)
¶
Writes a dictionary to a JSON file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
dict |
A dictionary. |
required |
file_path |
str |
The path to the JSON file. |
required |
indent |
int |
The indentation of the JSON file. Defaults to 4. |
4 |
Exceptions:
Type | Description |
---|---|
TypeError |
If the input data is not a dictionary. |
Source code in leafmap/common.py
def dict_to_json(data, file_path, indent=4):
"""Writes a dictionary to a JSON file.
Args:
data (dict): A dictionary.
file_path (str): The path to the JSON file.
indent (int, optional): The indentation of the JSON file. Defaults to 4.
Raises:
TypeError: If the input data is not a dictionary.
"""
import json
file_path = check_file_path(file_path)
if isinstance(data, dict):
with open(file_path, "w") as f:
json.dump(data, f, indent=indent)
else:
raise TypeError("The provided data must be a dictionary.")
display_html(src, width=950, height=600)
¶
Display an HTML file in a Jupyter Notebook.
Args src (str): File path to HTML file. width (int, optional): Width of the map. Defaults to 950. height (int, optional): Height of the map. Defaults to 600.
Source code in leafmap/common.py
def display_html(src, width=950, height=600):
"""Display an HTML file in a Jupyter Notebook.
Args
src (str): File path to HTML file.
width (int, optional): Width of the map. Defaults to 950.
height (int, optional): Height of the map. Defaults to 600.
"""
if not os.path.isfile(src):
raise ValueError(f"{src} is not a valid file path.")
display(IFrame(src=src, width=width, height=height))
download_file(url=None, output=None, quiet=False, proxy=None, speed=None, use_cookies=True, verify=True, id=None, fuzzy=False, resume=False, unzip=True)
¶
Download a file from URL, including Google Drive shared URL.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
Google Drive URL is also supported. Defaults to None. |
None |
output |
str |
Output filename. Default is basename of URL. |
None |
quiet |
bool |
Suppress terminal output. Default is False. |
False |
proxy |
str |
Proxy. Defaults to None. |
None |
speed |
float |
Download byte size per second (e.g., 256KB/s = 256 * 1024). Defaults to None. |
None |
use_cookies |
bool |
Flag to use cookies. Defaults to True. |
True |
verify |
bool | str |
Either a bool, in which case it controls whether the server's TLS certificate is verified, or a string, in which case it must be a path to a CA bundle to use. Default is True.. Defaults to True. |
True |
id |
str |
Google Drive's file ID. Defaults to None. |
None |
fuzzy |
bool |
Fuzzy extraction of Google Drive's file Id. Defaults to False. |
False |
resume |
bool |
Resume the download from existing tmp file if possible. Defaults to False. |
False |
unzip |
bool |
Unzip the file. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
str |
The output file path. |
Source code in leafmap/common.py
def download_file(
url=None,
output=None,
quiet=False,
proxy=None,
speed=None,
use_cookies=True,
verify=True,
id=None,
fuzzy=False,
resume=False,
unzip=True,
):
"""Download a file from URL, including Google Drive shared URL.
Args:
url (str, optional): Google Drive URL is also supported. Defaults to None.
output (str, optional): Output filename. Default is basename of URL.
quiet (bool, optional): Suppress terminal output. Default is False.
proxy (str, optional): Proxy. Defaults to None.
speed (float, optional): Download byte size per second (e.g., 256KB/s = 256 * 1024). Defaults to None.
use_cookies (bool, optional): Flag to use cookies. Defaults to True.
verify (bool | str, optional): Either a bool, in which case it controls whether the server's TLS certificate is verified, or a string, in which case it must be a path to a CA bundle to use. Default is True.. Defaults to True.
id (str, optional): Google Drive's file ID. Defaults to None.
fuzzy (bool, optional): Fuzzy extraction of Google Drive's file Id. Defaults to False.
resume (bool, optional): Resume the download from existing tmp file if possible. Defaults to False.
unzip (bool, optional): Unzip the file. Defaults to True.
Returns:
str: The output file path.
"""
import gdown
if "https://drive.google.com/file/d/" in url:
fuzzy = True
output = gdown.download(
url, output, quiet, proxy, speed, use_cookies, verify, id, fuzzy, resume
)
if unzip and output.endswith(".zip"):
with zipfile.ZipFile(output, "r") as zip_ref:
if not quiet:
print("Extracting files...")
zip_ref.extractall(os.path.dirname(output))
return os.path.abspath(output)
download_folder(url=None, id=None, output=None, quiet=False, proxy=None, speed=None, use_cookies=True, remaining_ok=False)
¶
Downloads the entire folder from URL.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
URL of the Google Drive folder. Must be of the format 'https://drive.google.com/drive/folders/{url}'. Defaults to None. |
None |
id |
str |
Google Drive's folder ID. Defaults to None. |
None |
output |
str |
String containing the path of the output folder. Defaults to current working directory. |
None |
quiet |
bool |
Suppress terminal output. Defaults to False. |
False |
proxy |
str |
Proxy. Defaults to None. |
None |
speed |
float |
Download byte size per second (e.g., 256KB/s = 256 * 1024). Defaults to None. |
None |
use_cookies |
bool |
Flag to use cookies. Defaults to True. |
True |
resume |
bool |
Resume the download from existing tmp file if possible. Defaults to False. |
required |
Returns:
Type | Description |
---|---|
list |
List of files downloaded, or None if failed. |
Source code in leafmap/common.py
def download_folder(
url=None,
id=None,
output=None,
quiet=False,
proxy=None,
speed=None,
use_cookies=True,
remaining_ok=False,
):
"""Downloads the entire folder from URL.
Args:
url (str, optional): URL of the Google Drive folder. Must be of the format 'https://drive.google.com/drive/folders/{url}'. Defaults to None.
id (str, optional): Google Drive's folder ID. Defaults to None.
output (str, optional): String containing the path of the output folder. Defaults to current working directory.
quiet (bool, optional): Suppress terminal output. Defaults to False.
proxy (str, optional): Proxy. Defaults to None.
speed (float, optional): Download byte size per second (e.g., 256KB/s = 256 * 1024). Defaults to None.
use_cookies (bool, optional): Flag to use cookies. Defaults to True.
resume (bool, optional): Resume the download from existing tmp file if possible. Defaults to False.
Returns:
list: List of files downloaded, or None if failed.
"""
import gdown
files = gdown.download_folder(
url, id, output, quiet, proxy, speed, use_cookies, remaining_ok
)
return files
download_from_gdrive(gfile_url, file_name, out_dir='.', unzip=True, verbose=True)
¶
Download a file shared via Google Drive (e.g., https://drive.google.com/file/d/18SUo_HcDGltuWYZs1s7PpOmOq_FvFn04/view?usp=sharing)
Parameters:
Name | Type | Description | Default |
---|---|---|---|
gfile_url |
str |
The Google Drive shared file URL |
required |
file_name |
str |
The output file name to use. |
required |
out_dir |
str |
The output directory. Defaults to '.'. |
'.' |
unzip |
bool |
Whether to unzip the output file if it is a zip file. Defaults to True. |
True |
verbose |
bool |
Whether to display or not the output of the function |
True |
Source code in leafmap/common.py
def download_from_gdrive(gfile_url, file_name, out_dir=".", unzip=True, verbose=True):
"""Download a file shared via Google Drive
(e.g., https://drive.google.com/file/d/18SUo_HcDGltuWYZs1s7PpOmOq_FvFn04/view?usp=sharing)
Args:
gfile_url (str): The Google Drive shared file URL
file_name (str): The output file name to use.
out_dir (str, optional): The output directory. Defaults to '.'.
unzip (bool, optional): Whether to unzip the output file if it is a zip file. Defaults to True.
verbose (bool, optional): Whether to display or not the output of the function
"""
try:
from google_drive_downloader import GoogleDriveDownloader as gdd
except ImportError:
raise ImportError(
'Please install googledrivedownloader using "pip install googledrivedownloader"'
)
file_id = gfile_url.split("/")[5]
if verbose:
print("Google Drive file id: {}".format(file_id))
out_dir = check_dir(out_dir)
dest_path = os.path.join(out_dir, file_name)
gdd.download_file_from_google_drive(file_id, dest_path, True, unzip)
download_from_url(url, out_file_name=None, out_dir='.', unzip=True, verbose=True)
¶
Download a file from a URL (e.g., https://github.com/giswqs/whitebox-python/raw/master/examples/testdata.zip)
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
The HTTP URL to download. |
required |
out_file_name |
str |
The output file name to use. Defaults to None. |
None |
out_dir |
str |
The output directory to use. Defaults to '.'. |
'.' |
unzip |
bool |
Whether to unzip the downloaded file if it is a zip file. Defaults to True. |
True |
verbose |
bool |
Whether to display or not the output of the function |
True |
Source code in leafmap/common.py
def download_from_url(url, out_file_name=None, out_dir=".", unzip=True, verbose=True):
"""Download a file from a URL (e.g., https://github.com/giswqs/whitebox-python/raw/master/examples/testdata.zip)
Args:
url (str): The HTTP URL to download.
out_file_name (str, optional): The output file name to use. Defaults to None.
out_dir (str, optional): The output directory to use. Defaults to '.'.
unzip (bool, optional): Whether to unzip the downloaded file if it is a zip file. Defaults to True.
verbose (bool, optional): Whether to display or not the output of the function
"""
in_file_name = os.path.basename(url)
out_dir = check_dir(out_dir)
if out_file_name is None:
out_file_name = in_file_name
out_file_path = os.path.join(out_dir, out_file_name)
if verbose:
print("Downloading {} ...".format(url))
try:
urllib.request.urlretrieve(url, out_file_path)
except Exception:
raise Exception("The URL is invalid. Please double check the URL.")
final_path = out_file_path
if unzip:
# if it is a zip file
if ".zip" in out_file_name:
if verbose:
print("Unzipping {} ...".format(out_file_name))
with zipfile.ZipFile(out_file_path, "r") as zip_ref:
zip_ref.extractall(out_dir)
final_path = os.path.join(
os.path.abspath(out_dir), out_file_name.replace(".zip", "")
)
# if it is a tar file
if ".tar" in out_file_name:
if verbose:
print("Unzipping {} ...".format(out_file_name))
with tarfile.open(out_file_path, "r") as tar_ref:
tar_ref.extractall(out_dir)
final_path = os.path.join(
os.path.abspath(out_dir), out_file_name.replace(".tart", "")
)
if verbose:
print("Data downloaded to: {}".format(final_path))
edit_download_html(htmlWidget, filename, title='Click here to download: ')
¶
Downloads a file from voila. Adopted from https://github.com/voila-dashboards/voila/issues/578#issuecomment-617668058
Parameters:
Name | Type | Description | Default |
---|---|---|---|
htmlWidget |
object |
The HTML widget to display the URL. |
required |
filename |
str |
File path to download. |
required |
title |
str |
Download description. Defaults to "Click here to download: ". |
'Click here to download: ' |
Source code in leafmap/common.py
def edit_download_html(htmlWidget, filename, title="Click here to download: "):
"""Downloads a file from voila. Adopted from https://github.com/voila-dashboards/voila/issues/578#issuecomment-617668058
Args:
htmlWidget (object): The HTML widget to display the URL.
filename (str): File path to download.
title (str, optional): Download description. Defaults to "Click here to download: ".
"""
# from IPython.display import HTML
# import ipywidgets as widgets
import base64
# Change widget html temporarily to a font-awesome spinner
htmlWidget.value = '<i class="fa fa-spinner fa-spin fa-2x fa-fw"></i><span class="sr-only">Loading...</span>'
# Process raw data
data = open(filename, "rb").read()
b64 = base64.b64encode(data)
payload = b64.decode()
basename = os.path.basename(filename)
# Create and assign html to widget
html = '<a download="{filename}" href="data:text/csv;base64,{payload}" target="_blank">{title}</a>'
htmlWidget.value = html.format(
payload=payload, title=title + basename, filename=basename
)
explode(coords)
¶
Explode a GeoJSON geometry's coordinates object and yield coordinate tuples. As long as the input is conforming, the type of the geometry doesn't matter. From Fiona 1.4.8
Parameters:
Name | Type | Description | Default |
---|---|---|---|
coords |
list |
A list of coordinates. |
required |
Yields:
Type | Description |
---|---|
[type] |
[description] |
Source code in leafmap/common.py
def explode(coords):
"""Explode a GeoJSON geometry's coordinates object and yield
coordinate tuples. As long as the input is conforming, the type of
the geometry doesn't matter. From Fiona 1.4.8
Args:
coords (list): A list of coordinates.
Yields:
[type]: [description]
"""
for e in coords:
if isinstance(e, (float, int)):
yield coords
break
else:
for f in explode(e):
yield f
gdf_bounds(gdf, return_geom=False)
¶
Returns the bounding box of a GeoDataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
gdf |
gpd.GeoDataFrame |
A GeoDataFrame. |
required |
return_geom |
bool |
Whether to return the bounding box as a GeoDataFrame. Defaults to False. |
False |
Returns:
Type | Description |
---|---|
list | gpd.GeoDataFrame |
A bounding box in the form of a list (minx, miny, maxx, maxy) or GeoDataFrame. |
Source code in leafmap/common.py
def gdf_bounds(gdf, return_geom=False):
"""Returns the bounding box of a GeoDataFrame.
Args:
gdf (gpd.GeoDataFrame): A GeoDataFrame.
return_geom (bool, optional): Whether to return the bounding box as a GeoDataFrame. Defaults to False.
Returns:
list | gpd.GeoDataFrame: A bounding box in the form of a list (minx, miny, maxx, maxy) or GeoDataFrame.
"""
bounds = gdf.total_bounds
if return_geom:
return bbox_to_gdf(bbox=bounds)
else:
return bounds
gdf_centroid(gdf, return_geom=False)
¶
Returns the centroid of a GeoDataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
gdf |
gpd.GeoDataFrame |
A GeoDataFrame. |
required |
return_geom |
bool |
Whether to return the bounding box as a GeoDataFrame. Defaults to False. |
False |
Returns:
Type | Description |
---|---|
list | gpd.GeoDataFrame |
A bounding box in the form of a list (lon, lat) or GeoDataFrame. |
Source code in leafmap/common.py
def gdf_centroid(gdf, return_geom=False):
"""Returns the centroid of a GeoDataFrame.
Args:
gdf (gpd.GeoDataFrame): A GeoDataFrame.
return_geom (bool, optional): Whether to return the bounding box as a GeoDataFrame. Defaults to False.
Returns:
list | gpd.GeoDataFrame: A bounding box in the form of a list (lon, lat) or GeoDataFrame.
"""
import warnings
warnings.filterwarnings("ignore")
centroid = gdf_bounds(gdf, return_geom=True).centroid
if return_geom:
return centroid
else:
return centroid.x[0], centroid.y[0]
gdf_geom_type(gdf, first_only=True)
¶
Returns the geometry type of a GeoDataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
gdf |
gpd.GeoDataFrame |
A GeoDataFrame. |
required |
first_only |
bool |
Whether to return the geometry type of the first feature in the GeoDataFrame. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
str |
The geometry type of the GeoDataFrame. |
Source code in leafmap/common.py
def gdf_geom_type(gdf, first_only=True):
"""Returns the geometry type of a GeoDataFrame.
Args:
gdf (gpd.GeoDataFrame): A GeoDataFrame.
first_only (bool, optional): Whether to return the geometry type of the first feature in the GeoDataFrame. Defaults to True.
Returns:
str: The geometry type of the GeoDataFrame.
"""
import geopandas as gpd
if first_only:
return gdf.geometry.type[0]
else:
return gdf.geometry.type
gdf_to_df(gdf, drop_geom=True)
¶
Converts a GeoDataFrame to a pandas DataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
gdf |
gpd.GeoDataFrame |
A GeoDataFrame. |
required |
drop_geom |
bool |
Whether to drop the geometry column. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
pd.DataFrame |
A pandas DataFrame containing the GeoDataFrame. |
Source code in leafmap/common.py
def gdf_to_df(gdf, drop_geom=True):
"""Converts a GeoDataFrame to a pandas DataFrame.
Args:
gdf (gpd.GeoDataFrame): A GeoDataFrame.
drop_geom (bool, optional): Whether to drop the geometry column. Defaults to True.
Returns:
pd.DataFrame: A pandas DataFrame containing the GeoDataFrame.
"""
import pandas as pd
if drop_geom:
df = pd.DataFrame(gdf.drop(columns=["geometry"]))
else:
df = pd.DataFrame(gdf)
return df
gdf_to_geojson(gdf, out_geojson=None, epsg=None, tuple_to_list=False, encoding='utf-8')
¶
Converts a GeoDataFame to GeoJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
gdf |
GeoDataFrame |
A GeoPandas GeoDataFrame. |
required |
out_geojson |
str |
File path to he output GeoJSON. Defaults to None. |
None |
epsg |
str |
An EPSG string, e.g., "4326". Defaults to None. |
None |
tuple_to_list |
bool |
Whether to convert tuples to lists. Defaults to False. |
False |
encoding |
str |
The encoding to use for the GeoJSON. Defaults to "utf-8". |
'utf-8' |
Exceptions:
Type | Description |
---|---|
TypeError |
When the output file extension is incorrect. |
Exception |
When the conversion fails. |
Returns:
Type | Description |
---|---|
dict |
When the out_json is None returns a dict. |
Source code in leafmap/common.py
def gdf_to_geojson(
gdf, out_geojson=None, epsg=None, tuple_to_list=False, encoding="utf-8"
):
"""Converts a GeoDataFame to GeoJSON.
Args:
gdf (GeoDataFrame): A GeoPandas GeoDataFrame.
out_geojson (str, optional): File path to he output GeoJSON. Defaults to None.
epsg (str, optional): An EPSG string, e.g., "4326". Defaults to None.
tuple_to_list (bool, optional): Whether to convert tuples to lists. Defaults to False.
encoding (str, optional): The encoding to use for the GeoJSON. Defaults to "utf-8".
Raises:
TypeError: When the output file extension is incorrect.
Exception: When the conversion fails.
Returns:
dict: When the out_json is None returns a dict.
"""
check_package(name="geopandas", URL="https://geopandas.org")
def listit(t):
return list(map(listit, t)) if isinstance(t, (list, tuple)) else t
try:
if epsg is not None:
if gdf.crs is not None and gdf.crs.to_epsg() != epsg:
gdf = gdf.to_crs(epsg=epsg)
geojson = gdf.__geo_interface__
if tuple_to_list:
for feature in geojson["features"]:
feature["geometry"]["coordinates"] = listit(
feature["geometry"]["coordinates"]
)
if out_geojson is None:
return geojson
else:
ext = os.path.splitext(out_geojson)[1]
if ext.lower() not in [".json", ".geojson"]:
raise TypeError(
"The output file extension must be either .json or .geojson"
)
out_dir = os.path.dirname(out_geojson)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
gdf.to_file(out_geojson, driver="GeoJSON", encoding=encoding)
except Exception as e:
raise Exception(e)
geojson_to_df(in_geojson, encoding='utf-8', drop_geometry=True)
¶
Converts a GeoJSON object to a pandas DataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_geojson |
str | dict |
The input GeoJSON file or dict. |
required |
encoding |
str |
The encoding of the GeoJSON object. Defaults to "utf-8". |
'utf-8' |
drop_geometry |
bool |
Whether to drop the geometry column. Defaults to True. |
True |
Exceptions:
Type | Description |
---|---|
FileNotFoundError |
If the input GeoJSON file could not be found. |
Returns:
Type | Description |
---|---|
pd.DataFrame |
A pandas DataFrame containing the GeoJSON object. |
Source code in leafmap/common.py
def geojson_to_df(in_geojson, encoding="utf-8", drop_geometry=True):
"""Converts a GeoJSON object to a pandas DataFrame.
Args:
in_geojson (str | dict): The input GeoJSON file or dict.
encoding (str, optional): The encoding of the GeoJSON object. Defaults to "utf-8".
drop_geometry (bool, optional): Whether to drop the geometry column. Defaults to True.
Raises:
FileNotFoundError: If the input GeoJSON file could not be found.
Returns:
pd.DataFrame: A pandas DataFrame containing the GeoJSON object.
"""
import json
import pandas as pd
from urllib.request import urlopen
if isinstance(in_geojson, str):
if in_geojson.startswith("http"):
with urlopen(in_geojson) as f:
data = json.load(f)
else:
in_geojson = os.path.abspath(in_geojson)
if not os.path.exists(in_geojson):
raise FileNotFoundError("The provided GeoJSON file could not be found.")
with open(in_geojson, encoding=encoding) as f:
data = json.load(f)
elif isinstance(in_geojson, dict):
data = in_geojson
df = pd.json_normalize(data["features"])
df.columns = [col.replace("properties.", "") for col in df.columns]
if drop_geometry:
df = df[df.columns.drop(list(df.filter(regex="geometry")))]
return df
geojson_to_gpkg(in_geojson, out_gpkg, **kwargs)
¶
Converts a GeoJSON object to GeoPackage.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_geojson |
str | dict |
The input GeoJSON file or dict. |
required |
out_gpkg |
str |
The output GeoPackage path. |
required |
Source code in leafmap/common.py
def geojson_to_gpkg(in_geojson, out_gpkg, **kwargs):
"""Converts a GeoJSON object to GeoPackage.
Args:
in_geojson (str | dict): The input GeoJSON file or dict.
out_gpkg (str): The output GeoPackage path.
"""
import geopandas as gpd
import json
ext = os.path.splitext(out_gpkg)[1]
if ext.lower() != ".gpkg":
out_gpkg = out_gpkg + ".gpkg"
out_gpkg = check_file_path(out_gpkg)
if isinstance(in_geojson, dict):
out_file = temp_file_path(extension="geojson")
with open(out_file, "w") as f:
json.dump(in_geojson, f)
in_geojson = out_file
gdf = gpd.read_file(in_geojson, **kwargs)
name = os.path.splitext(os.path.basename(out_gpkg))[0]
gdf.to_file(out_gpkg, layer=name, driver="GPKG")
geojson_to_shp(in_geojson, out_shp, **kwargs)
¶
Converts a GeoJSON object to GeoPandas GeoDataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_geojson |
str | dict |
The input GeoJSON file or dict. |
required |
out_shp |
str |
The output shapefile path. |
required |
Source code in leafmap/common.py
def geojson_to_shp(in_geojson, out_shp, **kwargs):
"""Converts a GeoJSON object to GeoPandas GeoDataFrame.
Args:
in_geojson (str | dict): The input GeoJSON file or dict.
out_shp (str): The output shapefile path.
"""
import geopandas as gpd
import json
ext = os.path.splitext(out_shp)[1]
if ext != ".shp":
out_shp = out_shp + ".shp"
out_shp = check_file_path(out_shp)
if isinstance(in_geojson, dict):
out_file = temp_file_path(extension="geojson")
with open(out_file, "w") as f:
json.dump(in_geojson, f)
in_geojson = out_file
gdf = gpd.read_file(in_geojson, **kwargs)
gdf.to_file(out_shp)
geom_type(in_geojson, encoding='utf-8')
¶
Returns the geometry type of a GeoJSON object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_geojson |
dict |
A GeoJSON object. |
required |
encoding |
str |
The encoding of the GeoJSON object. Defaults to "utf-8". |
'utf-8' |
Returns:
Type | Description |
---|---|
str |
The geometry type of the GeoJSON object. |
Source code in leafmap/common.py
def geom_type(in_geojson, encoding="utf-8"):
"""Returns the geometry type of a GeoJSON object.
Args:
in_geojson (dict): A GeoJSON object.
encoding (str, optional): The encoding of the GeoJSON object. Defaults to "utf-8".
Returns:
str: The geometry type of the GeoJSON object.
"""
import json
try:
if isinstance(in_geojson, str):
if in_geojson.startswith("http"):
data = requests.get(in_geojson).json()
else:
in_geojson = os.path.abspath(in_geojson)
if not os.path.exists(in_geojson):
raise FileNotFoundError(
"The provided GeoJSON file could not be found."
)
with open(in_geojson, encoding=encoding) as f:
data = json.load(f)
elif isinstance(in_geojson, dict):
data = in_geojson
else:
raise TypeError("The input geojson must be a type of str or dict.")
return data["features"][0]["geometry"]["type"]
except Exception as e:
raise Exception(e)
get_api_key(token_name, m=None)
¶
Retrieves an API key based on a system environmen variable.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
token_name |
str |
The token name. |
required |
m |
ipyleaflet.Map | folium.Map |
A Map instance. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
str |
The API key. |
Source code in leafmap/common.py
def get_api_key(token_name, m=None):
"""Retrieves an API key based on a system environmen variable.
Args:
token_name (str): The token name.
m (ipyleaflet.Map | folium.Map, optional): A Map instance. Defaults to None.
Returns:
str: The API key.
"""
api_key = os.environ.get(token_name)
if m is not None and token_name in m.api_keys:
api_key = m.api_keys[token_name]
return api_key
get_bounds(geometry, north_up=True, transform=None)
¶
Bounding box of a GeoJSON geometry, GeometryCollection, or FeatureCollection. left, bottom, right, top not xmin, ymin, xmax, ymax If not north_up, y will be switched to guarantee the above. Source code adapted from https://github.com/mapbox/rasterio/blob/master/rasterio/features.py#L361
Parameters:
Name | Type | Description | Default |
---|---|---|---|
geometry |
dict |
A GeoJSON dict. |
required |
north_up |
bool |
. Defaults to True. |
True |
transform |
[type] |
. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A list of coordinates representing [left, bottom, right, top] |
Source code in leafmap/common.py
def get_bounds(geometry, north_up=True, transform=None):
"""Bounding box of a GeoJSON geometry, GeometryCollection, or FeatureCollection.
left, bottom, right, top
*not* xmin, ymin, xmax, ymax
If not north_up, y will be switched to guarantee the above.
Source code adapted from https://github.com/mapbox/rasterio/blob/master/rasterio/features.py#L361
Args:
geometry (dict): A GeoJSON dict.
north_up (bool, optional): . Defaults to True.
transform ([type], optional): . Defaults to None.
Returns:
list: A list of coordinates representing [left, bottom, right, top]
"""
if "bbox" in geometry:
return tuple(geometry["bbox"])
geometry = geometry.get("geometry") or geometry
# geometry must be a geometry, GeometryCollection, or FeatureCollection
if not (
"coordinates" in geometry or "geometries" in geometry or "features" in geometry
):
raise ValueError(
"geometry must be a GeoJSON-like geometry, GeometryCollection, "
"or FeatureCollection"
)
if "features" in geometry:
# Input is a FeatureCollection
xmins = []
ymins = []
xmaxs = []
ymaxs = []
for feature in geometry["features"]:
xmin, ymin, xmax, ymax = get_bounds(feature["geometry"])
xmins.append(xmin)
ymins.append(ymin)
xmaxs.append(xmax)
ymaxs.append(ymax)
if north_up:
return min(xmins), min(ymins), max(xmaxs), max(ymaxs)
else:
return min(xmins), max(ymaxs), max(xmaxs), min(ymins)
elif "geometries" in geometry:
# Input is a geometry collection
xmins = []
ymins = []
xmaxs = []
ymaxs = []
for geometry in geometry["geometries"]:
xmin, ymin, xmax, ymax = get_bounds(geometry)
xmins.append(xmin)
ymins.append(ymin)
xmaxs.append(xmax)
ymaxs.append(ymax)
if north_up:
return min(xmins), min(ymins), max(xmaxs), max(ymaxs)
else:
return min(xmins), max(ymaxs), max(xmaxs), min(ymins)
elif "coordinates" in geometry:
# Input is a singular geometry object
if transform is not None:
xyz = list(explode(geometry["coordinates"]))
xyz_px = [transform * point for point in xyz]
xyz = tuple(zip(*xyz_px))
return min(xyz[0]), max(xyz[1]), max(xyz[0]), min(xyz[1])
else:
xyz = tuple(zip(*list(explode(geometry["coordinates"]))))
if north_up:
return min(xyz[0]), min(xyz[1]), max(xyz[0]), max(xyz[1])
else:
return min(xyz[0]), max(xyz[1]), max(xyz[0]), min(xyz[1])
# all valid inputs returned above, so whatever falls through is an error
raise ValueError(
"geometry must be a GeoJSON-like geometry, GeometryCollection, "
"or FeatureCollection"
)
get_census_dict(reset=False)
¶
Returns a dictionary of Census data.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
reset |
bool |
Reset the dictionary. Defaults to False. |
False |
Returns:
Type | Description |
---|---|
dict |
A dictionary of Census data. |
Source code in leafmap/common.py
def get_census_dict(reset=False):
"""Returns a dictionary of Census data.
Args:
reset (bool, optional): Reset the dictionary. Defaults to False.
Returns:
dict: A dictionary of Census data.
"""
import json
import pkg_resources
pkg_dir = os.path.dirname(pkg_resources.resource_filename("leafmap", "leafmap.py"))
census_data = os.path.join(pkg_dir, "data/census_data.json")
if reset:
try:
from owslib.wms import WebMapService
except ImportError:
raise ImportError("Please install owslib using 'pip install owslib'.")
census_dict = {}
names = [
"Current",
"ACS 2021",
"ACS 2019",
"ACS 2018",
"ACS 2017",
"ACS 2016",
"ACS 2015",
"ACS 2014",
"ACS 2013",
"ACS 2012",
"ECON 2012",
"Census 2020",
"Census 2010",
"Physical Features",
"Decennial Census 2020",
"Decennial Census 2010",
"Decennial Census 2000",
"Decennial Physical Features",
]
links = {}
print("Retrieving data. Please wait ...")
for name in names:
if "Decennial" not in name:
links[
name
] = f"https://tigerweb.geo.census.gov/arcgis/services/TIGERweb/tigerWMS_{name.replace(' ', '')}/MapServer/WMSServer"
else:
links[
name
] = f"https://tigerweb.geo.census.gov/arcgis/services/Census2020/tigerWMS_{name.replace('Decennial', '').replace(' ', '')}/MapServer/WMSServer"
wms = WebMapService(links[name], timeout=300)
layers = list(wms.contents)
layers.sort()
census_dict[name] = {
"url": links[name],
"layers": layers,
# "title": wms.identification.title,
# "abstract": wms.identification.abstract,
}
with open(census_data, "w") as f:
json.dump(census_dict, f, indent=4)
else:
with open(census_data, "r") as f:
census_dict = json.load(f)
return census_dict
get_center(geometry, north_up=True, transform=None)
¶
Get the centroid of a GeoJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
geometry |
dict |
A GeoJSON dict. |
required |
north_up |
bool |
. Defaults to True. |
True |
transform |
[type] |
. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
[lon, lat] |
Source code in leafmap/common.py
def get_center(geometry, north_up=True, transform=None):
"""Get the centroid of a GeoJSON.
Args:
geometry (dict): A GeoJSON dict.
north_up (bool, optional): . Defaults to True.
transform ([type], optional): . Defaults to None.
Returns:
list: [lon, lat]
"""
bounds = get_bounds(geometry, north_up, transform)
center = ((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2) # (lat, lon)
return center
get_local_tile_layer(source, port='default', debug=False, projection='EPSG:3857', band=None, palette=None, vmin=None, vmax=None, nodata=None, attribution=None, tile_format='ipyleaflet', layer_name='Local COG', return_client=False, **kwargs)
¶
Generate an ipyleaflet/folium TileLayer from a local raster dataset or remote Cloud Optimized GeoTIFF (COG). If you are using this function in JupyterHub on a remote server (e.g., Binder, Microsoft Planetary Computer), try adding to following two lines to the beginning of the notebook if the raster does not render properly.
1 2 |
|
Parameters:
Name | Type | Description | Default |
---|---|---|---|
source |
str |
The path to the GeoTIFF file or the URL of the Cloud Optimized GeoTIFF. |
required |
port |
str |
The port to use for the server. Defaults to "default". |
'default' |
debug |
bool |
If True, the server will be started in debug mode. Defaults to False. |
False |
projection |
str |
The projection of the GeoTIFF. Defaults to "EPSG:3857". |
'EPSG:3857' |
band |
int |
The band to use. Band indexing starts at 1. Defaults to None. |
None |
palette |
str |
The name of the color palette from |
None |
vmin |
float |
The minimum value to use when colormapping the palette when plotting a single band. Defaults to None. |
None |
vmax |
float |
The maximum value to use when colormapping the palette when plotting a single band. Defaults to None. |
None |
nodata |
float |
The value from the band to use to interpret as not valid data. Defaults to None. |
None |
attribution |
str |
Attribution for the source raster. This defaults to a message about it being a local file.. Defaults to None. |
None |
tile_format |
str |
The tile layer format. Can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
layer_name |
str |
The layer name to use. Defaults to None. |
'Local COG' |
return_client |
bool |
If True, the tile client will be returned. Defaults to False. |
False |
Returns:
Type | Description |
---|---|
ipyleaflet.TileLayer | folium.TileLayer |
An ipyleaflet.TileLayer or folium.TileLayer. |
Source code in leafmap/common.py
def get_local_tile_layer(
source,
port="default",
debug=False,
projection="EPSG:3857",
band=None,
palette=None,
vmin=None,
vmax=None,
nodata=None,
attribution=None,
tile_format="ipyleaflet",
layer_name="Local COG",
return_client=False,
**kwargs,
):
"""Generate an ipyleaflet/folium TileLayer from a local raster dataset or remote Cloud Optimized GeoTIFF (COG).
If you are using this function in JupyterHub on a remote server (e.g., Binder, Microsoft Planetary Computer),
try adding to following two lines to the beginning of the notebook if the raster does not render properly.
import os
os.environ['LOCALTILESERVER_CLIENT_PREFIX'] = f'{os.environ['JUPYTERHUB_SERVICE_PREFIX'].lstrip('/')}/proxy/{{port}}'
Args:
source (str): The path to the GeoTIFF file or the URL of the Cloud Optimized GeoTIFF.
port (str, optional): The port to use for the server. Defaults to "default".
debug (bool, optional): If True, the server will be started in debug mode. Defaults to False.
projection (str, optional): The projection of the GeoTIFF. Defaults to "EPSG:3857".
band (int, optional): The band to use. Band indexing starts at 1. Defaults to None.
palette (str, optional): The name of the color palette from `palettable` to use when plotting a single band. See https://jiffyclub.github.io/palettable. Default is greyscale
vmin (float, optional): The minimum value to use when colormapping the palette when plotting a single band. Defaults to None.
vmax (float, optional): The maximum value to use when colormapping the palette when plotting a single band. Defaults to None.
nodata (float, optional): The value from the band to use to interpret as not valid data. Defaults to None.
attribution (str, optional): Attribution for the source raster. This defaults to a message about it being a local file.. Defaults to None.
tile_format (str, optional): The tile layer format. Can be either ipyleaflet or folium. Defaults to "ipyleaflet".
layer_name (str, optional): The layer name to use. Defaults to None.
return_client (bool, optional): If True, the tile client will be returned. Defaults to False.
Returns:
ipyleaflet.TileLayer | folium.TileLayer: An ipyleaflet.TileLayer or folium.TileLayer.
"""
check_package(
"localtileserver", URL="https://github.com/banesullivan/localtileserver"
)
# Make it compatible with binder and JupyterHub
if os.environ.get("JUPYTERHUB_SERVICE_PREFIX") is not None:
os.environ[
"LOCALTILESERVER_CLIENT_PREFIX"
] = f"{os.environ['JUPYTERHUB_SERVICE_PREFIX'].lstrip('/')}/proxy/{{port}}"
from localtileserver import (
get_leaflet_tile_layer,
get_folium_tile_layer,
TileClient,
)
if isinstance(source, str):
if not source.startswith("http"):
if source.startswith("~"):
source = os.path.expanduser(source)
else:
source = os.path.abspath(source)
if not os.path.exists(source):
raise ValueError("The source path does not exist.")
else:
raise ValueError("The source must either be a string or TileClient")
if isinstance(palette, str):
palette = get_palette_colors(palette, hashtag=True)
if tile_format not in ["ipyleaflet", "folium"]:
raise ValueError("The tile format must be either ipyleaflet or folium.")
if layer_name is None:
if source.startswith("http"):
layer_name = "RemoteTile_" + random_string(3)
else:
layer_name = "LocalTile_" + random_string(3)
tile_client = TileClient(source, port=port, debug=debug)
if tile_format == "ipyleaflet":
tile_layer = get_leaflet_tile_layer(
tile_client,
port=port,
debug=debug,
projection=projection,
band=band,
palette=palette,
vmin=vmin,
vmax=vmax,
nodata=nodata,
attribution=attribution,
name=layer_name,
**kwargs,
)
else:
tile_layer = get_folium_tile_layer(
tile_client,
port=port,
debug=debug,
projection=projection,
band=band,
palette=palette,
vmin=vmin,
vmax=vmax,
nodata=nodata,
attr=attribution,
overlay=True,
name=layer_name,
**kwargs,
)
if return_client:
return tile_layer, tile_client
else:
return tile_layer
# center = tile_client.center()
# bounds = tile_client.bounds() # [ymin, ymax, xmin, xmax]
# bounds = (bounds[2], bounds[0], bounds[3], bounds[1]) # [minx, miny, maxx, maxy]
# if get_center and get_bounds:
# return tile_layer, center, bounds
# elif get_center:
# return tile_layer, center
# elif get_bounds:
# return tile_layer, bounds
# else:
# return tile_layer
get_palettable(types=None)
¶
Get a list of palettable color palettes.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
types |
list |
A list of palettable types to return, e.g., types=['matplotlib', 'cartocolors']. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A list of palettable color palettes. |
Source code in leafmap/common.py
def get_palettable(types=None):
"""Get a list of palettable color palettes.
Args:
types (list, optional): A list of palettable types to return, e.g., types=['matplotlib', 'cartocolors']. Defaults to None.
Returns:
list: A list of palettable color palettes.
"""
try:
import palettable
except ImportError:
raise ImportError(
"Please install the palettable package using 'pip install palettable'."
)
if types is not None and (not isinstance(types, list)):
raise ValueError("The types must be a list.")
allowed_palettes = [
"cartocolors",
"cmocean",
"colorbrewer",
"cubehelix",
"lightbartlein",
"matplotlib",
"mycarta",
"scientific",
"tableau",
"wesanderson",
]
if types is None:
types = allowed_palettes[:]
if all(x in allowed_palettes for x in types):
pass
else:
raise ValueError(
"The types must be one of the following: " + ", ".join(allowed_palettes)
)
palettes = []
if "cartocolors" in types:
cartocolors_diverging = [
f"cartocolors.diverging.{c}"
for c in dir(palettable.cartocolors.diverging)[:-19]
]
cartocolors_qualitative = [
f"cartocolors.qualitative.{c}"
for c in dir(palettable.cartocolors.qualitative)[:-19]
]
cartocolors_sequential = [
f"cartocolors.sequential.{c}"
for c in dir(palettable.cartocolors.sequential)[:-41]
]
palettes = (
palettes
+ cartocolors_diverging
+ cartocolors_qualitative
+ cartocolors_sequential
)
if "cmocean" in types:
cmocean_diverging = [
f"cmocean.diverging.{c}" for c in dir(palettable.cmocean.diverging)[:-19]
]
cmocean_sequential = [
f"cmocean.sequential.{c}" for c in dir(palettable.cmocean.sequential)[:-19]
]
palettes = palettes + cmocean_diverging + cmocean_sequential
if "colorbrewer" in types:
colorbrewer_diverging = [
f"colorbrewer.diverging.{c}"
for c in dir(palettable.colorbrewer.diverging)[:-19]
]
colorbrewer_qualitative = [
f"colorbrewer.qualitative.{c}"
for c in dir(palettable.colorbrewer.qualitative)[:-19]
]
colorbrewer_sequential = [
f"colorbrewer.sequential.{c}"
for c in dir(palettable.colorbrewer.sequential)[:-41]
]
palettes = (
palettes
+ colorbrewer_diverging
+ colorbrewer_qualitative
+ colorbrewer_sequential
)
if "cubehelix" in types:
cubehelix = [
"classic_16",
"cubehelix1_16",
"cubehelix2_16",
"cubehelix3_16",
"jim_special_16",
"perceptual_rainbow_16",
"purple_16",
"red_16",
]
cubehelix = [f"cubehelix.{c}" for c in cubehelix]
palettes = palettes + cubehelix
if "lightbartlein" in types:
lightbartlein_diverging = [
f"lightbartlein.diverging.{c}"
for c in dir(palettable.lightbartlein.diverging)[:-19]
]
lightbartlein_sequential = [
f"lightbartlein.sequential.{c}"
for c in dir(palettable.lightbartlein.sequential)[:-19]
]
palettes = palettes + lightbartlein_diverging + lightbartlein_sequential
if "matplotlib" in types:
matplotlib_colors = [
f"matplotlib.{c}" for c in dir(palettable.matplotlib)[:-16]
]
palettes = palettes + matplotlib_colors
if "mycarta" in types:
mycarta = [f"mycarta.{c}" for c in dir(palettable.mycarta)[:-16]]
palettes = palettes + mycarta
if "scientific" in types:
scientific_diverging = [
f"scientific.diverging.{c}"
for c in dir(palettable.scientific.diverging)[:-19]
]
scientific_sequential = [
f"scientific.sequential.{c}"
for c in dir(palettable.scientific.sequential)[:-19]
]
palettes = palettes + scientific_diverging + scientific_sequential
if "tableau" in types:
tableau = [f"tableau.{c}" for c in dir(palettable.tableau)[:-14]]
palettes = palettes + tableau
return palettes
get_palette_colors(cmap_name=None, n_class=None, hashtag=False)
¶
Get a palette from a matplotlib colormap. See the list of colormaps at https://matplotlib.org/stable/tutorials/colors/colormaps.html.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
cmap_name |
str |
The name of the matplotlib colormap. Defaults to None. |
None |
n_class |
int |
The number of colors. Defaults to None. |
None |
hashtag |
bool |
Whether to return a list of hex colors. Defaults to False. |
False |
Returns:
Type | Description |
---|---|
list |
A list of hex colors. |
Source code in leafmap/common.py
def get_palette_colors(cmap_name=None, n_class=None, hashtag=False):
"""Get a palette from a matplotlib colormap. See the list of colormaps at https://matplotlib.org/stable/tutorials/colors/colormaps.html.
Args:
cmap_name (str, optional): The name of the matplotlib colormap. Defaults to None.
n_class (int, optional): The number of colors. Defaults to None.
hashtag (bool, optional): Whether to return a list of hex colors. Defaults to False.
Returns:
list: A list of hex colors.
"""
import matplotlib as mpl
import matplotlib.pyplot as plt
cmap = plt.cm.get_cmap(cmap_name, n_class)
colors = [mpl.colors.rgb2hex(cmap(i))[1:] for i in range(cmap.N)]
if hashtag:
colors = ["#" + i for i in colors]
return colors
get_stac_collections(url)
¶
Retrieve a list of STAC collections from a URL. This function is adapted from https://github.com/mykolakozyr/stacdiscovery/blob/a5d1029aec9c428a7ce7ae615621ea8915162824/app.py#L31. Credits to Mykola Kozyr.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
A URL to a STAC catalog. |
required |
Returns:
Type | Description |
---|---|
list |
A list of STAC collections. |
Source code in leafmap/common.py
def get_stac_collections(url):
"""Retrieve a list of STAC collections from a URL.
This function is adapted from https://github.com/mykolakozyr/stacdiscovery/blob/a5d1029aec9c428a7ce7ae615621ea8915162824/app.py#L31.
Credits to Mykola Kozyr.
Args:
url (str): A URL to a STAC catalog.
Returns:
list: A list of STAC collections.
"""
from pystac_client import Client
# Expensive function. Added cache for it.
# Empty list that would be used for a dataframe to collect and visualize info about collections
root_catalog = Client.open(url)
collections_list = []
# Reading collections in the Catalog
collections = list(root_catalog.get_collections())
print(collections)
for collection in collections:
id = collection.id
title = collection.title
# bbox = collection.extent.spatial.bboxes # not in use for the first release
# interval = collection.extent.temporal.intervals # not in use for the first release
description = collection.description
# creating a list of lists of values
collections_list.append([id, title, description])
return collections_list
get_stac_items(url, collection, limit=None, bbox=None, datetime=None, intersects=None, ids=None, **kwargs)
¶
Retrieve a list of STAC items from a URL and a collection. This function is adapted from https://github.com/mykolakozyr/stacdiscovery/blob/a5d1029aec9c428a7ce7ae615621ea8915162824/app.py#L49. Credits to Mykola Kozyr. Available parameters can be found at https://github.com/radiantearth/stac-api-spec/tree/master/item-search
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
A URL to a STAC catalog. |
required |
collection |
str |
A STAC collection ID. |
required |
limit |
int |
The maximum number of results to return (page size). Defaults to None. |
None |
bbox |
tuple |
Requested bounding box in the format of (minx, miny, maxx, maxy). Defaults to None. |
None |
datetime |
str |
Single date+time, or a range ('/' separator), formatted to RFC 3339, section 5.6. Use double dots .. for open date ranges. |
None |
intersects |
dict |
A dictionary representing a GeoJSON Geometry. Searches items by performing intersection between their geometry and provided GeoJSON geometry. All GeoJSON geometry types must be supported. |
None |
ids |
list |
A list of item ids to return. |
None |
Returns:
Type | Description |
---|---|
GeoPandas.GeoDataFraem |
A GeoDataFrame with the STAC items. |
Source code in leafmap/common.py
def get_stac_items(
url,
collection,
limit=None,
bbox=None,
datetime=None,
intersects=None,
ids=None,
**kwargs,
):
"""Retrieve a list of STAC items from a URL and a collection.
This function is adapted from https://github.com/mykolakozyr/stacdiscovery/blob/a5d1029aec9c428a7ce7ae615621ea8915162824/app.py#L49.
Credits to Mykola Kozyr.
Available parameters can be found at https://github.com/radiantearth/stac-api-spec/tree/master/item-search
Args:
url (str): A URL to a STAC catalog.
collection (str): A STAC collection ID.
limit (int, optional): The maximum number of results to return (page size). Defaults to None.
bbox (tuple, optional): Requested bounding box in the format of (minx, miny, maxx, maxy). Defaults to None.
datetime (str, optional): Single date+time, or a range ('/' separator), formatted to RFC 3339, section 5.6. Use double dots .. for open date ranges.
intersects (dict, optional): A dictionary representing a GeoJSON Geometry. Searches items by performing intersection between their geometry and provided GeoJSON geometry. All GeoJSON geometry types must be supported.
ids (list, optional): A list of item ids to return.
Returns:
GeoPandas.GeoDataFraem: A GeoDataFrame with the STAC items.
"""
import itertools
import geopandas as gpd
from shapely.geometry import shape
from pystac_client import Client
# Empty list that would be used for a dataframe to collect and visualize info about collections
items_list = []
root_catalog = Client.open(url)
if limit:
kwargs["limit"] = limit
if bbox:
kwargs["bbox"] = bbox
if datetime:
kwargs["datetime"] = datetime
if intersects:
kwargs["intersects"] = intersects
if ids:
kwargs["ids"] = ids
if kwargs:
try:
catalog = root_catalog.search(collections=collection, **kwargs)
except NotImplementedError:
catalog = root_catalog
else:
catalog = root_catalog
iterable = catalog.get_all_items()
items = list(
itertools.islice(iterable, limit)
) # getting first 25000 items. To Do some smarter logic
if len(items) == 0:
try:
catalog = root_catalog.get_child(collection)
iterable = catalog.get_all_items()
items = list(itertools.islice(iterable, limit))
except Exception as _:
print("Ooops, it looks like this collection does not have items.")
return None
# Iterating over items to collect main information
for item in items:
id = item.id
geometry = shape(item.geometry)
datetime = (
item.datetime
or item.properties["datetime"]
or item.properties["end_datetime"]
or item.properties["start_datetime"]
)
links = item.links
for link in links:
if link.rel == "self":
self_url = link.target
assets_list = []
assets = item.assets
for asset in assets:
assets_list.append(asset)
# creating a list of lists of values
items_list.append([id, geometry, datetime, self_url, assets_list])
if limit is not None:
items_list = items_list[:limit]
items_df = gpd.GeoDataFrame(items_list)
items_df.columns = ["id", "geometry", "datetime", "self_url", "assets_list"]
items_gdf = items_df.set_geometry("geometry")
items_gdf["datetime"] = items_gdf["datetime"].astype(
str
) # specifically for KeplerGL. See https://github.com/keplergl/kepler.gl/issues/602
# items_gdf["assets_list"] = items_gdf["assets_list"].astype(str) #specifically for KeplerGL. See https://github.com/keplergl/kepler.gl/issues/602
items_gdf.set_crs(epsg=4326, inplace=True)
return items_gdf
get_wms_layers(url)
¶
Returns a list of WMS layers from a WMS service.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
The URL of the WMS service. |
required |
Returns:
Type | Description |
---|---|
list |
A list of WMS layers. |
Source code in leafmap/common.py
def get_wms_layers(url):
"""Returns a list of WMS layers from a WMS service.
Args:
url (str): The URL of the WMS service.
Returns:
list: A list of WMS layers.
"""
try:
from owslib.wms import WebMapService
except ImportError:
raise ImportError("Please install owslib using 'pip install owslib'.")
wms = WebMapService(url)
layers = list(wms.contents)
layers.sort()
return layers
has_transparency(img)
¶
Checks whether an image has transparency.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
img |
object |
a PIL Image object. |
required |
Returns:
Type | Description |
---|---|
bool |
True if it has transparency, False otherwise. |
Source code in leafmap/common.py
def has_transparency(img):
"""Checks whether an image has transparency.
Args:
img (object): a PIL Image object.
Returns:
bool: True if it has transparency, False otherwise.
"""
if img.mode == "P":
transparent = img.info.get("transparency", -1)
for _, index in img.getcolors():
if index == transparent:
return True
elif img.mode == "RGBA":
extrema = img.getextrema()
if extrema[3][0] < 255:
return True
return False
hex_to_rgb(value='FFFFFF')
¶
Converts hex color to RGB color.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
value |
str |
Hex color code as a string. Defaults to 'FFFFFF'. |
'FFFFFF' |
Returns:
Type | Description |
---|---|
tuple |
RGB color as a tuple. |
Source code in leafmap/common.py
def hex_to_rgb(value="FFFFFF"):
"""Converts hex color to RGB color.
Args:
value (str, optional): Hex color code as a string. Defaults to 'FFFFFF'.
Returns:
tuple: RGB color as a tuple.
"""
value = value.lstrip("#")
lv = len(value)
return tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3))
html_to_streamlit(html, width=800, height=600, responsive=True, scrolling=False, token_name=None, token_value=None, **kwargs)
¶
Renders an HTML file in a Streamlit app. This method is a static Streamlit Component, meaning, no information is passed back from Leaflet on browser interaction.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
html |
str |
The HTML file to render. It can a local file path or a URL. |
required |
width |
int |
Width of the map. Defaults to 800. |
800 |
height |
int |
Height of the map. Defaults to 600. |
600 |
responsive |
bool |
Whether to make the map responsive. Defaults to True. |
True |
scrolling |
bool |
Whether to allow the map to scroll. Defaults to False. |
False |
token_name |
str |
The name of the token in the HTML file to be replaced. Defaults to None. |
None |
token_value |
str |
The value of the token to pass to the HTML file. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
streamlit.components |
components.html object. |
Source code in leafmap/common.py
def html_to_streamlit(
html,
width=800,
height=600,
responsive=True,
scrolling=False,
token_name=None,
token_value=None,
**kwargs,
):
"""Renders an HTML file in a Streamlit app. This method is a static Streamlit Component, meaning, no information is passed back from Leaflet on browser interaction.
Args:
html (str): The HTML file to render. It can a local file path or a URL.
width (int, optional): Width of the map. Defaults to 800.
height (int, optional): Height of the map. Defaults to 600.
responsive (bool, optional): Whether to make the map responsive. Defaults to True.
scrolling (bool, optional): Whether to allow the map to scroll. Defaults to False.
token_name (str, optional): The name of the token in the HTML file to be replaced. Defaults to None.
token_value (str, optional): The value of the token to pass to the HTML file. Defaults to None.
Returns:
streamlit.components: components.html object.
"""
try:
import streamlit as st
import streamlit.components.v1 as components
if isinstance(html, str):
temp_path = None
if html.startswith("http") and html.endswith(".html"):
temp_path = temp_file_path(".html")
out_file = os.path.basename(temp_path)
out_dir = os.path.dirname(temp_path)
download_from_url(html, out_file, out_dir)
html = temp_path
elif not os.path.exists(html):
raise FileNotFoundError("The specified input html does not exist.")
with open(html) as f:
lines = f.readlines()
if (token_name is not None) and (token_value is not None):
lines = [line.replace(token_name, token_value) for line in lines]
html_str = "".join(lines)
if temp_path is not None:
os.remove(temp_path)
if responsive:
make_map_responsive = """
<style>
[title~="st.iframe"] { width: 100%}
</style>
"""
st.markdown(make_map_responsive, unsafe_allow_html=True)
return components.html(
html_str, width=width, height=height, scrolling=scrolling
)
else:
raise TypeError("The html must be a string.")
except Exception as e:
raise Exception(e)
image_to_cog(source, dst_path=None, profile='deflate', **kwargs)
¶
Converts an image to a COG file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
source |
str |
A dataset path, URL or rasterio.io.DatasetReader object. |
required |
dst_path |
str |
An output dataset path or or PathLike object. Defaults to None. |
None |
profile |
str |
COG profile. More at https://cogeotiff.github.io/rio-cogeo/profile. Defaults to "deflate". |
'deflate' |
Exceptions:
Type | Description |
---|---|
ImportError |
If rio-cogeo is not installed. |
FileNotFoundError |
If the source file could not be found. |
Source code in leafmap/common.py
def image_to_cog(source, dst_path=None, profile="deflate", **kwargs):
"""Converts an image to a COG file.
Args:
source (str): A dataset path, URL or rasterio.io.DatasetReader object.
dst_path (str, optional): An output dataset path or or PathLike object. Defaults to None.
profile (str, optional): COG profile. More at https://cogeotiff.github.io/rio-cogeo/profile. Defaults to "deflate".
Raises:
ImportError: If rio-cogeo is not installed.
FileNotFoundError: If the source file could not be found.
"""
try:
from rio_cogeo.cogeo import cog_translate
from rio_cogeo.profiles import cog_profiles
except ImportError:
raise ImportError(
"The rio-cogeo package is not installed. Please install it with `pip install rio-cogeo` or `conda install rio-cogeo -c conda-forge`."
)
if not source.startswith("http"):
source = check_file_path(source)
if not os.path.exists(source):
raise FileNotFoundError("The provided input file could not be found.")
if dst_path is None:
if not source.startswith("http"):
dst_path = os.path.splitext(source)[0] + "_cog.tif"
else:
dst_path = temp_file_path(extension=".tif")
dst_path = check_file_path(dst_path)
dst_profile = cog_profiles.get(profile)
cog_translate(source, dst_path, dst_profile, **kwargs)
image_to_numpy(image)
¶
Converts an image to a numpy array.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
image |
str |
A dataset path, URL or rasterio.io.DatasetReader object. |
required |
Exceptions:
Type | Description |
---|---|
FileNotFoundError |
If the provided file could not be found. |
Returns:
Type | Description |
---|---|
np.array |
A numpy array. |
Source code in leafmap/common.py
def image_to_numpy(image):
"""Converts an image to a numpy array.
Args:
image (str): A dataset path, URL or rasterio.io.DatasetReader object.
Raises:
FileNotFoundError: If the provided file could not be found.
Returns:
np.array: A numpy array.
"""
import rasterio
if not os.path.exists(image):
raise FileNotFoundError("The provided input file could not be found.")
with rasterio.open(image, "r") as ds:
arr = ds.read() # read all raster values
return arr
kml_to_geojson(in_kml, out_geojson=None)
¶
Converts a KML to GeoJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_kml |
str |
The file path to the input KML. |
required |
out_geojson |
str |
The file path to the output GeoJSON. Defaults to None. |
None |
Exceptions:
Type | Description |
---|---|
FileNotFoundError |
The input KML could not be found. |
TypeError |
The output must be a GeoJSON. |
Source code in leafmap/common.py
def kml_to_geojson(in_kml, out_geojson=None):
"""Converts a KML to GeoJSON.
Args:
in_kml (str): The file path to the input KML.
out_geojson (str): The file path to the output GeoJSON. Defaults to None.
Raises:
FileNotFoundError: The input KML could not be found.
TypeError: The output must be a GeoJSON.
"""
import warnings
warnings.filterwarnings("ignore")
in_kml = os.path.abspath(in_kml)
if not os.path.exists(in_kml):
raise FileNotFoundError("The input KML could not be found.")
if out_geojson is not None:
out_geojson = os.path.abspath(out_geojson)
ext = os.path.splitext(out_geojson)[1].lower()
if ext not in [".json", ".geojson"]:
raise TypeError("The output file must be a GeoJSON.")
out_dir = os.path.dirname(out_geojson)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
check_package(name="geopandas", URL="https://geopandas.org")
import geopandas as gpd
# import fiona
# print(fiona.supported_drivers)
gpd.io.file.fiona.drvsupport.supported_drivers["KML"] = "rw"
gdf = gpd.read_file(in_kml, driver="KML")
if out_geojson is not None:
gdf.to_file(out_geojson, driver="GeoJSON")
else:
return gdf.__geo_interface__
kml_to_shp(in_kml, out_shp)
¶
Converts a KML to shapefile.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_kml |
str |
The file path to the input KML. |
required |
out_shp |
str |
The file path to the output shapefile. |
required |
Exceptions:
Type | Description |
---|---|
FileNotFoundError |
The input KML could not be found. |
TypeError |
The output must be a shapefile. |
Source code in leafmap/common.py
def kml_to_shp(in_kml, out_shp):
"""Converts a KML to shapefile.
Args:
in_kml (str): The file path to the input KML.
out_shp (str): The file path to the output shapefile.
Raises:
FileNotFoundError: The input KML could not be found.
TypeError: The output must be a shapefile.
"""
import warnings
warnings.filterwarnings("ignore")
in_kml = os.path.abspath(in_kml)
if not os.path.exists(in_kml):
raise FileNotFoundError("The input KML could not be found.")
out_shp = os.path.abspath(out_shp)
if not out_shp.endswith(".shp"):
raise TypeError("The output must be a shapefile.")
out_dir = os.path.dirname(out_shp)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
check_package(name="geopandas", URL="https://geopandas.org")
import geopandas as gpd
# import fiona
# print(fiona.supported_drivers)
gpd.io.file.fiona.drvsupport.supported_drivers["KML"] = "rw"
df = gpd.read_file(in_kml, driver="KML")
df.to_file(out_shp)
list_palettes(add_extra=False, lowercase=False)
¶
List all available colormaps. See a complete lost of colormaps at https://matplotlib.org/stable/tutorials/colors/colormaps.html.
Returns:
Type | Description |
---|---|
list |
The list of colormap names. |
Source code in leafmap/common.py
def list_palettes(add_extra=False, lowercase=False):
"""List all available colormaps. See a complete lost of colormaps at https://matplotlib.org/stable/tutorials/colors/colormaps.html.
Returns:
list: The list of colormap names.
"""
import matplotlib.pyplot as plt
result = plt.colormaps()
if add_extra:
result += ["dem", "ndvi", "ndwi"]
if lowercase:
result = [i.lower() for i in result]
result.sort()
return result
local_tile_bands(source)
¶
Get band names from COG.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
source |
str | TileClient |
A local COG file path or TileClient |
required |
Returns:
Type | Description |
---|---|
list |
A list of band names. |
Source code in leafmap/common.py
def local_tile_bands(source):
"""Get band names from COG.
Args:
source (str | TileClient): A local COG file path or TileClient
Returns:
list: A list of band names.
"""
check_package("localtileserver", "https://github.com/banesullivan/localtileserver")
from localtileserver import TileClient
if isinstance(source, str):
tile_client = TileClient(source)
elif isinstance(source, TileClient):
tile_client = source
else:
raise ValueError("source must be a string or TileClient object.")
bandnames = list(tile_client.metadata()["bands"].keys())
return bandnames
local_tile_pixel_value(lon, lat, tile_client, verbose=True, **kwargs)
¶
Get pixel value from COG.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lon |
float |
Longitude of the pixel. |
required |
lat |
float |
Latitude of the pixel. |
required |
url |
str |
HTTP URL to a COG, e.g., 'https://opendata.digitalglobe.com/events/california-fire-2020/pre-event/2018-02-16/pine-gulch-fire20/1030010076004E00.tif' |
required |
bidx |
str |
Dataset band indexes (e.g bidx=1, bidx=1&bidx=2&bidx=3). Defaults to None. |
required |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
required |
verbose |
bool |
Print status messages. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
list |
A dictionary of band info. |
Source code in leafmap/common.py
def local_tile_pixel_value(
lon,
lat,
tile_client,
verbose=True,
**kwargs,
):
"""Get pixel value from COG.
Args:
lon (float): Longitude of the pixel.
lat (float): Latitude of the pixel.
url (str): HTTP URL to a COG, e.g., 'https://opendata.digitalglobe.com/events/california-fire-2020/pre-event/2018-02-16/pine-gulch-fire20/1030010076004E00.tif'
bidx (str, optional): Dataset band indexes (e.g bidx=1, bidx=1&bidx=2&bidx=3). Defaults to None.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
verbose (bool, optional): Print status messages. Defaults to True.
Returns:
list: A dictionary of band info.
"""
r = tile_client.pixel(lat, lon, units="EPSG:4326", **kwargs)
if "bands" in r:
return r["bands"]
else:
if verbose:
print("No pixel value found.")
return None
local_tile_vmin_vmax(source, bands=None, **kwargs)
¶
Get vmin and vmax from COG.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
source |
str | TileClient |
A local COG file path or TileClient object. |
required |
bands |
str | list |
A list of band names. Defaults to None. |
None |
Exceptions:
Type | Description |
---|---|
ValueError |
If source is not a TileClient object or a local COG file path. |
Returns:
Type | Description |
---|---|
tuple |
A tuple of vmin and vmax. |
Source code in leafmap/common.py
def local_tile_vmin_vmax(
source,
bands=None,
**kwargs,
):
"""Get vmin and vmax from COG.
Args:
source (str | TileClient): A local COG file path or TileClient object.
bands (str | list, optional): A list of band names. Defaults to None.
Raises:
ValueError: If source is not a TileClient object or a local COG file path.
Returns:
tuple: A tuple of vmin and vmax.
"""
check_package("localtileserver", "https://github.com/banesullivan/localtileserver")
from localtileserver import TileClient
if isinstance(source, str):
tile_client = TileClient(source)
elif isinstance(source, TileClient):
tile_client = source
else:
raise ValueError("source must be a string or TileClient object.")
stats = tile_client.metadata()["bands"]
bandnames = list(stats.keys())
if isinstance(bands, str):
bands = [bands]
elif isinstance(bands, list):
pass
elif bands is None:
bands = bandnames
if all(b in bandnames for b in bands):
vmin = min([stats[b]["min"] for b in bands])
vmax = max([stats[b]["max"] for b in bands])
else:
vmin = min([stats[b]["min"] for b in bandnames])
vmax = max([stats[b]["max"] for b in bandnames])
return vmin, vmax
mosaic_bounds(url, titiler_endpoint=None, **kwargs)
¶
Get the bounding box of a MosaicJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a MosaicJSON. |
required |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A list of values representing [left, bottom, right, top] |
Source code in leafmap/common.py
def mosaic_bounds(url, titiler_endpoint=None, **kwargs):
"""Get the bounding box of a MosaicJSON.
Args:
url (str): HTTP URL to a MosaicJSON.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz". Defaults to None.
Returns:
list: A list of values representing [left, bottom, right, top]
"""
if titiler_endpoint is None:
titiler_endpoint = "https://titiler.xyz"
if isinstance(url, str) and url.startswith("http"):
kwargs["url"] = url
else:
raise ValueError("url must be a string and start with http.")
if isinstance(titiler_endpoint, str):
r = requests.get(
f"{titiler_endpoint}/mosaicjson/bounds",
params=kwargs,
).json()
else:
raise ValueError("titiler_endpoint must be a string.")
return r["bounds"]
mosaic_info(url, titiler_endpoint=None, **kwargs)
¶
Get the info of a MosaicJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a MosaicJSON. |
required |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
dict |
A dictionary containing bounds, center, minzoom, maxzoom, and name as keys. |
Source code in leafmap/common.py
def mosaic_info(url, titiler_endpoint=None, **kwargs):
"""Get the info of a MosaicJSON.
Args:
url (str): HTTP URL to a MosaicJSON.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz". Defaults to None.
Returns:
dict: A dictionary containing bounds, center, minzoom, maxzoom, and name as keys.
"""
if titiler_endpoint is None:
titiler_endpoint = "https://titiler.xyz"
if isinstance(url, str) and url.startswith("http"):
kwargs["url"] = url
else:
raise ValueError("url must be a string and start with http.")
if isinstance(titiler_endpoint, str):
r = requests.get(
f"{titiler_endpoint}/mosaicjson/info",
params=kwargs,
).json()
else:
raise ValueError("titiler_endpoint must be a string.")
return r
mosaic_info_geojson(url, titiler_endpoint=None, **kwargs)
¶
Get the info of a MosaicJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a MosaicJSON. |
required |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
dict |
A dictionary representing a dict of GeoJSON. |
Source code in leafmap/common.py
def mosaic_info_geojson(url, titiler_endpoint=None, **kwargs):
"""Get the info of a MosaicJSON.
Args:
url (str): HTTP URL to a MosaicJSON.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz". Defaults to None.
Returns:
dict: A dictionary representing a dict of GeoJSON.
"""
if titiler_endpoint is None:
titiler_endpoint = "https://titiler.xyz"
if isinstance(url, str) and url.startswith("http"):
kwargs["url"] = url
else:
raise ValueError("url must be a string and start with http.")
if isinstance(titiler_endpoint, str):
r = requests.get(
f"{titiler_endpoint}/mosaicjson/info.geojson",
params=kwargs,
).json()
else:
raise ValueError("titiler_endpoint must be a string.")
return r
mosaic_tile(url, titiler_endpoint=None, **kwargs)
¶
Get the tile URL from a MosaicJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a MosaicJSON. |
required |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
str |
The tile URL. |
Source code in leafmap/common.py
def mosaic_tile(url, titiler_endpoint=None, **kwargs):
"""Get the tile URL from a MosaicJSON.
Args:
url (str): HTTP URL to a MosaicJSON.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz". Defaults to None.
Returns:
str: The tile URL.
"""
if titiler_endpoint is None:
titiler_endpoint = "https://titiler.xyz"
if isinstance(url, str) and url.startswith("http"):
kwargs["url"] = url
else:
raise ValueError("url must be a string and start with http.")
if isinstance(titiler_endpoint, str):
r = requests.get(
f"{titiler_endpoint}/mosaicjson/tilejson.json",
params=kwargs,
).json()
else:
raise ValueError("titiler_endpoint must be a string.")
return r["tiles"][0]
netcdf_tile_layer(filename, variables=None, palette=None, vmin=None, vmax=None, nodata=None, port='default', debug=False, projection='EPSG:3857', attribution=None, tile_format='ipyleaflet', layer_name='NetCDF layer', return_client=False, shift_lon=True, lat='lat', lon='lon', **kwargs)
¶
Generate an ipyleaflet/folium TileLayer from a netCDF file. If you are using this function in JupyterHub on a remote server (e.g., Binder, Microsoft Planetary Computer), try adding to following two lines to the beginning of the notebook if the raster does not render properly.
1 2 |
|
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filename |
str |
File path or HTTP URL to the netCDF file. |
required |
variables |
int |
The variable/band names to extract data from the netCDF file. Defaults to None. If None, all variables will be extracted. |
None |
port |
str |
The port to use for the server. Defaults to "default". |
'default' |
palette |
str |
The name of the color palette from |
None |
vmin |
float |
The minimum value to use when colormapping the palette when plotting a single band. Defaults to None. |
None |
vmax |
float |
The maximum value to use when colormapping the palette when plotting a single band. Defaults to None. |
None |
nodata |
float |
The value from the band to use to interpret as not valid data. Defaults to None. |
None |
debug |
bool |
If True, the server will be started in debug mode. Defaults to False. |
False |
projection |
str |
The projection of the GeoTIFF. Defaults to "EPSG:3857". |
'EPSG:3857' |
attribution |
str |
Attribution for the source raster. This defaults to a message about it being a local file.. Defaults to None. |
None |
tile_format |
str |
The tile layer format. Can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
layer_name |
str |
The layer name to use. Defaults to "NetCDF layer". |
'NetCDF layer' |
return_client |
bool |
If True, the tile client will be returned. Defaults to False. |
False |
shift_lon |
bool |
Flag to shift longitude values from [0, 360] to the range [-180, 180]. Defaults to True. |
True |
lat |
str |
Name of the latitude variable. Defaults to 'lat'. |
'lat' |
lon |
str |
Name of the longitude variable. Defaults to 'lon'. |
'lon' |
Returns:
Type | Description |
---|---|
ipyleaflet.TileLayer | folium.TileLayer |
An ipyleaflet.TileLayer or folium.TileLayer. |
Source code in leafmap/common.py
def netcdf_tile_layer(
filename,
variables=None,
palette=None,
vmin=None,
vmax=None,
nodata=None,
port="default",
debug=False,
projection="EPSG:3857",
attribution=None,
tile_format="ipyleaflet",
layer_name="NetCDF layer",
return_client=False,
shift_lon=True,
lat="lat",
lon="lon",
**kwargs,
):
"""Generate an ipyleaflet/folium TileLayer from a netCDF file.
If you are using this function in JupyterHub on a remote server (e.g., Binder, Microsoft Planetary Computer),
try adding to following two lines to the beginning of the notebook if the raster does not render properly.
import os
os.environ['LOCALTILESERVER_CLIENT_PREFIX'] = f'{os.environ['JUPYTERHUB_SERVICE_PREFIX'].lstrip('/')}/proxy/{{port}}'
Args:
filename (str): File path or HTTP URL to the netCDF file.
variables (int, optional): The variable/band names to extract data from the netCDF file. Defaults to None. If None, all variables will be extracted.
port (str, optional): The port to use for the server. Defaults to "default".
palette (str, optional): The name of the color palette from `palettable` to use when plotting a single band. See https://jiffyclub.github.io/palettable. Default is greyscale
vmin (float, optional): The minimum value to use when colormapping the palette when plotting a single band. Defaults to None.
vmax (float, optional): The maximum value to use when colormapping the palette when plotting a single band. Defaults to None.
nodata (float, optional): The value from the band to use to interpret as not valid data. Defaults to None.
debug (bool, optional): If True, the server will be started in debug mode. Defaults to False.
projection (str, optional): The projection of the GeoTIFF. Defaults to "EPSG:3857".
attribution (str, optional): Attribution for the source raster. This defaults to a message about it being a local file.. Defaults to None.
tile_format (str, optional): The tile layer format. Can be either ipyleaflet or folium. Defaults to "ipyleaflet".
layer_name (str, optional): The layer name to use. Defaults to "NetCDF layer".
return_client (bool, optional): If True, the tile client will be returned. Defaults to False.
shift_lon (bool, optional): Flag to shift longitude values from [0, 360] to the range [-180, 180]. Defaults to True.
lat (str, optional): Name of the latitude variable. Defaults to 'lat'.
lon (str, optional): Name of the longitude variable. Defaults to 'lon'.
Returns:
ipyleaflet.TileLayer | folium.TileLayer: An ipyleaflet.TileLayer or folium.TileLayer.
"""
check_package(
"localtileserver", URL="https://github.com/banesullivan/localtileserver"
)
try:
import xarray as xr
except ImportError as e:
raise ImportError(e)
if filename.startswith("http"):
filename = download_file(filename)
if not os.path.exists(filename):
raise FileNotFoundError(f"{filename} does not exist.")
output = filename.replace(".nc", ".tif")
xds = xr.open_dataset(filename, **kwargs)
if shift_lon:
xds.coords[lon] = (xds.coords[lon] + 180) % 360 - 180
xds = xds.sortby(xds.lon)
allowed_vars = list(xds.data_vars.keys())
if isinstance(variables, str):
if variables not in allowed_vars:
raise ValueError(f"{variables} is not a subset of {allowed_vars}.")
variables = [variables]
if variables is not None and len(variables) > 3:
raise ValueError("Only 3 variables can be plotted at a time.")
if variables is not None and (not set(variables).issubset(allowed_vars)):
raise ValueError(f"{variables} must be a subset of {allowed_vars}.")
xds.rio.set_spatial_dims(x_dim=lon, y_dim=lat).rio.to_raster(output)
if variables is None:
if len(allowed_vars) >= 3:
band_idx = [1, 2, 3]
else:
band_idx = [1]
else:
band_idx = [allowed_vars.index(var) + 1 for var in variables]
tile_layer = get_local_tile_layer(
output,
port=port,
debug=debug,
projection=projection,
band=band_idx,
palette=palette,
vmin=vmin,
vmax=vmax,
nodata=nodata,
attribution=attribution,
tile_format=tile_format,
layer_name=layer_name,
return_client=return_client,
)
return tile_layer
netcdf_to_tif(filename, output=None, variables=None, shift_lon=True, lat='lat', lon='lon', lev='lev', level_index=0, time=0, return_vars=False, **kwargs)
¶
Convert a netcdf file to a GeoTIFF file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filename |
str |
Path to the netcdf file. |
required |
output |
str |
Path to the output GeoTIFF file. Defaults to None. If None, the output file will be the same as the input file with the extension changed to .tif. |
None |
variables |
str | list |
Name of the variable or a list of variables to extract. Defaults to None. If None, all variables will be extracted. |
None |
shift_lon |
bool |
Flag to shift longitude values from [0, 360] to the range [-180, 180]. Defaults to True. |
True |
lat |
str |
Name of the latitude variable. Defaults to 'lat'. |
'lat' |
lon |
str |
Name of the longitude variable. Defaults to 'lon'. |
'lon' |
lev |
str |
Name of the level variable. Defaults to 'lev'. |
'lev' |
level_index |
int |
Index of the level dimension. Defaults to 0'. |
0 |
time |
int |
Index of the time dimension. Defaults to 0'. |
0 |
return_vars |
bool |
Flag to return all variables. Defaults to False. |
False |
Exceptions:
Type | Description |
---|---|
ImportError |
If the xarray or rioxarray package is not installed. |
FileNotFoundError |
If the netcdf file is not found. |
ValueError |
If the variable is not found in the netcdf file. |
Source code in leafmap/common.py
def netcdf_to_tif(
filename,
output=None,
variables=None,
shift_lon=True,
lat="lat",
lon="lon",
lev="lev",
level_index=0,
time=0,
return_vars=False,
**kwargs,
):
"""Convert a netcdf file to a GeoTIFF file.
Args:
filename (str): Path to the netcdf file.
output (str, optional): Path to the output GeoTIFF file. Defaults to None. If None, the output file will be the same as the input file with the extension changed to .tif.
variables (str | list, optional): Name of the variable or a list of variables to extract. Defaults to None. If None, all variables will be extracted.
shift_lon (bool, optional): Flag to shift longitude values from [0, 360] to the range [-180, 180]. Defaults to True.
lat (str, optional): Name of the latitude variable. Defaults to 'lat'.
lon (str, optional): Name of the longitude variable. Defaults to 'lon'.
lev (str, optional): Name of the level variable. Defaults to 'lev'.
level_index (int, optional): Index of the level dimension. Defaults to 0'.
time (int, optional): Index of the time dimension. Defaults to 0'.
return_vars (bool, optional): Flag to return all variables. Defaults to False.
Raises:
ImportError: If the xarray or rioxarray package is not installed.
FileNotFoundError: If the netcdf file is not found.
ValueError: If the variable is not found in the netcdf file.
"""
try:
import xarray as xr
except ImportError as e:
raise ImportError(e)
if filename.startswith("http"):
filename = download_file(filename)
if not os.path.exists(filename):
raise FileNotFoundError(f"{filename} does not exist.")
if output is None:
ext = os.path.splitext(filename)[1].lower()
if ext not in [".nc", ".nc4"]:
raise TypeError(
"The output file must be a netCDF with extension .nc or .nc4."
)
output = filename.replace(ext, ".tif")
else:
output = check_file_path(output)
xds = xr.open_dataset(filename, **kwargs)
coords = list(xds.coords.keys())
if "time" in coords:
xds = xds.isel(time=time, drop=True)
if lev in coords:
xds = xds.isel(lev=level_index, drop=True)
if shift_lon:
xds.coords[lon] = (xds.coords[lon] + 180) % 360 - 180
xds = xds.sortby(xds.lon)
allowed_vars = list(xds.data_vars.keys())
if isinstance(variables, str):
if variables not in allowed_vars:
raise ValueError(f"{variables} is not a valid variable.")
variables = [variables]
if variables is not None and (not set(variables).issubset(allowed_vars)):
raise ValueError(f"{variables} must be a subset of {allowed_vars}.")
if variables is None:
xds.rio.set_spatial_dims(x_dim=lon, y_dim=lat).rio.to_raster(output)
else:
xds[variables].rio.set_spatial_dims(x_dim=lon, y_dim=lat).rio.to_raster(output)
if return_vars:
return output, allowed_vars
else:
return output
numpy_to_cog(np_array, out_cog, bounds=None, profile=None, dtype=None, crs='epsg:4326')
¶
Converts a numpy array to a COG file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
np_array |
np.array |
A numpy array representing the image. |
required |
out_cog |
str |
The output COG file path. |
required |
bounds |
tuple |
The bounds of the image in the format of (minx, miny, maxx, maxy). Defaults to None. |
None |
profile |
str | dict |
File path to an existing COG file or a dictionary representing the profile. Defaults to None. |
None |
dtype |
str |
The data type of the output COG file. Defaults to None. |
None |
crs |
str |
The coordinate reference system of the output COG file. Defaults to "epsg:4326". |
'epsg:4326' |
Source code in leafmap/common.py
def numpy_to_cog(
np_array, out_cog, bounds=None, profile=None, dtype=None, crs="epsg:4326"
):
"""Converts a numpy array to a COG file.
Args:
np_array (np.array): A numpy array representing the image.
out_cog (str): The output COG file path.
bounds (tuple, optional): The bounds of the image in the format of (minx, miny, maxx, maxy). Defaults to None.
profile (str | dict, optional): File path to an existing COG file or a dictionary representing the profile. Defaults to None.
dtype (str, optional): The data type of the output COG file. Defaults to None.
crs (str, optional): The coordinate reference system of the output COG file. Defaults to "epsg:4326".
"""
import warnings
import numpy as np
import rasterio
from rasterio.io import MemoryFile
from rasterio.transform import from_bounds
from rio_cogeo.cogeo import cog_translate
from rio_cogeo.profiles import cog_profiles
warnings.filterwarnings("ignore")
if not isinstance(np_array, np.ndarray):
raise TypeError("The input array must be a numpy array.")
out_dir = os.path.dirname(out_cog)
check_dir(out_dir)
if profile is not None:
if isinstance(profile, str):
if not os.path.exists(profile):
raise FileNotFoundError("The provided file could not be found.")
with rasterio.open(profile) as ds:
bounds = ds.bounds
elif isinstance(profile, rasterio.profiles.Profile):
profile = dict(profile)
elif not isinstance(profile, dict):
raise TypeError("The provided profile must be a file path or a dictionary.")
if bounds is None:
bounds = (-180.0, -85.0511287798066, 180.0, 85.0511287798066)
if not isinstance(bounds, tuple) and len(bounds) != 4:
raise TypeError("The provided bounds must be a tuple of length 4.")
# Rasterio uses numpy array of shape of `(bands, height, width)`
if len(np_array.shape) == 3:
nbands = np_array.shape[0]
height = np_array.shape[1]
width = np_array.shape[2]
elif len(np_array.shape) == 2:
nbands = 1
height = np_array.shape[0]
width = np_array.shape[1]
np_array = np_array.reshape((1, height, width))
else:
raise ValueError("The input array must be a 2D or 3D numpy array.")
src_transform = from_bounds(*bounds, width=width, height=height)
if dtype is None:
dtype = str(np_array.dtype)
if isinstance(profile, dict):
src_profile = profile
src_profile["count"] = nbands
else:
src_profile = dict(
driver="GTiff",
dtype=dtype,
count=nbands,
height=height,
width=width,
crs=crs,
transform=src_transform,
)
with MemoryFile() as memfile:
with memfile.open(**src_profile) as mem:
# Populate the input file with numpy array
mem.write(np_array)
dst_profile = cog_profiles.get("deflate")
cog_translate(
mem,
out_cog,
dst_profile,
in_memory=True,
quiet=True,
)
open_image_from_url(url)
¶
Loads an image from the specified URL.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
URL of the image. |
required |
Returns:
Type | Description |
---|---|
object |
Image object. |
Source code in leafmap/common.py
def open_image_from_url(url):
"""Loads an image from the specified URL.
Args:
url (str): URL of the image.
Returns:
object: Image object.
"""
from PIL import Image
from io import BytesIO
# from urllib.parse import urlparse
try:
response = requests.get(url)
img = Image.open(BytesIO(response.content))
return img
except Exception as e:
print(e)
pandas_to_geojson(df, out_geojson=None, latitude='latitude', longitude='longitude', encoding='utf-8')
¶
Creates points for a Pandas DataFrame and exports data as a GeoJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
df |
pandas.DataFrame |
The input Pandas DataFrame. |
required |
out_geojson |
str |
The file path to the exported GeoJSON. Default to None. |
None |
latitude |
str |
The name of the column containing latitude coordinates. Defaults to "latitude". |
'latitude' |
longitude |
str |
The name of the column containing longitude coordinates. Defaults to "longitude". |
'longitude' |
encoding |
str |
The encoding of characters. Defaults to "utf-8". |
'utf-8' |
Source code in leafmap/common.py
def pandas_to_geojson(
df,
out_geojson=None,
latitude="latitude",
longitude="longitude",
encoding="utf-8",
):
"""Creates points for a Pandas DataFrame and exports data as a GeoJSON.
Args:
df (pandas.DataFrame): The input Pandas DataFrame.
out_geojson (str): The file path to the exported GeoJSON. Default to None.
latitude (str, optional): The name of the column containing latitude coordinates. Defaults to "latitude".
longitude (str, optional): The name of the column containing longitude coordinates. Defaults to "longitude".
encoding (str, optional): The encoding of characters. Defaults to "utf-8".
"""
import json
from geojson import Feature, FeatureCollection, Point
if out_geojson is not None:
out_dir = os.path.dirname(os.path.abspath(out_geojson))
if not os.path.exists(out_dir):
os.makedirs(out_dir)
features = df.apply(
lambda row: Feature(
geometry=Point((float(row[longitude]), float(row[latitude]))),
properties=dict(row),
),
axis=1,
).tolist()
geojson = FeatureCollection(features=features)
if out_geojson is None:
return geojson
else:
with open(out_geojson, "w", encoding=encoding) as f:
f.write(json.dumps(geojson))
planet_biannual_tiles_tropical(api_key=None, token_name='PLANET_API_KEY', tile_format='ipyleaflet')
¶
Generates Planet bi-annual imagery TileLayer based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
tile_format |
str |
The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the tile layer format is invalid. |
Returns:
Type | Description |
---|---|
dict |
A dictionary of TileLayer. |
Source code in leafmap/common.py
def planet_biannual_tiles_tropical(
api_key=None, token_name="PLANET_API_KEY", tile_format="ipyleaflet"
):
"""Generates Planet bi-annual imagery TileLayer based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
tile_format (str, optional): The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet".
Raises:
ValueError: If the tile layer format is invalid.
Returns:
dict: A dictionary of TileLayer.
"""
if tile_format not in ["ipyleaflet", "folium"]:
raise ValueError("The tile format must be either ipyleaflet or folium.")
tiles = {}
link = planet_biannual_tropical(api_key, token_name)
for url in link:
index = url.find("20")
name = "Planet_" + url[index : index + 15]
if tile_format == "ipyleaflet":
tile = ipyleaflet.TileLayer(url=url, attribution="Planet", name=name)
else:
tile = folium.TileLayer(
tiles=url,
attr="Planet",
name=name,
overlay=True,
control=True,
)
tiles[name] = tile
return tiles
planet_biannual_tropical(api_key=None, token_name='PLANET_API_KEY')
¶
Generates Planet bi-annual imagery URLs based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the API key could not be found. |
Returns:
Type | Description |
---|---|
list |
A list of tile URLs. |
Source code in leafmap/common.py
def planet_biannual_tropical(api_key=None, token_name="PLANET_API_KEY"):
"""Generates Planet bi-annual imagery URLs based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
Raises:
ValueError: If the API key could not be found.
Returns:
list: A list of tile URLs.
"""
if api_key is None:
api_key = os.environ.get(token_name)
if api_key is None:
raise ValueError("The Planet API Key must be provided.")
dates = [
"2015-12_2016-05",
"2016-06_2016-11",
"2016-12_2017-05",
"2017-06_2017-11",
"2017-12_2018-05",
"2018-06_2018-11",
"2018-12_2019-05",
"2019-06_2019-11",
"2019-12_2020-05",
"2020-06_2020-08",
]
link = []
prefix = "https://tiles.planet.com/basemaps/v1/planet-tiles/planet_medres_normalized_analytic_"
subfix = "_mosaic/gmap/{z}/{x}/{y}.png?api_key="
for d in dates:
url = f"{prefix}{d}{subfix}{api_key}"
link.append(url)
return link
planet_by_month(year=2016, month=1, api_key=None, token_name='PLANET_API_KEY')
¶
Gets Planet global mosaic tile url by month. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Parameters:
Name | Type | Description | Default |
---|---|---|---|
year |
int |
The year of Planet global mosaic, must be >=2016. Defaults to 2016. |
2016 |
month |
int |
The month of Planet global mosaic, must be 1-12. Defaults to 1. |
1 |
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
Exceptions:
Type | Description |
---|---|
ValueError |
The Planet API key is not provided. |
ValueError |
The year is invalid. |
ValueError |
The month is invalid. |
ValueError |
The month is invalid. |
Returns:
Type | Description |
---|---|
str |
A Planet global mosaic tile url. |
Source code in leafmap/common.py
def planet_by_month(
year=2016,
month=1,
api_key=None,
token_name="PLANET_API_KEY",
):
"""Gets Planet global mosaic tile url by month. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Args:
year (int, optional): The year of Planet global mosaic, must be >=2016. Defaults to 2016.
month (int, optional): The month of Planet global mosaic, must be 1-12. Defaults to 1.
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
Raises:
ValueError: The Planet API key is not provided.
ValueError: The year is invalid.
ValueError: The month is invalid.
ValueError: The month is invalid.
Returns:
str: A Planet global mosaic tile url.
"""
from datetime import date
if api_key is None:
api_key = os.environ.get(token_name)
if api_key is None:
raise ValueError("The Planet API Key must be provided.")
today = date.today()
year_now = int(today.strftime("%Y"))
month_now = int(today.strftime("%m"))
# quarter_now = (month_now - 1) // 3 + 1
if year > year_now:
raise ValueError(f"Year must be between 2016 and {year_now}.")
elif year == year_now and month >= month_now:
raise ValueError(f"Month must be less than {month_now} for year {year_now}")
if month < 1 or month > 12:
raise ValueError("Month must be between 1 and 12.")
prefix = "https://tiles.planet.com/basemaps/v1/planet-tiles/global_monthly_"
subfix = "_mosaic/gmap/{z}/{x}/{y}.png?api_key="
m_str = str(year) + "_" + str(month).zfill(2)
url = f"{prefix}{m_str}{subfix}{api_key}"
return url
planet_by_quarter(year=2016, quarter=1, api_key=None, token_name='PLANET_API_KEY')
¶
Gets Planet global mosaic tile url by quarter. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Parameters:
Name | Type | Description | Default |
---|---|---|---|
year |
int |
The year of Planet global mosaic, must be >=2016. Defaults to 2016. |
2016 |
quarter |
int |
The quarter of Planet global mosaic, must be 1-4. Defaults to 1. |
1 |
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
Exceptions:
Type | Description |
---|---|
ValueError |
The Planet API key is not provided. |
ValueError |
The year is invalid. |
ValueError |
The quarter is invalid. |
ValueError |
The quarter is invalid. |
Returns:
Type | Description |
---|---|
str |
A Planet global mosaic tile url. |
Source code in leafmap/common.py
def planet_by_quarter(
year=2016,
quarter=1,
api_key=None,
token_name="PLANET_API_KEY",
):
"""Gets Planet global mosaic tile url by quarter. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Args:
year (int, optional): The year of Planet global mosaic, must be >=2016. Defaults to 2016.
quarter (int, optional): The quarter of Planet global mosaic, must be 1-4. Defaults to 1.
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
Raises:
ValueError: The Planet API key is not provided.
ValueError: The year is invalid.
ValueError: The quarter is invalid.
ValueError: The quarter is invalid.
Returns:
str: A Planet global mosaic tile url.
"""
from datetime import date
if api_key is None:
api_key = os.environ.get(token_name)
if api_key is None:
raise ValueError("The Planet API Key must be provided.")
today = date.today()
year_now = int(today.strftime("%Y"))
month_now = int(today.strftime("%m"))
quarter_now = (month_now - 1) // 3 + 1
if year > year_now:
raise ValueError(f"Year must be between 2016 and {year_now}.")
elif year == year_now and quarter >= quarter_now:
raise ValueError(f"Quarter must be less than {quarter_now} for year {year_now}")
if quarter < 1 or quarter > 4:
raise ValueError("Quarter must be between 1 and 4.")
prefix = "https://tiles.planet.com/basemaps/v1/planet-tiles/global_quarterly_"
subfix = "_mosaic/gmap/{z}/{x}/{y}.png?api_key="
m_str = str(year) + "q" + str(quarter)
url = f"{prefix}{m_str}{subfix}{api_key}"
return url
planet_catalog(api_key=None, token_name='PLANET_API_KEY')
¶
Generates Planet bi-annual and monthly imagery URLs based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
Returns:
Type | Description |
---|---|
list |
A list of tile URLs. |
Source code in leafmap/common.py
def planet_catalog(api_key=None, token_name="PLANET_API_KEY"):
"""Generates Planet bi-annual and monthly imagery URLs based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
Returns:
list: A list of tile URLs.
"""
quarterly = planet_quarterly(api_key, token_name)
monthly = planet_monthly(api_key, token_name)
return quarterly + monthly
planet_catalog_tropical(api_key=None, token_name='PLANET_API_KEY')
¶
Generates Planet bi-annual and monthly imagery URLs based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
Returns:
Type | Description |
---|---|
list |
A list of tile URLs. |
Source code in leafmap/common.py
def planet_catalog_tropical(api_key=None, token_name="PLANET_API_KEY"):
"""Generates Planet bi-annual and monthly imagery URLs based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
Returns:
list: A list of tile URLs.
"""
biannual = planet_biannual_tropical(api_key, token_name)
monthly = planet_monthly_tropical(api_key, token_name)
return biannual + monthly
planet_monthly(api_key=None, token_name='PLANET_API_KEY')
¶
Generates Planet monthly imagery URLs based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the API key could not be found. |
Returns:
Type | Description |
---|---|
list |
A list of tile URLs. |
Source code in leafmap/common.py
def planet_monthly(api_key=None, token_name="PLANET_API_KEY"):
"""Generates Planet monthly imagery URLs based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
Raises:
ValueError: If the API key could not be found.
Returns:
list: A list of tile URLs.
"""
from datetime import date
if api_key is None:
api_key = os.environ.get(token_name)
if api_key is None:
raise ValueError("The Planet API Key must be provided.")
today = date.today()
year_now = int(today.strftime("%Y"))
month_now = int(today.strftime("%m"))
link = []
prefix = "https://tiles.planet.com/basemaps/v1/planet-tiles/global_monthly_"
subfix = "_mosaic/gmap/{z}/{x}/{y}.png?api_key="
for year in range(2016, year_now + 1):
for month in range(1, 13):
m_str = str(year) + "_" + str(month).zfill(2)
if year == year_now and month >= month_now:
break
url = f"{prefix}{m_str}{subfix}{api_key}"
link.append(url)
return link
planet_monthly_tiles(api_key=None, token_name='PLANET_API_KEY', tile_format='ipyleaflet')
¶
Generates Planet monthly imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
tile_format |
str |
The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the tile layer format is invalid. |
Returns:
Type | Description |
---|---|
dict |
A dictionary of TileLayer. |
Source code in leafmap/common.py
def planet_monthly_tiles(
api_key=None, token_name="PLANET_API_KEY", tile_format="ipyleaflet"
):
"""Generates Planet monthly imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
tile_format (str, optional): The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet".
Raises:
ValueError: If the tile layer format is invalid.
Returns:
dict: A dictionary of TileLayer.
"""
if tile_format not in ["ipyleaflet", "folium"]:
raise ValueError("The tile format must be either ipyleaflet or folium.")
tiles = {}
link = planet_monthly(api_key, token_name)
for url in link:
index = url.find("20")
name = "Planet_" + url[index : index + 7]
if tile_format == "ipyleaflet":
tile = ipyleaflet.TileLayer(url=url, attribution="Planet", name=name)
else:
tile = folium.TileLayer(
tiles=url,
attr="Planet",
name=name,
overlay=True,
control=True,
)
tiles[name] = tile
return tiles
planet_monthly_tiles_tropical(api_key=None, token_name='PLANET_API_KEY', tile_format='ipyleaflet')
¶
Generates Planet monthly imagery TileLayer based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
tile_format |
str |
The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the tile layer format is invalid. |
Returns:
Type | Description |
---|---|
dict |
A dictionary of TileLayer. |
Source code in leafmap/common.py
def planet_monthly_tiles_tropical(
api_key=None, token_name="PLANET_API_KEY", tile_format="ipyleaflet"
):
"""Generates Planet monthly imagery TileLayer based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
tile_format (str, optional): The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet".
Raises:
ValueError: If the tile layer format is invalid.
Returns:
dict: A dictionary of TileLayer.
"""
if tile_format not in ["ipyleaflet", "folium"]:
raise ValueError("The tile format must be either ipyleaflet or folium.")
tiles = {}
link = planet_monthly_tropical(api_key, token_name)
for url in link:
index = url.find("20")
name = "Planet_" + url[index : index + 7]
if tile_format == "ipyleaflet":
tile = ipyleaflet.TileLayer(url=url, attribution="Planet", name=name)
else:
tile = folium.TileLayer(
tiles=url,
attr="Planet",
name=name,
overlay=True,
control=True,
)
tiles[name] = tile
return tiles
planet_monthly_tropical(api_key=None, token_name='PLANET_API_KEY')
¶
Generates Planet monthly imagery URLs based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the API key could not be found. |
Returns:
Type | Description |
---|---|
list |
A list of tile URLs. |
Source code in leafmap/common.py
def planet_monthly_tropical(api_key=None, token_name="PLANET_API_KEY"):
"""Generates Planet monthly imagery URLs based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
Raises:
ValueError: If the API key could not be found.
Returns:
list: A list of tile URLs.
"""
from datetime import date
if api_key is None:
api_key = os.environ.get(token_name)
if api_key is None:
raise ValueError("The Planet API Key must be provided.")
today = date.today()
year_now = int(today.strftime("%Y"))
month_now = int(today.strftime("%m"))
links = []
prefix = "https://tiles.planet.com/basemaps/v1/planet-tiles/planet_medres_normalized_analytic_"
subfix = "_mosaic/gmap/{z}/{x}/{y}.png?api_key="
for year in range(2020, year_now + 1):
for month in range(1, 13):
m_str = str(year) + "-" + str(month).zfill(2)
if year == 2020 and month < 9:
continue
if year == year_now and month >= month_now:
break
url = f"{prefix}{m_str}{subfix}{api_key}"
links.append(url)
return links
planet_quarterly(api_key=None, token_name='PLANET_API_KEY')
¶
Generates Planet quarterly imagery URLs based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the API key could not be found. |
Returns:
Type | Description |
---|---|
list |
A list of tile URLs. |
Source code in leafmap/common.py
def planet_quarterly(api_key=None, token_name="PLANET_API_KEY"):
"""Generates Planet quarterly imagery URLs based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
Raises:
ValueError: If the API key could not be found.
Returns:
list: A list of tile URLs.
"""
from datetime import date
if api_key is None:
api_key = os.environ.get(token_name)
if api_key is None:
raise ValueError("The Planet API Key must be provided.")
today = date.today()
year_now = int(today.strftime("%Y"))
month_now = int(today.strftime("%m"))
quarter_now = (month_now - 1) // 3 + 1
link = []
prefix = "https://tiles.planet.com/basemaps/v1/planet-tiles/global_quarterly_"
subfix = "_mosaic/gmap/{z}/{x}/{y}.png?api_key="
for year in range(2016, year_now + 1):
for quarter in range(1, 5):
m_str = str(year) + "q" + str(quarter)
if year == year_now and quarter >= quarter_now:
break
url = f"{prefix}{m_str}{subfix}{api_key}"
link.append(url)
return link
planet_quarterly_tiles(api_key=None, token_name='PLANET_API_KEY', tile_format='ipyleaflet')
¶
Generates Planet quarterly imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
tile_format |
str |
The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the tile layer format is invalid. |
Returns:
Type | Description |
---|---|
dict |
A dictionary of TileLayer. |
Source code in leafmap/common.py
def planet_quarterly_tiles(
api_key=None, token_name="PLANET_API_KEY", tile_format="ipyleaflet"
):
"""Generates Planet quarterly imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
tile_format (str, optional): The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet".
Raises:
ValueError: If the tile layer format is invalid.
Returns:
dict: A dictionary of TileLayer.
"""
if tile_format not in ["ipyleaflet", "folium"]:
raise ValueError("The tile format must be either ipyleaflet or folium.")
tiles = {}
links = planet_quarterly(api_key, token_name)
for url in links:
index = url.find("20")
name = "Planet_" + url[index : index + 6]
if tile_format == "ipyleaflet":
tile = ipyleaflet.TileLayer(url=url, attribution="Planet", name=name)
else:
tile = folium.TileLayer(
tiles=url,
attr="Planet",
name=name,
overlay=True,
control=True,
)
tiles[name] = tile
return tiles
planet_tile_by_month(year=2016, month=1, name=None, api_key=None, token_name='PLANET_API_KEY', tile_format='ipyleaflet')
¶
Generates Planet monthly imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis
Parameters:
Name | Type | Description | Default |
---|---|---|---|
year |
int |
The year of Planet global mosaic, must be >=2016. Defaults to 2016. |
2016 |
month |
int |
The month of Planet global mosaic, must be 1-12. Defaults to 1. |
1 |
name |
str |
The layer name to use. Defaults to None. |
None |
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
tile_format |
str |
The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the tile layer format is invalid. |
Returns:
Type | Description |
---|---|
dict |
A dictionary of TileLayer. |
Source code in leafmap/common.py
def planet_tile_by_month(
year=2016,
month=1,
name=None,
api_key=None,
token_name="PLANET_API_KEY",
tile_format="ipyleaflet",
):
"""Generates Planet monthly imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis
Args:
year (int, optional): The year of Planet global mosaic, must be >=2016. Defaults to 2016.
month (int, optional): The month of Planet global mosaic, must be 1-12. Defaults to 1.
name (str, optional): The layer name to use. Defaults to None.
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
tile_format (str, optional): The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet".
Raises:
ValueError: If the tile layer format is invalid.
Returns:
dict: A dictionary of TileLayer.
"""
if tile_format not in ["ipyleaflet", "folium"]:
raise ValueError("The tile format must be either ipyleaflet or folium.")
url = planet_by_month(year, month, api_key, token_name)
if name is None:
name = "Planet_" + str(year) + "_" + str(month).zfill(2)
if tile_format == "ipyleaflet":
tile = ipyleaflet.TileLayer(url=url, attribution="Planet", name=name)
else:
tile = folium.TileLayer(
tiles=url,
attr="Planet",
name=name,
overlay=True,
control=True,
)
return tile
planet_tile_by_quarter(year=2016, quarter=1, name=None, api_key=None, token_name='PLANET_API_KEY', tile_format='ipyleaflet')
¶
Generates Planet quarterly imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis
Parameters:
Name | Type | Description | Default |
---|---|---|---|
year |
int |
The year of Planet global mosaic, must be >=2016. Defaults to 2016. |
2016 |
quarter |
int |
The quarter of Planet global mosaic, must be 1-4. Defaults to 1. |
1 |
name |
str |
The layer name to use. Defaults to None. |
None |
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
tile_format |
str |
The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the tile layer format is invalid. |
Returns:
Type | Description |
---|---|
dict |
A dictionary of TileLayer. |
Source code in leafmap/common.py
def planet_tile_by_quarter(
year=2016,
quarter=1,
name=None,
api_key=None,
token_name="PLANET_API_KEY",
tile_format="ipyleaflet",
):
"""Generates Planet quarterly imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis
Args:
year (int, optional): The year of Planet global mosaic, must be >=2016. Defaults to 2016.
quarter (int, optional): The quarter of Planet global mosaic, must be 1-4. Defaults to 1.
name (str, optional): The layer name to use. Defaults to None.
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
tile_format (str, optional): The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet".
Raises:
ValueError: If the tile layer format is invalid.
Returns:
dict: A dictionary of TileLayer.
"""
if tile_format not in ["ipyleaflet", "folium"]:
raise ValueError("The tile format must be either ipyleaflet or folium.")
url = planet_by_quarter(year, quarter, api_key, token_name)
if name is None:
name = "Planet_" + str(year) + "_q" + str(quarter)
if tile_format == "ipyleaflet":
tile = ipyleaflet.TileLayer(url=url, attribution="Planet", name=name)
else:
tile = folium.TileLayer(
tiles=url,
attr="Planet",
name=name,
overlay=True,
control=True,
)
return tile
planet_tiles(api_key=None, token_name='PLANET_API_KEY', tile_format='ipyleaflet')
¶
Generates Planet imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
tile_format |
str |
The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the tile layer format is invalid. |
Returns:
Type | Description |
---|---|
dict |
A dictionary of TileLayer. |
Source code in leafmap/common.py
def planet_tiles(api_key=None, token_name="PLANET_API_KEY", tile_format="ipyleaflet"):
"""Generates Planet imagery TileLayer based on an API key. To get a Planet API key, see https://developers.planet.com/quickstart/apis/
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
tile_format (str, optional): The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet".
Raises:
ValueError: If the tile layer format is invalid.
Returns:
dict: A dictionary of TileLayer.
"""
catalog = {}
quarterly = planet_quarterly_tiles(api_key, token_name, tile_format)
monthly = planet_monthly_tiles(api_key, token_name, tile_format)
for key in quarterly:
catalog[key] = quarterly[key]
for key in monthly:
catalog[key] = monthly[key]
return catalog
planet_tiles_tropical(api_key=None, token_name='PLANET_API_KEY', tile_format='ipyleaflet')
¶
Generates Planet monthly imagery TileLayer based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_key |
str |
The Planet API key. Defaults to None. |
None |
token_name |
str |
The environment variable name of the API key. Defaults to "PLANET_API_KEY". |
'PLANET_API_KEY' |
tile_format |
str |
The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet". |
'ipyleaflet' |
Exceptions:
Type | Description |
---|---|
ValueError |
If the tile layer format is invalid. |
Returns:
Type | Description |
---|---|
dict |
A dictionary of TileLayer. |
Source code in leafmap/common.py
def planet_tiles_tropical(
api_key=None, token_name="PLANET_API_KEY", tile_format="ipyleaflet"
):
"""Generates Planet monthly imagery TileLayer based on an API key. See https://assets.planet.com/docs/NICFI_UserGuidesFAQ.pdf
Args:
api_key (str, optional): The Planet API key. Defaults to None.
token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
tile_format (str, optional): The TileLayer format, can be either ipyleaflet or folium. Defaults to "ipyleaflet".
Raises:
ValueError: If the tile layer format is invalid.
Returns:
dict: A dictionary of TileLayer.
"""
catalog = {}
biannul = planet_biannual_tiles_tropical(api_key, token_name, tile_format)
monthly = planet_monthly_tiles_tropical(api_key, token_name, tile_format)
for key in biannul:
catalog[key] = biannul[key]
for key in monthly:
catalog[key] = monthly[key]
return catalog
plot_raster(image, band=None, cmap='terrain', proj='EPSG:3857', figsize=None, open_kwargs={}, **kwargs)
¶
Plot a raster image.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
image |
str | xarray.DataArray |
The input raster image, can be a file path, HTTP URL, or xarray.DataArray. |
required |
band |
int |
The band index, starting from zero. Defaults to None. |
None |
cmap |
str |
The matplotlib colormap to use. Defaults to "terrain". |
'terrain' |
proj |
str |
The EPSG projection code. Defaults to "EPSG:3857". |
'EPSG:3857' |
figsize |
tuple |
The figure size as a tuple, such as (10, 8). Defaults to None. |
None |
open_kwargs |
dict |
The keyword arguments to pass to rioxarray.open_rasterio. Defaults to {}. |
{} |
**kwargs |
Additional keyword arguments to pass to xarray.DataArray.plot(). |
{} |
Source code in leafmap/common.py
def plot_raster(
image,
band=None,
cmap="terrain",
proj="EPSG:3857",
figsize=None,
open_kwargs={},
**kwargs,
):
"""Plot a raster image.
Args:
image (str | xarray.DataArray ): The input raster image, can be a file path, HTTP URL, or xarray.DataArray.
band (int, optional): The band index, starting from zero. Defaults to None.
cmap (str, optional): The matplotlib colormap to use. Defaults to "terrain".
proj (str, optional): The EPSG projection code. Defaults to "EPSG:3857".
figsize (tuple, optional): The figure size as a tuple, such as (10, 8). Defaults to None.
open_kwargs (dict, optional): The keyword arguments to pass to rioxarray.open_rasterio. Defaults to {}.
**kwargs: Additional keyword arguments to pass to xarray.DataArray.plot().
"""
if os.environ.get("USE_MKDOCS") is not None:
return
try:
import pvxarray
import rioxarray
import xarray
except ImportError:
raise ImportError(
"pyxarray and rioxarray are required for plotting. Please install them using 'pip install rioxarray pyvista-xarray'."
)
if isinstance(image, str):
da = rioxarray.open_rasterio(image, **open_kwargs)
elif isinstance(image, xarray.DataArray):
da = image
else:
raise ValueError("image must be a string or xarray.Dataset.")
if band is not None:
da = da[dict(band=band)]
da = da.rio.reproject(proj)
kwargs["cmap"] = cmap
kwargs["figsize"] = figsize
da.plot(**kwargs)
plot_raster_3d(image, band=None, cmap='terrain', factor=1.0, proj='EPSG:3857', background=None, open_kwargs={}, mesh_kwargs={}, **kwargs)
¶
Plot a raster image in 3D.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
image |
str | xarray.DataArray |
The input raster image, can be a file path, HTTP URL, or xarray.DataArray. |
required |
band |
int |
The band index, starting from zero. Defaults to None. |
None |
cmap |
str |
The matplotlib colormap to use. Defaults to "terrain". |
'terrain' |
factor |
float |
The scaling factor for the raster. Defaults to 1.0. |
1.0 |
proj |
str |
The EPSG projection code. Defaults to "EPSG:3857". |
'EPSG:3857' |
background |
str |
The background color. Defaults to None. |
None |
open_kwargs |
dict |
The keyword arguments to pass to rioxarray.open_rasterio. Defaults to {}. |
{} |
mesh_kwargs |
dict |
The keyword arguments to pass to pyvista.mesh.warp_by_scalar(). Defaults to {}. |
{} |
**kwargs |
Additional keyword arguments to pass to xarray.DataArray.plot(). |
{} |
Source code in leafmap/common.py
def plot_raster_3d(
image,
band=None,
cmap="terrain",
factor=1.0,
proj="EPSG:3857",
background=None,
open_kwargs={},
mesh_kwargs={},
**kwargs,
):
"""Plot a raster image in 3D.
Args:
image (str | xarray.DataArray ): The input raster image, can be a file path, HTTP URL, or xarray.DataArray.
band (int, optional): The band index, starting from zero. Defaults to None.
cmap (str, optional): The matplotlib colormap to use. Defaults to "terrain".
factor (float, optional): The scaling factor for the raster. Defaults to 1.0.
proj (str, optional): The EPSG projection code. Defaults to "EPSG:3857".
background (str, optional): The background color. Defaults to None.
open_kwargs (dict, optional): The keyword arguments to pass to rioxarray.open_rasterio. Defaults to {}.
mesh_kwargs (dict, optional): The keyword arguments to pass to pyvista.mesh.warp_by_scalar(). Defaults to {}.
**kwargs: Additional keyword arguments to pass to xarray.DataArray.plot().
"""
if os.environ.get("USE_MKDOCS") is not None:
return
try:
import pvxarray
import pyvista
import rioxarray
import xarray
except ImportError:
raise ImportError(
"pyxarray and rioxarray are required for plotting. Please install them using 'pip install rioxarray pyvista-xarray'."
)
if isinstance(background, str):
pyvista.global_theme.background = background
if isinstance(image, str):
da = rioxarray.open_rasterio(image, **open_kwargs)
elif isinstance(image, xarray.DataArray):
da = image
else:
raise ValueError("image must be a string or xarray.Dataset.")
if band is not None:
da = da[dict(band=band)]
da = da.rio.reproject(proj)
mesh_kwargs["factor"] = factor
kwargs["cmap"] = cmap
# Grab the mesh object for use with PyVista
mesh = da.pyvista.mesh
# Warp top and plot in 3D
mesh.warp_by_scalar(**mesh_kwargs).plot(**kwargs)
points_from_xy(data, x='longitude', y='latitude', z=None, crs=None, **kwargs)
¶
Create a GeoPandas GeoDataFrame from a csv or Pandas DataFrame containing x, y, z values.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
str | pd.DataFrame |
A csv or Pandas DataFrame containing x, y, z values. |
required |
x |
str |
The column name for the x values. Defaults to "longitude". |
'longitude' |
y |
str |
The column name for the y values. Defaults to "latitude". |
'latitude' |
z |
str |
The column name for the z values. Defaults to None. |
None |
crs |
str | int |
The coordinate reference system for the GeoDataFrame. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
geopandas.GeoDataFrame |
A GeoPandas GeoDataFrame containing x, y, z values. |
Source code in leafmap/common.py
def points_from_xy(data, x="longitude", y="latitude", z=None, crs=None, **kwargs):
"""Create a GeoPandas GeoDataFrame from a csv or Pandas DataFrame containing x, y, z values.
Args:
data (str | pd.DataFrame): A csv or Pandas DataFrame containing x, y, z values.
x (str, optional): The column name for the x values. Defaults to "longitude".
y (str, optional): The column name for the y values. Defaults to "latitude".
z (str, optional): The column name for the z values. Defaults to None.
crs (str | int, optional): The coordinate reference system for the GeoDataFrame. Defaults to None.
Returns:
geopandas.GeoDataFrame: A GeoPandas GeoDataFrame containing x, y, z values.
"""
check_package(name="geopandas", URL="https://geopandas.org")
import geopandas as gpd
import pandas as pd
if crs is None:
crs = "epsg:4326"
if isinstance(data, pd.DataFrame):
df = data
elif isinstance(data, str):
if not data.startswith("http") and (not os.path.exists(data)):
raise FileNotFoundError("The specified input csv does not exist.")
else:
df = pd.read_csv(data, **kwargs)
else:
raise TypeError("The data must be a pandas DataFrame or a csv file path.")
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df[x], df[y], z=z, crs=crs))
return gdf
random_string(string_length=3)
¶
Generates a random string of fixed length.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
string_length |
int |
Fixed length. Defaults to 3. |
3 |
Returns:
Type | Description |
---|---|
str |
A random string |
Source code in leafmap/common.py
def random_string(string_length=3):
"""Generates a random string of fixed length.
Args:
string_length (int, optional): Fixed length. Defaults to 3.
Returns:
str: A random string
"""
import random
import string
# random.seed(1001)
letters = string.ascii_lowercase
return "".join(random.choice(letters) for i in range(string_length))
read_file_from_url(url, return_type='list', encoding='utf-8')
¶
Reads a file from a URL.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
The URL of the file. |
required |
return_type |
str |
The return type, can either be string or list. Defaults to "list". |
'list' |
encoding |
str |
The encoding of the file. Defaults to "utf-8". |
'utf-8' |
Exceptions:
Type | Description |
---|---|
ValueError |
The return type must be either list or string. |
Returns:
Type | Description |
---|---|
str | list |
The contents of the file. |
Source code in leafmap/common.py
def read_file_from_url(url, return_type="list", encoding="utf-8"):
"""Reads a file from a URL.
Args:
url (str): The URL of the file.
return_type (str, optional): The return type, can either be string or list. Defaults to "list".
encoding (str, optional): The encoding of the file. Defaults to "utf-8".
Raises:
ValueError: The return type must be either list or string.
Returns:
str | list: The contents of the file.
"""
from urllib.request import urlopen
if return_type == "list":
return [line.decode(encoding).rstrip() for line in urlopen(url).readlines()]
elif return_type == "string":
return urlopen(url).read().decode(encoding)
else:
raise ValueError("The return type must be either list or string.")
read_lidar(filename, **kwargs)
¶
Read a LAS file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filename |
str |
Path to a LAS file. |
required |
Returns:
Type | Description |
---|---|
LasData |
The LasData object return by laspy.read. |
Source code in leafmap/common.py
def read_lidar(filename, **kwargs):
"""Read a LAS file.
Args:
filename (str): Path to a LAS file.
Returns:
LasData: The LasData object return by laspy.read.
"""
try:
import laspy
except ImportError:
print(
"The laspy package is required for this function. Use pip install laspy to install it."
)
return
return laspy.read(filename, **kwargs)
read_netcdf(filename, **kwargs)
¶
Read a netcdf file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filename |
str |
File path or HTTP URL to the netcdf file. |
required |
Exceptions:
Type | Description |
---|---|
ImportError |
If the xarray or rioxarray package is not installed. |
FileNotFoundError |
If the netcdf file is not found. |
Returns:
Type | Description |
---|---|
xarray.Dataset |
The netcdf file as an xarray dataset. |
Source code in leafmap/common.py
def read_netcdf(filename, **kwargs):
"""Read a netcdf file.
Args:
filename (str): File path or HTTP URL to the netcdf file.
Raises:
ImportError: If the xarray or rioxarray package is not installed.
FileNotFoundError: If the netcdf file is not found.
Returns:
xarray.Dataset: The netcdf file as an xarray dataset.
"""
try:
import xarray as xr
except ImportError as e:
raise ImportError(e)
if filename.startswith("http"):
filename = download_file(filename)
if not os.path.exists(filename):
raise FileNotFoundError(f"{filename} does not exist.")
xds = xr.open_dataset(filename, **kwargs)
return xds
read_postgis(sql, con, geom_col='geom', crs=None, **kwargs)
¶
Reads data from a PostGIS database and returns a GeoDataFrame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sql |
str |
SQL query to execute in selecting entries from database, or name of the table to read from the database. |
required |
con |
sqlalchemy.engine.Engine |
Active connection to the database to query. |
required |
geom_col |
str |
Column name to convert to shapely geometries. Defaults to "geom". |
'geom' |
crs |
str | dict |
CRS to use for the returned GeoDataFrame; if not set, tries to determine CRS from the SRID associated with the first geometry in the database, and assigns that to all geometries. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
[type] |
[description] |
Source code in leafmap/common.py
def read_postgis(sql, con, geom_col="geom", crs=None, **kwargs):
"""Reads data from a PostGIS database and returns a GeoDataFrame.
Args:
sql (str): SQL query to execute in selecting entries from database, or name of the table to read from the database.
con (sqlalchemy.engine.Engine): Active connection to the database to query.
geom_col (str, optional): Column name to convert to shapely geometries. Defaults to "geom".
crs (str | dict, optional): CRS to use for the returned GeoDataFrame; if not set, tries to determine CRS from the SRID associated with the first geometry in the database, and assigns that to all geometries. Defaults to None.
Returns:
[type]: [description]
"""
check_package(name="geopandas", URL="https://geopandas.org")
import geopandas as gpd
gdf = gpd.read_postgis(sql, con, geom_col, crs, **kwargs)
return gdf
rgb_to_hex(rgb=(255, 255, 255))
¶
Converts RGB to hex color. In RGB color R stands for Red, G stands for Green, and B stands for Blue, and it ranges from the decimal value of 0 – 255.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rgb |
tuple |
RGB color code as a tuple of (red, green, blue). Defaults to (255, 255, 255). |
(255, 255, 255) |
Returns:
Type | Description |
---|---|
str |
hex color code |
Source code in leafmap/common.py
def rgb_to_hex(rgb=(255, 255, 255)):
"""Converts RGB to hex color. In RGB color R stands for Red, G stands for Green, and B stands for Blue, and it ranges from the decimal value of 0 – 255.
Args:
rgb (tuple, optional): RGB color code as a tuple of (red, green, blue). Defaults to (255, 255, 255).
Returns:
str: hex color code
"""
return "%02x%02x%02x" % rgb
save_data(data, file_ext=None, file_name=None)
¶
Save data in the memory to a file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
object |
The data to be saved. |
required |
file_ext |
str |
The file extension of the file. |
None |
file_name |
str |
The name of the file to be saved. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
str |
The path of the file. |
Source code in leafmap/common.py
def save_data(data, file_ext=None, file_name=None):
"""Save data in the memory to a file.
Args:
data (object): The data to be saved.
file_ext (str): The file extension of the file.
file_name (str, optional): The name of the file to be saved. Defaults to None.
Returns:
str: The path of the file.
"""
import tempfile
import uuid
try:
if file_ext is None:
if hasattr(data, "name"):
_, file_ext = os.path.splitext(data.name)
else:
if not file_ext.startswith("."):
file_ext = "." + file_ext
if file_name is not None:
file_path = os.path.abspath(file_name)
if not file_path.endswith(file_ext):
file_path = file_path + file_ext
else:
file_id = str(uuid.uuid4())
file_path = os.path.join(tempfile.gettempdir(), f"{file_id}{file_ext}")
with open(file_path, "wb") as file:
file.write(data.getbuffer())
return file_path
except Exception as e:
print(e)
return None
screen_capture(outfile, monitor=1)
¶
Takes a full screenshot of the selected monitor.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
outfile |
str |
The output file path to the screenshot. |
required |
monitor |
int |
The monitor to take the screenshot. Defaults to 1. |
1 |
Source code in leafmap/common.py
def screen_capture(outfile, monitor=1):
"""Takes a full screenshot of the selected monitor.
Args:
outfile (str): The output file path to the screenshot.
monitor (int, optional): The monitor to take the screenshot. Defaults to 1.
"""
try:
from mss import mss
except ImportError:
raise ImportError("Please install mss using 'pip install mss'")
out_dir = os.path.dirname(outfile)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
if not isinstance(monitor, int):
print("The monitor number must be an integer.")
return
try:
with mss() as sct:
sct.shot(output=outfile, mon=monitor)
return outfile
except Exception as e:
raise Exception(e)
search_qms(keyword, limit=10, list_only=True, add_prefix=True)
¶
Search for QMS tile providers from Quick Map Services.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
keyword |
str |
The keyword to search for. |
required |
limit |
int |
The maximum number of results to return. Defaults to 10. |
10 |
list_only |
bool |
If True, only the list of services will be returned. Defaults to True. |
True |
add_prefix |
bool |
If True, the prefix "qms." will be added to the service name. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
list |
A list of QMS tile providers. |
Source code in leafmap/common.py
def search_qms(keyword, limit=10, list_only=True, add_prefix=True):
"""Search for QMS tile providers from Quick Map Services.
Args:
keyword (str): The keyword to search for.
limit (int, optional): The maximum number of results to return. Defaults to 10.
list_only (bool, optional): If True, only the list of services will be returned. Defaults to True.
add_prefix (bool, optional): If True, the prefix "qms." will be added to the service name. Defaults to True.
Returns:
list: A list of QMS tile providers.
"""
QMS_API = "https://qms.nextgis.com/api/v1/geoservices"
services = requests.get(
f"{QMS_API}/?search={keyword}&type=tms&epsg=3857&limit={limit}"
)
services = services.json()
if services["results"]:
providers = services["results"]
if list_only:
if add_prefix:
return ["qms." + provider["name"] for provider in providers]
else:
return [provider["name"] for provider in providers]
else:
return providers
else:
return None
search_xyz_services(keyword, name=None, list_only=True, add_prefix=True)
¶
Search for XYZ tile providers from xyzservices.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
keyword |
str |
The keyword to search for. |
required |
name |
str |
The name of the xyz tile. Defaults to None. |
None |
list_only |
bool |
If True, only the list of services will be returned. Defaults to True. |
True |
add_prefix |
bool |
If True, the prefix "xyz." will be added to the service name. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
list |
A list of XYZ tile providers. |
Source code in leafmap/common.py
def search_xyz_services(keyword, name=None, list_only=True, add_prefix=True):
"""Search for XYZ tile providers from xyzservices.
Args:
keyword (str): The keyword to search for.
name (str, optional): The name of the xyz tile. Defaults to None.
list_only (bool, optional): If True, only the list of services will be returned. Defaults to True.
add_prefix (bool, optional): If True, the prefix "xyz." will be added to the service name. Defaults to True.
Returns:
list: A list of XYZ tile providers.
"""
import xyzservices.providers as xyz
if name is None:
providers = xyz.filter(keyword=keyword).flatten()
else:
providers = xyz.filter(name=name).flatten()
if list_only:
if add_prefix:
return ["xyz." + provider for provider in providers]
else:
return [provider for provider in providers]
else:
return providers
set_api_key(token_name, api_key, m=None)
¶
Sets an API key as an environment variable.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
token_name |
str |
The token name. |
required |
api_key |
str |
The API key. |
required |
m |
ipyleaflet.Map | folium.Map |
A Map instance.. Defaults to None. |
None |
Source code in leafmap/common.py
def set_api_key(token_name, api_key, m=None):
"""Sets an API key as an environment variable.
Args:
token_name (str): The token name.
api_key (str): The API key.
m (ipyleaflet.Map | folium.Map, optional): A Map instance.. Defaults to None.
"""
os.environ[token_name] = api_key
if m is not None:
m.api_keys[token_name] = api_key
set_proxy(port=1080, ip='http://127.0.0.1')
¶
Sets proxy if needed. This is only needed for countries where Google services are not available.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
port |
int |
The proxy port number. Defaults to 1080. |
1080 |
ip |
str |
The IP address. Defaults to 'http://127.0.0.1'. |
'http://127.0.0.1' |
Source code in leafmap/common.py
def set_proxy(port=1080, ip="http://127.0.0.1"):
"""Sets proxy if needed. This is only needed for countries where Google services are not available.
Args:
port (int, optional): The proxy port number. Defaults to 1080.
ip (str, optional): The IP address. Defaults to 'http://127.0.0.1'.
"""
try:
if not ip.startswith("http"):
ip = "http://" + ip
proxy = "{}:{}".format(ip, port)
os.environ["HTTP_PROXY"] = proxy
os.environ["HTTPS_PROXY"] = proxy
a = requests.get("https://google.com")
if a.status_code != 200:
print(
"Failed to connect to Google services. Please double check the port number and ip address."
)
except Exception as e:
raise Exception(e)
show_image(img_path, width=None, height=None)
¶
Shows an image within Jupyter notebook.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
img_path |
str |
The image file path. |
required |
width |
int |
Width of the image in pixels. Defaults to None. |
None |
height |
int |
Height of the image in pixels. Defaults to None. |
None |
Source code in leafmap/common.py
def show_image(img_path, width=None, height=None):
"""Shows an image within Jupyter notebook.
Args:
img_path (str): The image file path.
width (int, optional): Width of the image in pixels. Defaults to None.
height (int, optional): Height of the image in pixels. Defaults to None.
"""
from IPython.display import display
try:
out = widgets.Output()
# layout={'border': '1px solid black'})
# layout={'border': '1px solid black', 'width': str(width + 20) + 'px', 'height': str(height + 10) + 'px'},)
out.clear_output(wait=True)
display(out)
with out:
file = open(img_path, "rb")
image = file.read()
if (width is None) and (height is None):
display(widgets.Image(value=image))
elif (width is not None) and (height is not None):
display(widgets.Image(value=image, width=width, height=height))
else:
print("You need set both width and height.")
return
except Exception as e:
raise Exception(e)
shp_to_gdf(in_shp)
¶
Converts a shapefile to Geopandas dataframe.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_shp |
str |
File path to the input shapefile. |
required |
Exceptions:
Type | Description |
---|---|
FileNotFoundError |
The provided shp could not be found. |
Returns:
Type | Description |
---|---|
gpd.GeoDataFrame |
geopandas.GeoDataFrame |
Source code in leafmap/common.py
def shp_to_gdf(in_shp):
"""Converts a shapefile to Geopandas dataframe.
Args:
in_shp (str): File path to the input shapefile.
Raises:
FileNotFoundError: The provided shp could not be found.
Returns:
gpd.GeoDataFrame: geopandas.GeoDataFrame
"""
import warnings
warnings.filterwarnings("ignore")
in_shp = os.path.abspath(in_shp)
if not os.path.exists(in_shp):
raise FileNotFoundError("The provided shp could not be found.")
check_package(name="geopandas", URL="https://geopandas.org")
import geopandas as gpd
try:
return gpd.read_file(in_shp)
except Exception as e:
raise Exception(e)
shp_to_geojson(in_shp, out_json=None, encoding='utf-8', **kwargs)
¶
Converts a shapefile to GeoJSON.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_shp |
str |
File path of the input shapefile. |
required |
out_json |
str |
File path of the output GeoJSON. Defaults to None. |
None |
Returns:
Type | Description |
---|---|
object |
The json object representing the shapefile. |
Source code in leafmap/common.py
def shp_to_geojson(in_shp, out_json=None, encoding="utf-8", **kwargs):
"""Converts a shapefile to GeoJSON.
Args:
in_shp (str): File path of the input shapefile.
out_json (str, optional): File path of the output GeoJSON. Defaults to None.
Returns:
object: The json object representing the shapefile.
"""
try:
import shapefile
in_shp = os.path.abspath(in_shp)
if out_json is not None:
ext = os.path.splitext(out_json)[1]
print(ext)
if ext.lower() not in [".json", ".geojson"]:
raise TypeError("The output file extension must the .json or .geojson.")
if not os.path.exists(os.path.dirname(out_json)):
os.makedirs(os.path.dirname(out_json))
if not is_GCS(in_shp):
try:
import geopandas as gpd
except Exception:
raise ImportError(
"Geopandas is required to perform reprojection of the data. See https://geopandas.org/install.html"
)
try:
in_gdf = gpd.read_file(in_shp, encoding=encoding)
out_gdf = in_gdf.to_crs(epsg="4326")
out_shp = in_shp.replace(".shp", "_gcs.shp")
out_gdf.to_file(out_shp)
in_shp = out_shp
except Exception as e:
raise Exception(e)
kwargs["encoding"] = encoding
if "encoding" in kwargs:
reader = shapefile.Reader(in_shp, encoding=kwargs.pop("encoding"))
else:
reader = shapefile.Reader(in_shp)
out_dict = reader.__geo_interface__
if out_json is not None:
import json
with open(out_json, "w") as geojson:
geojson.write(json.dumps(out_dict, indent=2) + "\n")
else:
return out_dict
except Exception as e:
raise Exception(e)
st_download_button(label, data, file_name=None, mime=None, key=None, help=None, on_click=None, args=None, csv_sep=',', **kwargs)
¶
Streamlit function to create a download button.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
label |
str |
A short label explaining to the user what this button is for.. |
required |
data |
str | list |
The contents of the file to be downloaded. See example below for caching techniques to avoid recomputing this data unnecessarily. |
required |
file_name |
str |
An optional string to use as the name of the file to be downloaded, such as 'my_file.csv'. If not specified, the name will be automatically generated. Defaults to None. |
None |
mime |
str |
The MIME type of the data. If None, defaults to "text/plain" (if data is of type str or is a textual file) or "application/octet-stream" (if data is of type bytes or is a binary file). Defaults to None. |
None |
key |
str |
An optional string or integer to use as the unique key for the widget. If this is omitted, a key will be generated for the widget based on its content. Multiple widgets of the same type may not share the same key. Defaults to None. |
None |
help |
str |
An optional tooltip that gets displayed when the button is hovered over. Defaults to None. |
None |
on_click |
str |
An optional callback invoked when this button is clicked. Defaults to None. |
None |
args |
list |
An optional tuple of args to pass to the callback. Defaults to None. |
None |
kwargs |
dict |
An optional tuple of args to pass to the callback. |
{} |
Source code in leafmap/common.py
def st_download_button(
label,
data,
file_name=None,
mime=None,
key=None,
help=None,
on_click=None,
args=None,
csv_sep=",",
**kwargs,
):
"""Streamlit function to create a download button.
Args:
label (str): A short label explaining to the user what this button is for..
data (str | list): The contents of the file to be downloaded. See example below for caching techniques to avoid recomputing this data unnecessarily.
file_name (str, optional): An optional string to use as the name of the file to be downloaded, such as 'my_file.csv'. If not specified, the name will be automatically generated. Defaults to None.
mime (str, optional): The MIME type of the data. If None, defaults to "text/plain" (if data is of type str or is a textual file) or "application/octet-stream" (if data is of type bytes or is a binary file). Defaults to None.
key (str, optional): An optional string or integer to use as the unique key for the widget. If this is omitted, a key will be generated for the widget based on its content. Multiple widgets of the same type may not share the same key. Defaults to None.
help (str, optional): An optional tooltip that gets displayed when the button is hovered over. Defaults to None.
on_click (str, optional): An optional callback invoked when this button is clicked. Defaults to None.
args (list, optional): An optional tuple of args to pass to the callback. Defaults to None.
kwargs (dict, optional): An optional tuple of args to pass to the callback.
"""
try:
import streamlit as st
import pandas as pd
if isinstance(data, str):
if file_name is None:
file_name = data.split("/")[-1]
if data.endswith(".csv"):
data = pd.read_csv(data).to_csv(sep=csv_sep, index=False)
if mime is None:
mime = "text/csv"
return st.download_button(
label, data, file_name, mime, key, help, on_click, args, **kwargs
)
elif (
data.endswith(".gif") or data.endswith(".png") or data.endswith(".jpg")
):
if mime is None:
mime = f"image/{os.path.splitext(data)[1][1:]}"
with open(data, "rb") as file:
return st.download_button(
label,
file,
file_name,
mime,
key,
help,
on_click,
args,
**kwargs,
)
elif isinstance(data, pd.DataFrame):
if file_name is None:
file_name = "data.csv"
data = data.to_csv(sep=csv_sep, index=False)
if mime is None:
mime = "text/csv"
return st.download_button(
label, data, file_name, mime, key, help, on_click, args, **kwargs
)
else:
# if mime is None:
# mime = "application/pdf"
return st.download_button(
label,
data,
file_name,
mime,
key,
help,
on_click,
args,
**kwargs,
)
except ImportError:
print("Streamlit is not installed. Please run 'pip install streamlit'.")
return
except Exception as e:
raise Exception(e)
stac_assets(url=None, collection=None, item=None, titiler_endpoint=None, **kwargs)
¶
Get all assets of a STAC item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A list of assets. |
Source code in leafmap/common.py
def stac_assets(url=None, collection=None, item=None, titiler_endpoint=None, **kwargs):
"""Get all assets of a STAC item.
Args:
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
Returns:
list: A list of assets.
"""
if url is None and collection is None:
raise ValueError("Either url or collection must be specified.")
if collection is not None and titiler_endpoint is None:
titiler_endpoint = "planetary-computer"
if url is not None:
kwargs["url"] = url
if collection is not None:
kwargs["collection"] = collection
if item is not None:
kwargs["item"] = item
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
if isinstance(titiler_endpoint, str):
r = requests.get(f"{titiler_endpoint}/stac/assets", params=kwargs).json()
else:
r = requests.get(titiler_endpoint.url_for_stac_assets(), params=kwargs).json()
return r
stac_bands(url=None, collection=None, item=None, titiler_endpoint=None, **kwargs)
¶
Get band names of a single SpatialTemporal Asset Catalog (STAC) item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A list of band names |
Source code in leafmap/common.py
def stac_bands(url=None, collection=None, item=None, titiler_endpoint=None, **kwargs):
"""Get band names of a single SpatialTemporal Asset Catalog (STAC) item.
Args:
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
Returns:
list: A list of band names
"""
if url is None and collection is None:
raise ValueError("Either url or collection must be specified.")
if collection is not None and titiler_endpoint is None:
titiler_endpoint = "planetary-computer"
if url is not None:
kwargs["url"] = url
if collection is not None:
kwargs["collection"] = collection
if item is not None:
kwargs["item"] = item
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
if isinstance(titiler_endpoint, str):
r = requests.get(f"{titiler_endpoint}/stac/assets", params=kwargs).json()
else:
r = requests.get(titiler_endpoint.url_for_stac_assets(), params=kwargs).json()
return r
stac_bounds(url=None, collection=None, item=None, titiler_endpoint=None, **kwargs)
¶
Get the bounding box of a single SpatialTemporal Asset Catalog (STAC) item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A list of values representing [left, bottom, right, top] |
Source code in leafmap/common.py
def stac_bounds(url=None, collection=None, item=None, titiler_endpoint=None, **kwargs):
"""Get the bounding box of a single SpatialTemporal Asset Catalog (STAC) item.
Args:
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
Returns:
list: A list of values representing [left, bottom, right, top]
"""
if url is None and collection is None:
raise ValueError("Either url or collection must be specified.")
if collection is not None and titiler_endpoint is None:
titiler_endpoint = "planetary-computer"
if url is not None:
kwargs["url"] = url
if collection is not None:
kwargs["collection"] = collection
if item is not None:
kwargs["item"] = item
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
if isinstance(titiler_endpoint, str):
r = requests.get(f"{titiler_endpoint}/stac/bounds", params=kwargs).json()
else:
r = requests.get(titiler_endpoint.url_for_stac_bounds(), params=kwargs).json()
bounds = r["bounds"]
return bounds
stac_center(url=None, collection=None, item=None, titiler_endpoint=None, **kwargs)
¶
Get the centroid of a single SpatialTemporal Asset Catalog (STAC) item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
tuple |
A tuple representing (longitude, latitude) |
Source code in leafmap/common.py
def stac_center(url=None, collection=None, item=None, titiler_endpoint=None, **kwargs):
"""Get the centroid of a single SpatialTemporal Asset Catalog (STAC) item.
Args:
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
Returns:
tuple: A tuple representing (longitude, latitude)
"""
bounds = stac_bounds(url, collection, item, titiler_endpoint, **kwargs)
center = ((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2) # (lon, lat)
return center
stac_info(url=None, collection=None, item=None, assets=None, titiler_endpoint=None, **kwargs)
¶
Get band info of a STAC item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
assets |
str | list |
The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"]. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A dictionary of band info. |
Source code in leafmap/common.py
def stac_info(
url=None, collection=None, item=None, assets=None, titiler_endpoint=None, **kwargs
):
"""Get band info of a STAC item.
Args:
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
assets (str | list): The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"].
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
Returns:
list: A dictionary of band info.
"""
if url is None and collection is None:
raise ValueError("Either url or collection must be specified.")
if collection is not None and titiler_endpoint is None:
titiler_endpoint = "planetary-computer"
if url is not None:
kwargs["url"] = url
if collection is not None:
kwargs["collection"] = collection
if item is not None:
kwargs["item"] = item
if assets is not None:
kwargs["assets"] = assets
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
if isinstance(titiler_endpoint, str):
r = requests.get(f"{titiler_endpoint}/stac/info", params=kwargs).json()
else:
r = requests.get(titiler_endpoint.url_for_stac_info(), params=kwargs).json()
return r
stac_info_geojson(url=None, collection=None, item=None, assets=None, titiler_endpoint=None, **kwargs)
¶
Get band info of a STAC item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
assets |
str | list |
The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"]. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A dictionary of band info. |
Source code in leafmap/common.py
def stac_info_geojson(
url=None, collection=None, item=None, assets=None, titiler_endpoint=None, **kwargs
):
"""Get band info of a STAC item.
Args:
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
assets (str | list): The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"].
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
Returns:
list: A dictionary of band info.
"""
if url is None and collection is None:
raise ValueError("Either url or collection must be specified.")
if collection is not None and titiler_endpoint is None:
titiler_endpoint = "planetary-computer"
if url is not None:
kwargs["url"] = url
if collection is not None:
kwargs["collection"] = collection
if item is not None:
kwargs["item"] = item
if assets is not None:
kwargs["assets"] = assets
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
if isinstance(titiler_endpoint, str):
r = requests.get(f"{titiler_endpoint}/stac/info.geojson", params=kwargs).json()
else:
r = requests.get(
titiler_endpoint.url_for_stac_info_geojson(), params=kwargs
).json()
return r
stac_pixel_value(lon, lat, url=None, collection=None, item=None, assets=None, titiler_endpoint=None, verbose=True, **kwargs)
¶
Get pixel value from STAC assets.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
lon |
float |
Longitude of the pixel. |
required |
lat |
float |
Latitude of the pixel. |
required |
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
assets |
str | list |
The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"]. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
None |
verbose |
bool |
Print out the error message. Defaults to True. |
True |
Returns:
Type | Description |
---|---|
list |
A dictionary of pixel values for each asset. |
Source code in leafmap/common.py
def stac_pixel_value(
lon,
lat,
url=None,
collection=None,
item=None,
assets=None,
titiler_endpoint=None,
verbose=True,
**kwargs,
):
"""Get pixel value from STAC assets.
Args:
lon (float): Longitude of the pixel.
lat (float): Latitude of the pixel.
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
assets (str | list): The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"].
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
verbose (bool, optional): Print out the error message. Defaults to True.
Returns:
list: A dictionary of pixel values for each asset.
"""
if url is None and collection is None:
raise ValueError("Either url or collection must be specified.")
if collection is not None and titiler_endpoint is None:
titiler_endpoint = "planetary-computer"
if url is not None:
kwargs["url"] = url
if collection is not None:
kwargs["collection"] = collection
if item is not None:
kwargs["item"] = item
if assets is None:
assets = stac_assets(
url=url,
collection=collection,
item=item,
titiler_endpoint=titiler_endpoint,
)
assets = ",".join(assets)
kwargs["assets"] = assets
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
if isinstance(titiler_endpoint, str):
r = requests.get(f"{titiler_endpoint}/stac/{lon},{lat}", params=kwargs).json()
else:
r = requests.get(
titiler_endpoint.url_for_stac_pixel_value(lon, lat), params=kwargs
).json()
if "detail" in r:
if verbose:
print(r["detail"])
return None
else:
values = [v[0] for v in r["values"]]
result = dict(zip(assets.split(","), values))
return result
stac_stats(url=None, collection=None, item=None, assets=None, titiler_endpoint=None, **kwargs)
¶
Get band statistics of a STAC item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
assets |
str | list |
The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"]. |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
list |
A dictionary of band statistics. |
Source code in leafmap/common.py
def stac_stats(
url=None, collection=None, item=None, assets=None, titiler_endpoint=None, **kwargs
):
"""Get band statistics of a STAC item.
Args:
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
assets (str | list): The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"].
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "planetary-computer", "pc". Defaults to None.
Returns:
list: A dictionary of band statistics.
"""
if url is None and collection is None:
raise ValueError("Either url or collection must be specified.")
if collection is not None and titiler_endpoint is None:
titiler_endpoint = "planetary-computer"
if url is not None:
kwargs["url"] = url
if collection is not None:
kwargs["collection"] = collection
if item is not None:
kwargs["item"] = item
if assets is not None:
kwargs["assets"] = assets
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
if isinstance(titiler_endpoint, str):
r = requests.get(f"{titiler_endpoint}/stac/statistics", params=kwargs).json()
else:
r = requests.get(
titiler_endpoint.url_for_stac_statistics(), params=kwargs
).json()
return r
stac_tile(url=None, collection=None, item=None, assets=None, bands=None, titiler_endpoint=None, **kwargs)
¶
Get a tile layer from a single SpatialTemporal Asset Catalog (STAC) item.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
url |
str |
HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json |
None |
collection |
str |
The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2. |
None |
item |
str |
The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1. |
None |
assets |
str | list |
The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"]. |
None |
bands |
list |
A list of band names, e.g., ["SR_B7", "SR_B5", "SR_B4"] |
None |
titiler_endpoint |
str |
Titiler endpoint, e.g., "https://titiler.xyz", "https://planetarycomputer.microsoft.com/api/data/v1", "planetary-computer", "pc". Defaults to None. |
None |
Returns:
Type | Description |
---|---|
str |
Returns the STAC Tile layer URL. |
Source code in leafmap/common.py
def stac_tile(
url=None,
collection=None,
item=None,
assets=None,
bands=None,
titiler_endpoint=None,
**kwargs,
):
"""Get a tile layer from a single SpatialTemporal Asset Catalog (STAC) item.
Args:
url (str): HTTP URL to a STAC item, e.g., https://canada-spot-ortho.s3.amazonaws.com/canada_spot_orthoimages/canada_spot5_orthoimages/S5_2007/S5_11055_6057_20070622/S5_11055_6057_20070622.json
collection (str): The Microsoft Planetary Computer STAC collection ID, e.g., landsat-8-c2-l2.
item (str): The Microsoft Planetary Computer STAC item ID, e.g., LC08_L2SP_047027_20201204_02_T1.
assets (str | list): The Microsoft Planetary Computer STAC asset ID, e.g., ["SR_B7", "SR_B5", "SR_B4"].
bands (list): A list of band names, e.g., ["SR_B7", "SR_B5", "SR_B4"]
titiler_endpoint (str, optional): Titiler endpoint, e.g., "https://titiler.xyz", "https://planetarycomputer.microsoft.com/api/data/v1", "planetary-computer", "pc". Defaults to None.
Returns:
str: Returns the STAC Tile layer URL.
"""
if url is None and collection is None:
raise ValueError("Either url or collection must be specified.")
if collection is not None and titiler_endpoint is None:
titiler_endpoint = "planetary-computer"
if url is not None:
kwargs["url"] = url
if collection is not None:
kwargs["collection"] = collection
if item is not None:
kwargs["item"] = item
if "palette" in kwargs:
kwargs["colormap_name"] = kwargs["palette"].lower()
del kwargs["palette"]
if isinstance(bands, list) and len(set(bands)) == 1:
bands = bands[0]
if isinstance(assets, list) and len(set(assets)) == 1:
assets = assets[0]
titiler_endpoint = check_titiler_endpoint(titiler_endpoint)
if isinstance(titiler_endpoint, PlanetaryComputerEndpoint):
if isinstance(bands, str):
bands = bands.split(",")
if isinstance(assets, str):
assets = assets.split(",")
if assets is None and (bands is not None):
assets = bands
else:
kwargs["bidx"] = bands
kwargs["assets"] = assets
# if ("expression" in kwargs) and ("rescale" not in kwargs):
# stats = stac_stats(
# collection=collection,
# item=item,
# expression=kwargs["expression"],
# titiler_endpoint=titiler_endpoint,
# )
# kwargs[
# "rescale"
# ] = f"{stats[0]['percentile_2']},{stats[0]['percentile_98']}"
# if ("asset_expression" in kwargs) and ("rescale" not in kwargs):
# stats = stac_stats(
# collection=collection,
# item=item,
# expression=kwargs["asset_expression"],
# titiler_endpoint=titiler_endpoint,
# )
# kwargs[
# "rescale"
# ] = f"{stats[0]['percentile_2']},{stats[0]['percentile_98']}"
if (
(assets is not None)
and ("asset_expression" not in kwargs)
and ("expression" not in kwargs)
and ("rescale" not in kwargs)
):
stats = stac_stats(
collection=collection,
item=item,
assets=assets,
titiler_endpoint=titiler_endpoint,
)
if "detail" not in stats:
try:
percentile_2 = min([stats[s]["percentile_2"] for s in stats])
percentile_98 = max([stats[s]["percentile_98"] for s in stats])
except:
percentile_2 = min(
[
stats[s][list(stats[s].keys())[0]]["percentile_2"]
for s in stats
]
)
percentile_98 = max(
[
stats[s][list(stats[s].keys())[0]]["percentile_98"]
for s in stats
]
)
kwargs["rescale"] = f"{percentile_2},{percentile_98}"
else:
print(stats["detail"]) # When operation times out.
else:
if isinstance(bands, str):
bands = bands.split(",")
if isinstance(assets, str):
assets = assets.split(",")
if assets is None and (bands is not None):
assets = bands
else:
kwargs["asset_bidx"] = bands
kwargs["assets"] = assets
TileMatrixSetId = "WebMercatorQuad"
if "TileMatrixSetId" in kwargs.keys():
TileMatrixSetId = kwargs["TileMatrixSetId"]
kwargs.pop("TileMatrixSetId")
if isinstance(titiler_endpoint, str):
r = requests.get(
f"{titiler_endpoint}/stac/{TileMatrixSetId}/tilejson.json",
params=kwargs,
).json()
else:
r = requests.get(titiler_endpoint.url_for_stac_item(), params=kwargs).json()
return r["tiles"][0]
streamlit_legend(html, width=None, height=None, scrolling=True)
¶
Streamlit function to display a legend.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
html |
str |
The HTML string of the legend. |
required |
width |
str |
The width of the legend. Defaults to None. |
None |
height |
str |
The height of the legend. Defaults to None. |
None |
scrolling |
bool |
Whether to allow scrolling in the legend. Defaults to True. |
True |
Source code in leafmap/common.py
def streamlit_legend(html, width=None, height=None, scrolling=True):
"""Streamlit function to display a legend.
Args:
html (str): The HTML string of the legend.
width (str, optional): The width of the legend. Defaults to None.
height (str, optional): The height of the legend. Defaults to None.
scrolling (bool, optional): Whether to allow scrolling in the legend. Defaults to True.
"""
try:
import streamlit.components.v1 as components
components.html(html, width=width, height=height, scrolling=scrolling)
except ImportError:
print("Streamlit is not installed. Please run 'pip install streamlit'.")
return
system_fonts(show_full_path=False)
¶
Gets a list of system fonts
1 2 3 4 |
|
Parameters:
Name | Type | Description | Default |
---|---|---|---|
show_full_path |
bool |
Whether to show the full path of each system font. Defaults to False. |
False |
Returns:
Type | Description |
---|---|
list |
A list of system fonts. |
Source code in leafmap/common.py
def system_fonts(show_full_path=False):
"""Gets a list of system fonts
# Common font locations:
# Linux: /usr/share/fonts/TTF/
# Windows: C:/Windows/Fonts
# macOS: System > Library > Fonts
Args:
show_full_path (bool, optional): Whether to show the full path of each system font. Defaults to False.
Returns:
list: A list of system fonts.
"""
try:
import matplotlib.font_manager
font_list = matplotlib.font_manager.findSystemFonts(
fontpaths=None, fontext="ttf"
)
font_list.sort()
font_names = [os.path.basename(f) for f in font_list]
font_names.sort()
if show_full_path:
return font_list
else:
return font_names
except Exception as e:
raise Exception(e)
temp_file_path(extension)
¶
Returns a temporary file path.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
extension |
str |
The file extension. |
required |
Returns:
Type | Description |
---|---|
str |
The temporary file path. |
Source code in leafmap/common.py
def temp_file_path(extension):
"""Returns a temporary file path.
Args:
extension (str): The file extension.
Returns:
str: The temporary file path.
"""
import tempfile
import uuid
if not extension.startswith("."):
extension = "." + extension
file_id = str(uuid.uuid4())
file_path = os.path.join(tempfile.gettempdir(), f"{file_id}{extension}")
return file_path
to_hex_colors(colors)
¶
Adds # to a list of hex color codes.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
colors |
list |
A list of hex color codes. |
required |
Returns:
Type | Description |
---|---|
list |
A list of hex color codes prefixed with #. |
Source code in leafmap/common.py
def to_hex_colors(colors):
"""Adds # to a list of hex color codes.
Args:
colors (list): A list of hex color codes.
Returns:
list: A list of hex color codes prefixed with #.
"""
result = all([len(color.strip()) == 6 for color in colors])
if result:
return ["#" + color.strip() for color in colors]
else:
return colors
update_package()
¶
Updates the leafmap package from the leafmap GitHub repository without the need to use pip or conda. In this way, I don't have to keep updating pypi and conda-forge with every minor update of the package.
Source code in leafmap/common.py
def update_package():
"""Updates the leafmap package from the leafmap GitHub repository without the need to use pip or conda.
In this way, I don't have to keep updating pypi and conda-forge with every minor update of the package.
"""
try:
download_dir = os.path.join(os.path.expanduser("~"), "Downloads")
if not os.path.exists(download_dir):
os.makedirs(download_dir)
_clone_repo(out_dir=download_dir)
pkg_dir = os.path.join(download_dir, "leafmap-master")
work_dir = os.getcwd()
os.chdir(pkg_dir)
if shutil.which("pip") is None:
cmd = "pip3 install ."
else:
cmd = "pip install ."
os.system(cmd)
os.chdir(work_dir)
print(
"\nPlease comment out 'leafmap.update_package()' and restart the kernel to take effect:\nJupyter menu -> Kernel -> Restart & Clear Output"
)
except Exception as e:
raise Exception(e)
upload_to_imgur(in_gif)
¶
Uploads an image to imgur.com
Parameters:
Name | Type | Description | Default |
---|---|---|---|
in_gif |
str |
The file path to the image. |
required |
Source code in leafmap/common.py
def upload_to_imgur(in_gif):
"""Uploads an image to imgur.com
Args:
in_gif (str): The file path to the image.
"""
import subprocess
pkg_name = "imgur-uploader"
if not _is_tool(pkg_name):
_check_install(pkg_name)
try:
IMGUR_API_ID = os.environ.get("IMGUR_API_ID", None)
IMGUR_API_SECRET = os.environ.get("IMGUR_API_SECRET", None)
credentials_path = os.path.join(
os.path.expanduser("~"), ".config/imgur_uploader/uploader.cfg"
)
if (
(IMGUR_API_ID is not None) and (IMGUR_API_SECRET is not None)
) or os.path.exists(credentials_path):
proc = subprocess.Popen(["imgur-uploader", in_gif], stdout=subprocess.PIPE)
for _ in range(0, 2):
line = proc.stdout.readline()
print(line.rstrip().decode("utf-8"))
# while True:
# line = proc.stdout.readline()
# if not line:
# break
# print(line.rstrip().decode("utf-8"))
else:
print(
"Imgur API credentials could not be found. Please check https://pypi.org/project/imgur-uploader/ for instructions on how to get Imgur API credentials"
)
return
except Exception as e:
raise Exception(e)
vector_col_names(filename, **kwargs)
¶
Retrieves the column names of a vector attribute table.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filename |
str |
The input file path. |
required |
Returns:
Type | Description |
---|---|
list |
The list of column names. |
Source code in leafmap/common.py
def vector_col_names(