### Install BlackMarblePy using uv (recommended) Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/README.md Install the BlackMarblePy package using uv, a fast and modern Python package installer. This is the recommended installation method. ```shell uv add blackmarblepy ``` -------------------------------- ### Install BlackMarblePy with Extras Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb Install the BlackMarblePy package along with extra dependencies required for examples. It's recommended to do this within a Python virtual environment. ```python # Install blackmarblepy and extras for examples #!pip install "blackmarblepy[examples]" ``` -------------------------------- ### Install BlackMarblePy from Source Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/CONTRIBUTING.md Install the BlackMarblePy package from its source code after cloning the repository. This command installs the package with all its dependencies. ```shell pip install . ``` -------------------------------- ### Create and Activate Virtual Environment Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/CONTRIBUTING.md Create a Python virtual environment for the project. This helps isolate project dependencies. Activate the environment before installing packages. ```shell python3 -m venv venv source venv/bin/activate # On Windows, use `venv\Scripts\activate` ``` -------------------------------- ### Install BlackMarblePy with Documentation Dependencies Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/CONTRIBUTING.md Install the BlackMarblePy package along with its documentation-specific dependencies. This is required for building the documentation locally. ```shell pip install -e .[docs] ``` -------------------------------- ### Install BlackMarblePy from PyPI Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/CONTRIBUTING.md Install the BlackMarblePy package using pip. This is the standard way to install the latest release from the Python Package Index. ```shell pip install blackmarblepy ``` -------------------------------- ### Setup for Monthly Data Processing Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/collection-comparison.ipynb Initializes paths and lists for processing monthly Black Marble data (VNP46A3). It sets up directories for two collections and finds all .tif files within them. ```python import rasterio import matplotlib.pyplot as plt import numpy as np import glob from datetime import datetime import geopandas as gpd from pathlib import Path import re # Set the month of interest (August 2022) plot_month = datetime(2022, 8, 1) month_str = plot_month.strftime("%Y%m") # e.g., 202208 # The file structure is VNP46A3.AYYYYDDD.hXXvYY.COLLECTION.TIMESTAMP for monthly base_dir = Path.home() / ".blackmarble_test" monthly_dir1 = base_dir / "collection1" / "monthly" monthly_dir2 = base_dir / "collection2" / "monthly" # List all .tif files in the monthly folders all_tifs1 = sorted(glob.glob(str(monthly_dir1 / "*.tif"))) all_tifs2 = sorted(glob.glob(str(monthly_dir2 / "*.tif"))) ``` -------------------------------- ### Install BlackMarblePy from Source (Editable Mode) Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/CONTRIBUTING.md Install the BlackMarblePy package in editable mode. This allows changes in the source code to be reflected immediately in the installed package without reinstallation. ```shell pip install -e . ``` -------------------------------- ### Get Quality Indicator for Composite Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/quality-assessment.ipynb Retrieve the quality indicator for the nighttime light composite. This data helps in understanding the reliability of the generated values. ```python quality_r = bm_raster( gdf, product_id="VNP46A3", date_range="2023-01-01", token=bearer, variable="NearNadir_Composite_Snow_Free_Quality", ) ``` -------------------------------- ### Build Documentation Locally Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/CONTRIBUTING.md Build the project's documentation locally using Sphinx. The generated HTML files will be placed in the `_build/html` directory. ```shell sphinx-build docs _build/html -b html ``` -------------------------------- ### Set Up Logging and Load Environment Variables Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb Configures the logging level for the blackmarblepy library and loads environment variables, typically used for sensitive information like API tokens. ```python logging.getLogger("blackmarblepy").setLevel(logging.INFO) load_dotenv() ``` -------------------------------- ### Get Number of Observations for Composite Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/quality-assessment.ipynb Retrieve the number of observations used to generate nighttime light values for each pixel. Append '_Num' to the variable name to access this data. ```python cf_r = bm_raster( gdf, product_id="VNP46A3", date_range="2023-01-01", token=bearer, variable="NearNadir_Composite_Snow_Free_Num", ) ``` -------------------------------- ### Process and Store Collection Data Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/collection-comparison.ipynb This code snippet iterates through predefined directories for collection-1 and collection-2 (daily and monthly), finds all .tif files, and uses the `summarize_tif_set` function to process them. Results are stored in a dictionary. Ensure the base directory and folder structure match your Blackmarblepy installation. ```python base_dir = Path.home() / ".blackmarble_test" folders = { "collection1_daily": base_dir / "collection1" / "daily", "collection2_daily": base_dir / "collection2" / "daily", "collection1_monthly": base_dir / "collection1" / "monthly", "collection2_monthly": base_dir / "collection2" / "monthly", } results = {} for key, folder in folders.items(): tif_files = sorted(glob.glob(str(folder / "*.tif"))) results[key] = summarize_tif_set(tif_files) ``` -------------------------------- ### Import Libraries and Configure Environment Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb Imports necessary libraries for data handling, visualization, and BlackMarblePy functionality. It also sets up autoreload, watermark, and inline plotting for a better development experience. ```python import os import datetime import logging import colorcet as cc import contextily as cx import geopandas import matplotlib.pyplot as plt import pandas as pd from dotenv import load_dotenv from bokeh.plotting import figure, output_notebook, show from bokeh.models import HoverTool, Title from blackmarble import BlackMarble %load_ext autoreload %load_ext watermark %autoreload 2 %config InlineBackend.figure_format = 'retina' %watermark -v -u -n -p blackmarble ``` -------------------------------- ### Initialize BlackMarble Class Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb Initializes the BlackMarble interface for downloading and processing nighttime lights data. Configuration options can be passed during initialization or set via environment variables. ```python # Class-based interface example # Initialize the BlackMarble interface bm = BlackMarble() # Optional: configure options # bm = BlackMarble( # token="your_token_here", # NASA Earthdata bearer token (can also be set via env var) # check_all_tiles_exist=True, # Skip dates if any tile is missing # drop_values_by_quality_flag=[255], # Mask out invalid data (e.g., fill value) # output_directory="data", # Directory to save outputs # output_skip_if_exists=True # Skip downloading if file already exists # ) ``` -------------------------------- ### Generate High-Level Summary Statistics Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/collection-comparison.ipynb This function creates a concise summary string for a given DataFrame of raster statistics. It calculates overall min, max, mean, median, and std from the individual file statistics. Call this function after processing your .tif files to get a quick overview. ```python def high_level_summary(df, label): if df.empty or not set(["min", "max", "mean", "median", "std"]).issubset( df.columns ): return f"{label}: No valid data" return ( f"{label}: count={len(df)}, min={df['min'].min():.2f}, max={df['max'].max():.2f}, " f"mean={df['mean'].mean():.2f}, median={df['median'].mean():.2f}, std={df['std'].mean():.2f}" ) ``` -------------------------------- ### Download Nighttime Lights Data Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb This snippet shows how to download VNP46A4 data files. It indicates when files already exist and are reused. ```text [2025-11-11 11:52:41] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2022001.h17v07.002.2025156103600.h5 [2025-11-11 11:52:41] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2023001.h17v07.002.2025161112953.h5 [2025-11-11 11:52:41] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2024001.h17v07.002.2025162012742.h5 ``` ```text [2025-11-11 11:52:50] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2019001.h17v08.002.2025133143236.h5 [2025-11-11 11:52:50] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2020001.h17v08.002.2025134020111.h5 [2025-11-11 11:52:50] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2021001.h17v08.002.2025149104126.h5 [2025-11-11 11:52:50] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2022001.h17v08.002.2025156103417.h5 [2025-11-11 11:52:50] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2023001.h17v08.002.2025161112928.h5 [2025-11-11 11:52:50] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2024001.h17v08.002.2025162013131.h5 ``` -------------------------------- ### Summarize .tif Files in a Directory Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/collection-comparison.ipynb This function reads .tif files, calculates various statistics (min, max, mean, median, std, counts), and handles masked or NaN values. It returns a pandas DataFrame with the statistics for each file. Use this to get a statistical overview of raster datasets. ```python import rasterio import numpy as np import glob from pathlib import Path import pandas as pd import matplotlib.pyplot as plt def summarize_tif_set(tif_files): stats = [] for f in tif_files: try: with rasterio.open(f) as src: arr = src.read(1) masked = np.ma.masked_where((arr == 0) | np.isnan(arr), arr) # Only include if there is at least one valid (unmasked) value if masked.count() > 0: stats.append( { "file": Path(f).name, "min": float(masked.min()), "max": float(masked.max()), "mean": float(masked.mean()), "median": float(np.ma.median(masked)), "std": float(masked.std()), "nonzero_count": int(np.sum(masked != 0)), "total_count": int(masked.size), "nan_count": int(np.sum(np.isnan(masked))), } ) else: stats.append( {"file": Path(f).name, "error": "All values masked or NaN"} ) except Exception as e: stats.append({"file": Path(f).name, "error": str(e)}) df = pd.DataFrame(stats) # Remove rows with error for numeric analysis if "error" in df.columns: df = df[df["error"].isna() | (df["error"].isnull())] df = df.drop(columns=["error"], errors="ignore") return df ``` -------------------------------- ### Downloaded File Information Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb This output indicates that the requested nighttime lights data files already exist and are being reused. It logs the file path and details for each reused file. ```text Output: [2025-11-11 11:52:05] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2019001.h18v07.002.2025133143238.h5 [2025-11-11 11:52:05] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2020001.h18v07.002.2025134020332.h5 [2025-11-11 11:52:05] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2021001.h18v07.002.2025149104224.h5 [2025-11-11 11:52:05] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2022001.h18v07.002.2025156103531.h5 [2025-11-11 11:52:05] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2023001.h18v07.002.2025161113010.h5 [2025-11-11 11:52:05] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2024001.h18v07.002.2025162031135.h5 ``` ```text Output: [2025-11-11 11:52:22] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2019001.h18v08.002.2025133143239.h5 [2025-11-11 11:52:22] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2020001.h18v08.002.2025134022453.h5 [2025-11-11 11:52:22] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2021001.h18v08.002.2025149104215.h5 [2025-11-11 11:52:22] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2022001.h18v08.002.2025156103341.h5 [2025-11-11 11:52:22] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2023001.h18v08.002.2025161113203.h5 [2025-11-11 11:52:22] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2024001.h18v08.002.2025162031854.h5 ``` ```text Output: [2025-11-11 11:52:41] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2019001.h17v07.002.2025133143240.h5 [2025-11-11 11:52:41] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2020001.h17v07.002.2025134020200.h5 [2025-11-11 11:52:41] [INFO] [download]: File already exists, reusing: /private/var/folders/lb/68gqsbvn171cckt3kdl3d5nr0000gn/T/tmpp426pt0c/VNP46A4.A2021001.h17v07.002.2025149104125.h5 ``` -------------------------------- ### Process and Visualize Daily Nighttime Lights (Gap-Filled) Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/quality-assessment.ipynb Processes the downloaded gap-filled daily nighttime lights data, replacing invalid values with NaN, and visualizes it using a fire colormap. This snippet is used after downloading the data. ```python r_np = ntl_tmp_gap_r["Latest_High_Quality_Retrieval"].sel(time="2023-01-01") r_np = np.where(r_np == 255, np.nan, r_np) plt.imshow(r_np, cmap=cc.cm.fire) plt.axis("off") plt.colorbar( label="Temporal\nGap\n(Days)" ) # Add a colorbar with ticks for discrete values plt.tight_layout() ``` -------------------------------- ### Find and Prepare Daily TIF Files Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/collection-comparison.ipynb Locates daily GeoTIFF files for two Black Marble collections based on a date pattern and prepares them for processing. Assumes a specific directory structure and naming convention for the files. ```python base_dir = Path.home() / ".blackmarble_test" tif_pattern1 = str(base_dir / "collection1" / "daily" / f"*A{date_str}*.tif") tif_pattern2 = str(base_dir / "collection2" / "daily" / f"*A{date_str}*.tif") # Find the .tif files (could be more than one per day) files1 = sorted(glob.glob(tif_pattern1)) files2 = sorted(glob.glob(tif_pattern2)) ``` -------------------------------- ### Download Daily Nighttime Lights (Gap-Filled) Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/quality-assessment.ipynb Downloads daily nighttime lights data using the 'Latest_High_Quality_Retrieval' variable, which includes gap-filled observations. This is useful for obtaining a continuous daily record. ```python ntl_tmp_gap_r = bm_raster( gdf, product_id="VNP46A2", date_range="2023-01-01", token=bearer, variable="Latest_High_Quality_Retrieval", ) ``` -------------------------------- ### Create Monthly Raster Stack Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb Initializes a monthly raster stack using a GeoDataFrame, product ID, and a date range. Ensure the GeoDataFrame and date range are correctly defined before execution. ```python r_monthly = bm.raster( gdf, product_id="VNP46A3", date_range=pd.date_range("2023-01-01", "2025-04-01", freq="MS"), ) ``` -------------------------------- ### Create Daily Raster Stack Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb Retrieves and stacks NASA Black Marble daily VNP46A2 data for a specified date range. Requires pandas for date range generation. ```python import pandas as pd from blackmarblepy.blackmarble import BlackMarble date_range = pd.date_range(start='2025-04-15', end='2025-04-22', freq='D') blackmarble_daily = BlackMarble(date_range=date_range) blackmarble_daily.get_data() blackmarble_daily.create_raster_stack() print(blackmarble_daily.raster_stack.dims) ``` -------------------------------- ### Download VNP46 Data with BlackMarblePy Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/README.md This snippet demonstrates how to initialize the BlackMarble client and download VNP46 data for a specified region and date. It assumes your Earthdata token is set as an environment variable or passed directly. Ensure you have a GeoDataFrame defining your region of interest. ```python import geopandas as gpd from blackmarble import BlackMarble, Product # ------------------------------------------------------------------------------ # 1. Define your region of interest # ------------------------------------------------------------------------------ # In this example ,we load a region from a GeoJSON. gdf = gpd.read_file("path/to/your/shapefile.geojson") # ------------------------------------------------------------------------------ # 2. Set up the BlackMarble client # ------------------------------------------------------------------------------ # If the environment variable `BLACKMARBLE_TOKEN` is set, it will be used automatically. # You can also pass your token directly, but using the environment variable is recommended. bm = BlackMarble(token="YOUR_BLACKMARBLE_TOKEN") # ------------------------------------------------------------------------------ # 3. Download VNP46 data from NASA Earthdata # ------------------------------------------------------------------------------ # In this example, we request the VNP46A2 product for a specific date. # The data is returned as an xarray.Dataset. raster_earth_day = bm.raster( gdf, product_id=Product.VNP46A2, date_range="2025-04-22", ) ``` -------------------------------- ### Download Daily Nighttime Lights (No Gap-Filling, Quality Filtered) Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/quality-assessment.ipynb Downloads daily nighttime lights data using the 'DNB_BRDF-Corrected_NTL' variable, excluding gap-filled observations and removing poor quality pixels (flags 2 and 255). Use this when raw, high-quality data is preferred. ```python ntl_r = bm_raster( gdf, product_id="VNP46A2", date_range="2023-01-01", token=bearer, variable="DNB_BRDF-Corrected_NTL", quality_flag_rm=[2, 255], ) ``` -------------------------------- ### Initialize GIS and Date Variables Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/collection-comparison.ipynb Initializes necessary libraries for geospatial data processing and sets a specific date of interest for analysis. This snippet is a prerequisite for subsequent geospatial operations. ```python import rasterio import numpy as np import glob from datetime import datetime import geopandas as gpd from rasterio.merge import merge # Set the date of interest plot_date = datetime(2023, 6, 3) date_str = plot_date.strftime( "%Y%j" # %j is day of year, e.g., 2023156 for June 5, 2023 ) ``` -------------------------------- ### Download Monthly Nighttime Lights (Snow-Free) Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/quality-assessment.ipynb Downloads monthly nighttime lights data for January 2023 using the 'NearNadir_Composite_Snow_Free' variable. This variable is the default when not specified and removes snow cover effects. This is suitable for monthly or annual analysis. ```python ntl_r = bm_raster( gdf, product_id="VNP46A3", date_range="2023-01-01", token=bearer, variable="NearNadir_Composite_Snow_Free", ) ``` -------------------------------- ### Plotting Monthly Nighttime Light Radiance Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb This snippet visualizes monthly aggregate nighttime light radiance data. It sets up a plot, plots the data, adds labels and a source text, and adjusts layout before displaying. ```python fig, ax = plt.subplots(figsize=(10, 5)) # Plot NTL radiance r_monthly["NearNadir_Composite_Snow_Free"].sum(dim=["x", "y"]).plot(ax=ax) ax.set_title( "Monthly Aggregate Nighttime Light Radiance in Ghana", fontsize=18, weight="bold" ) a.set_xlabel("Date", fontsize=12) a.set_ylabel("Radiance (nW/cm²/sr)", fontsize=12) plt.ylim(bottom=0) a.text( 0, -0.2, "Source: NASA Black Marble VNP46A3", ha="left", va="center", transform=ax.transAxes, fontsize=10, color="black", weight="normal", ) fig.tight_layout() plt.show() ``` -------------------------------- ### Process and Visualize Daily Nighttime Lights Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/collection-comparison.ipynb Merges daily tiles for two collections, masks zero values, computes a shared color scale, and visualizes the data side-by-side. Overlays the Rwanda boundary if available. Requires GeoTIFF files and a Rwanda boundary GeoJSON. ```python if files1 and files2: # Merge tiles for each collection img1_merged, trans1, crs1 = merge_tiles(files1) img2_merged, trans2, crs2 = merge_tiles(files2) img1_masked = mask_zero(img1_merged) img2_masked = mask_zero(img2_merged) # Compute global vmin/vmax for both images (ignoring masked values) all_data = np.ma.concatenate([img1_masked.compressed(), img2_masked.compressed()]) vmin = all_data.min() vmax = all_data.max() print( f"Collection 1 (merged): min={img1_masked.min()}, max={img1_masked.max()}, shape={img1_masked.shape}" ) print( f"Collection 2 (merged): min={img2_masked.min()}, max={img2_masked.max()}, shape={img2_masked.shape}" ) print(f"Shared color scale: vmin={vmin}, vmax={vmax}") fig, axes = plt.subplots(1, 2, figsize=(14, 7)) fig.suptitle("Daily Nighttime Lights (June 4, 2023)", fontsize=16) for idx, (img, trans, crs, title, ax) in enumerate( [ (img1_masked, trans1, crs1, "Collection 1 (Daily)", axes[0]), (img2_masked, trans2, crs2, "Collection 2 (Daily)", axes[1]), ] ): bounds = rasterio.transform.array_bounds(img.shape[0], img.shape[1], trans) extent = [ bounds[0], bounds[2], bounds[1], bounds[3], ] # [left, right, bottom, top] im = ax.imshow( img, cmap="viridis", extent=extent, origin="upper", vmin=vmin, vmax=vmax ) ax.set_title(title) ax.set_xlabel("Longitude") ax.set_ylabel("Latitude") ax.set_xlim(extent[0], extent[1]) ax.set_ylim(extent[2], extent[3]) ax.grid(True, color="white", linestyle="--", alpha=0.5) plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04) # Overlay Rwanda boundary if available, after the raster if gdf_rwanda is not None: gdf_rwanda_plot = gdf_rwanda.copy() if gdf_rwanda_plot.crs != crs: gdf_rwanda_plot = gdf_rwanda_plot.to_crs(crs) gdf_rwanda_plot.boundary.plot( ax=ax, edgecolor="red", linewidth=2, zorder=20 ) plt.tight_layout(rect=[0, 0, 1, 0.96]) plt.show() else: print( f"No .tif file found for {plot_date.strftime('%Y-%m-%d')} in one or both collections." ) ``` -------------------------------- ### Plot Monthly Nighttime Lights (Snow-Free) Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/quality-assessment.ipynb Plots the downloaded monthly nighttime lights data using a 'cividis' colormap and adds a basemap. This visualization is used after downloading the monthly data. ```python fig, ax = plt.subplots() tl_r["NearNadir_Composite_Snow_Free"].sel(time="2023-01-01").plot( robust=True, cmap="cividis" ) cx.add_basemap(ax, crs=gdf.crs.to_string(), source=cx.providers.CartoDB.Positron) plt.axis("off") plt.tight_layout() ``` -------------------------------- ### Retrieve Monthly VNP46A3 Data Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb Fetches the VNP46A3 product for a specific date range. Ensure the 'bm' and 'gdf' objects are initialized. ```python VNP46A3 = bm.raster( gdf, product_id="VNP46A3", date_range="2024-03-21", ) VNP46A3 ``` -------------------------------- ### Clone BlackMarblePy Repository Source: https://github.com/worldbank/blackmarblepy/blob/main/docs/CONTRIBUTING.md Clone the BlackMarblePy project repository from GitHub to your local machine. This is the first step for contributing code or making changes from source. ```shell git clone https://github.com/worldbank/blackmarblepy.git cd blackmarblepy ``` -------------------------------- ### Download Progress Indicator Source: https://github.com/worldbank/blackmarblepy/blob/main/notebooks/blackmarblepy.ipynb These snippets show the progress of data download operations, indicating the percentage and amount of data being downloaded. ```text Result: OBTAINING MANIFEST...: 0%| | 0/4 [00:00