diff --git a/SDG_15_4_2_Sub_A_Default_values.ipynb b/Colab_SDG_15_4_2_Sub_A_Default_values.ipynb similarity index 100% rename from SDG_15_4_2_Sub_A_Default_values.ipynb rename to Colab_SDG_15_4_2_Sub_A_Default_values.ipynb diff --git a/SDG_15_4_2_Sub_B_Default_values.ipynb b/Colab_SDG_15_4_2_Sub_B_Default_values.ipynb similarity index 100% rename from SDG_15_4_2_Sub_B_Default_values.ipynb rename to Colab_SDG_15_4_2_Sub_B_Default_values.ipynb diff --git a/SDG_15_4_2_Sub_A_Default_values _SEPAL.ipynb b/SDG_15_4_2_Sub_A_Default_values _SEPAL.ipynb deleted file mode 100644 index 8e79479..0000000 --- a/SDG_15_4_2_Sub_A_Default_values _SEPAL.ipynb +++ /dev/null @@ -1,759 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "source": [ - "# **SDG 15.4.2 Sub-indicator A: Calculate Global Default Values**\n", - "\n", - "* This script allows batch processing for this indicator for all countries.\n", - "\n", - "* Output is a combined excel file on your Google Drive.\n", - "\n", - "* Runs on the cloud using [Google Colab](https://research.google.com/colaboratory/faq.html)\n", - "\n", - "* Requires: [Google Earth Engine](https://earthengine.google.com/) (GEE) account and project and access to Google Drive\n" - ], - "metadata": { - "id": "82FWR5yMh0HV" - } - }, - { - "cell_type": "markdown", - "source": [ - "### 1) Install required packages" - ], - "metadata": { - "id": "YdoCOI_1yWY0" - } - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "id": "Kg3K1EPJu_f5", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 208 - }, - "outputId": "460f7ba2-8668-4c4d-824b-6d5068884129" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m6.1/6.1 MB\u001b[0m \u001b[31m34.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.7/2.7 MB\u001b[0m \u001b[31m54.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.6/1.6 MB\u001b[0m \u001b[31m38.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hipyvuetify has been installed.\n", - "ee is already installed.\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m235.5/235.5 kB\u001b[0m \u001b[31m4.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hunidecode has been installed.\n", - "google-api-python-client has been installed.\n", - "google-auth-httplib2 has been installed.\n", - "google-auth-oauthlib has been installed.\n", - "geemap is already installed.\n" - ] - } - ], - "source": [ - "# to automatically reload modules.\n", - "%load_ext autoreload\n", - "\n", - "# Set to reload all modules before executing code.\n", - "%autoreload 2\n", - "\n", - "# Function to install a package if it's not already installed\n", - "def install_if_not_exists(package_name):\n", - " try:\n", - " __import__(package_name)\n", - " print(f\"{package_name} is already installed.\")\n", - " except ImportError:\n", - " !pip install -q {package_name}\n", - " print(f\"{package_name} has been installed.\")\n", - "\n", - "# List of packages to install if not already installed\n", - "packages_to_install = ['ipyvuetify','ee', 'unidecode', 'google-api-python-client',\n", - " 'google-auth-httplib2', 'google-auth-oauthlib','geemap'] #admin_boundaries\n", - "\n", - "# Install necessary packages\n", - "for package in packages_to_install:\n", - " install_if_not_exists(package)" - ] - }, - { - "cell_type": "markdown", - "source": [ - "### 2) Access GitHub repository\n", - "Clones repository for SDG 15.4.2 into colab.\n", - "Provides functions and lookup tables etc." - ], - "metadata": { - "id": "qGfLFLEkwS1n" - } - }, - { - "cell_type": "code", - "source": [ - "# Change the current working directory to \"/content\" for cloning the repo into.\n", - "%cd \"/content\"\n", - "\n", - "# Clone the GitHub repository \"sepalz_mgci\" into the current directory.\n", - "# NB 'fatal' error on reruns are typically just saying it already exists\n", - "!git clone https://github.com/sepal-contrib/sepal_mgci\n", - "\n", - "# Change working directory to the cloned sepal_mgci github repository\n", - "%cd \"/content/sepal_mgci\"" - ], - "metadata": { - "id": "TNohZrOTvNqT", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 173 - }, - "outputId": "1ad0a56a-2b6e-4966-ab95-a55a1a612aae" - }, - "execution_count": 2, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": [ - "" - ], - "text/html": [ - "\n", - " \n", - " " - ] - }, - "metadata": {} - }, - { - "output_type": "stream", - "name": "stdout", - "text": [ - "/content\n", - "Cloning into 'sepal_mgci'...\n", - "remote: Enumerating objects: 3071, done.\u001b[K\n", - "remote: Counting objects: 100% (1009/1009), done.\u001b[K\n", - "remote: Compressing objects: 100% (426/426), done.\u001b[K\n", - "remote: Total 3071 (delta 663), reused 807 (delta 582), pack-reused 2062\u001b[K\n", - "Receiving objects: 100% (3071/3071), 5.02 MiB | 17.37 MiB/s, done.\n", - "Resolving deltas: 100% (1939/1939), done.\n", - "/content/sepal_mgci\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "### 3) Setup Google Earth Engine\n", - "Launches access request pop up window" - ], - "metadata": { - "id": "Lbg9P7frZRy1" - } - }, - { - "cell_type": "code", - "source": [ - "# Google Earth Engine project\n", - "gee_project_name = \"ee-andyarnellgee\" # \"insert cloud project here\" # a registered cloud project (if unsure of name see pic here: https://developers.google.com/earth-engine/cloud/assets)\n", - "\n", - "import ee # google earth engine\n", - "\n", - "ee.Authenticate()\n", - "\n", - "ee.Initialize(project=gee_project_name) # NB gee project name is defined in parameters section" - ], - "metadata": { - "id": "SLLcPONnZRy2" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 4) Setup Google Drive\n", - "Launches access request pop up window" - ], - "metadata": { - "id": "cxXsgaXEZRy3" - } - }, - { - "cell_type": "code", - "source": [ - "# for accessing google drive\n", - "from google.colab import auth, drive\n", - "from googleapiclient.discovery import build\n", - "\n", - "drive.mount('/content/drive')" - ], - "metadata": { - "id": "e2NxIhcgZRy3" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 5) Import remaining packages\n", - "- imports required packages and functions listed in 'colab_imports.py' script (found here: sepal_mgci/component/scripts)\n", - "\n" - ], - "metadata": { - "id": "MsQu9VfqZRy3" - } - }, - { - "cell_type": "code", - "source": [ - "from component.scripts.colab_imports import *" - ], - "metadata": { - "id": "NQ9flKZGZRy4" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### 6) Set parameters\n" - ], - "metadata": { - "id": "Bi0XpRRDo6V1" - } - }, - { - "cell_type": "markdown", - "source": [ - "Input parameters" - ], - "metadata": { - "id": "5aIr_OxkG-Ky" - } - }, - { - "cell_type": "code", - "source": [ - "# Google Earth Engine project\n", - "gee_project_name = \"ee-andyarnellgee\" # \"insert cloud project here\" # a registered cloud project (if unsure of name see pic here: https://developers.google.com/earth-engine/cloud/assets)\n", - "\n", - "\n", - "# Admin boundaries asset\n", - "admin_asset_id = \"FAO/GAUL/2015/level0\" # administrative units feature collection\n", - "\n", - "admin_asset_property_name = \"ADM0_NAME\" # property/column name for selecting admin boundaries (e.g. ISO3 code or country name)\n", - "\n", - "\n", - "# Land cover assets\n", - "\n", - "# For Sub-indicator A (sub_a), we need to set the following structure.\n", - "a_years = {\n", - " 1: {\"asset\": \"users/amitghosh/sdg_module/esa/cci_landcover/2000\", \"year\": 2000}, # baseline\n", - " 2: {\"year\": 2003, \"asset\": \"users/amitghosh/sdg_module/esa/cci_landcover/2003\"}, # subsequent reporting years...\n", - " 3: {\"year\": 2007, \"asset\": \"users/amitghosh/sdg_module/esa/cci_landcover/2007\"},\n", - " 4: {\"year\": 2010, \"asset\": \"users/amitghosh/sdg_module/esa/cci_landcover/2010\"},\n", - "}\n", - "\n" - ], - "metadata": { - "id": "t9C1qT5bGoqt" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "Output parameters\n", - "\n", - "---\n", - "\n" - ], - "metadata": { - "id": "naz3Qe4JHFER" - } - }, - { - "cell_type": "code", - "source": [ - "final_report_folder = \"sdg_15_4_2_A_combined_report\" # folder name in Google Drive for final output (if doesnt exist creates one)\n", - "\n", - "final_report_name = \"sdg_15_4_2_A_default_global.xlsx\" # file name for final excel output\n", - "\n", - "# export GEE tasks or not\n", - "export = False # default: True. Set to False if debugging or limiting accidental re-exporting of tasks\n", - "\n", - "# prints more messages\n", - "debug = False # default: False. Set to True if debugging code" - ], - "metadata": { - "id": "mSvTM29TnndR" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "Temporary output parameters\n" - ], - "metadata": { - "id": "iV8-wbddOJuT" - } - }, - { - "cell_type": "code", - "source": [ - "stats_csv_folder = \"sdg_15_4_2_A_csvs\" # for storing stats tables exported from GEE for each admin boundary/AOI\n", - "\n", - "excel_reports_folder = \"sdg_15_4_2_A_reports\" # for storing formatted excel tables for each admin boundary/AOI\n", - "\n", - "drive_home =\"/content/drive/MyDrive/\" # Google Drive location. Don't change unless you know this is incorrect\n", - "\n", - "error_log_file_path = drive_home + excel_reports_folder + \"/\"+\"1_error_log\" +\".csv\" # for storing errors\n" - ], - "metadata": { - "id": "TCBNkALuOL1N" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "c_8UzlUnu_f6" - }, - "source": [ - "### 7) Setup inputs for processing" - ] - }, - { - "cell_type": "markdown", - "source": [ - "Create list of boundaries to process" - ], - "metadata": { - "id": "qi5zNGTWN3df" - } - }, - { - "cell_type": "code", - "source": [ - "# admin boundary feature collection\n", - "admin_boundaries = ee.FeatureCollection(admin_asset_id)\n", - "\n", - "# list to process\n", - "list_of_countries = admin_boundaries.aggregate_array(admin_asset_property_name).getInfo()\n", - "\n", - "print (\"Length of admin boundaries to process\", len(list_of_countries))\n", - "\n", - "list_of_countries = list(set(list_of_countries)) # remove dupicates\n", - "\n", - "print (\"Length of distinct admin boundaries to process\", (len(set(list_of_countries))))\n" - ], - "metadata": { - "id": "BiuBEJwPue2v" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "Read the default land cover remapping table and convert it to a dictionary" - ], - "metadata": { - "id": "2G1q9TSiUsc1" - } - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "PRSEqq5bu_f7" - }, - "outputs": [], - "source": [ - "default_map_matrix = map_matrix_to_dict(LC_MAP_MATRIX)" - ] - }, - { - "cell_type": "markdown", - "source": [ - "Select years of land cover to process" - ], - "metadata": { - "id": "4-Ut_-S35Yg8" - } - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "PwqJFWR4u_f7", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 17 - }, - "outputId": "09d3ab98-6b20-4212-b5ed-f3386c3a32bf" - }, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": [ - "" - ], - "text/html": [ - "\n", - " \n", - " " - ] - }, - "metadata": {} - } - ], - "source": [ - "# extracts the years from the a_years dictionary (as defined in parameters)\n", - "single_years = [y[\"year\"] for y in a_years.values()]" - ] - }, - { - "cell_type": "markdown", - "source": [ - "### 8) Calculate area statistics by country\n", - "* Runs for each country and each mountain biobelt\n", - "* Gets area of land cover reclassified into the 10 SEAM classes\n", - "* Repeat for each year specified\n" - ], - "metadata": { - "id": "iNxHtR984cNk" - } - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "VftKLuY4u_f7" - }, - "outputs": [], - "source": [ - "# you can monitor your GEE tasks here : https://code.earthengine.google.com/tasks\n", - "create_folder_if_not_exists(stats_csv_folder) # to store outputs in google drive\n", - "\n", - "counter=0 # starting place of counter used to keep track of number of tasks that are being run\n", - "\n", - "for aoi_name in list_of_countries:\n", - "\n", - " aoi = admin_boundaries.filter(ee.Filter.eq(admin_asset_property_name,aoi_name))#.first()\n", - "\n", - " # gets areas of landcover in each mountain belt in each country\n", - " # uses reduce_regions function imported from the cloned sepal_mgci git hub repository (see Imports section)\n", - " # pixels counted at native resolution (scale) of input land cover (or DEM if RSA implementation)\n", - " process = ee.FeatureCollection([\n", - " ee.Feature(\n", - " None,\n", - " reduce_regions(\n", - " aoi,\n", - " remap_matrix=default_map_matrix,\n", - " rsa=False,\n", - " # dem=param.DEM_DEFAULT,\n", - " dem=DEM_DEFAULT, #default digital elevation model (DEM). Relevant for the real surface area (RSA) implementation.\n", - " lc_years= year,\n", - " transition_matrix=False\n", - " )\n", - " ).set(\"process_id\", year[0][\"year\"])\n", - " for year in get_a_years(a_years) # creates GEE images and runs stats on each. Images to run are in the 'a_years\" dictionary (above)\n", - " ])\n", - "\n", - " #make name acceptable for running tasks (i.e., removes special characters)\n", - " task_name = str(sanitize_description(unidecode(aoi_name)))\n", - "\n", - "\n", - " task = ee.batch.Export.table.toDrive(\n", - " **{ #asterisks unpack dictionary into keyword arguments format\n", - " \"collection\": process,\n", - " \"description\": task_name,\n", - " \"fileFormat\": \"CSV\",\n", - " \"folder\":stats_csv_folder,\n", - " \"selectors\": [\n", - " \"process_id\",\n", - " \"sub_a\",\n", - " ],\n", - " }\n", - " )\n", - "\n", - " counter+=1\n", - "\n", - " print (f\"\\r process {counter}/{len(list_of_countries)} {aoi_name} \", end=\"\") #print in place (remove \\r and end=\"\" for verbose version)\n", - "\n", - " if export:\n", - " task.start()\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "vM0SIvJtu_f8" - }, - "source": [ - "### 9) Read and translate results into report tables" - ] - }, - { - "cell_type": "markdown", - "source": [ - "#####NOTE: you will need to wait until results files for each country have been created in your google drive (from previous step).\n", - "- see here to monitor the tasks https://code.earthengine.google.com/tasks\n", - "- once tasks are complete, you can run the cell below\n", - "\n", - "This cell formats individual excel reports for each country.\n", - "See Error_log.csv for missing files/errors" - ], - "metadata": { - "id": "3x7jwkZJWwE-" - } - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "qkpDfHqQu_f9" - }, - "outputs": [], - "source": [ - "# Initialize the counter\n", - "counter = 0\n", - "\n", - "# to store outputs in google drive\n", - "create_folder_if_not_exists(excel_reports_folder)\n", - "\n", - "# Loop over each AOI name in the list of countries\n", - "for aoi_name in list_of_countries:\n", - " counter += 1\n", - "\n", - " # Clean the AOI name\n", - " aoi_name_clean = str(sanitize_description(unidecode(aoi_name)))\n", - "\n", - " # Construct the file path for the stats CSV file\n", - " stats_csv_file = aoi_name_clean + \".csv\"\n", - " stats_csv_file_path = os.path.join(drive_home, stats_csv_folder, stats_csv_file)\n", - "\n", - " message = f\"Process {counter}, {stats_csv_file}\"\n", - "\n", - " try:\n", - " # Read the results from the CSV file and parse it to a dictionary\n", - " dict_results = read_from_csv(stats_csv_file_path)\n", - "\n", - " details = {\n", - " \"geo_area_name\": aoi_name,\n", - " \"ref_area\": \" \",\n", - " \"source_detail\": \" \",\n", - " }\n", - "\n", - " # Generate reports for the sub_a and mtn indicators\n", - " sub_a_reports = [sub_a.get_reports(parse_result(dict_results[year][\"sub_a\"], single=True), year, **details) for year in single_years]\n", - " mtn_reports = [mntn.get_report(parse_result(dict_results[year][\"sub_a\"], single=True), year, **details) for year in single_years]\n", - "\n", - " # Concatenate the mtn reports\n", - " mtn_reports_df = pd.concat(mtn_reports)\n", - "\n", - " # Concatenate the sub a reports\n", - " er_mtn_grnvi_df = pd.concat([report[0] for report in sub_a_reports])\n", - " er_mtn_grncov_df = pd.concat([report[1] for report in sub_a_reports])\n", - "\n", - " # Define the output report file path\n", - " report_file_path = os.path.join(drive_home, excel_reports_folder, aoi_name_clean + \".xlsx\")\n", - "\n", - " # Create the Excel file with the reports\n", - " with pd.ExcelWriter(report_file_path) as writer:\n", - " mtn_reports_df.to_excel(writer, sheet_name=\"Table1_ER_MTN_TOTL\", index=False)\n", - " er_mtn_grncov_df.to_excel(writer, sheet_name=\"Table2_ER_MTN_GRNCOV\", index=False)\n", - " er_mtn_grnvi_df.to_excel(writer, sheet_name=\"Table3_ER_MTN_GRNCVI\", index=False)\n", - "\n", - " # Adjust column widths and alignment for each sheet\n", - " for sheetname in writer.sheets:\n", - " worksheet = writer.sheets[sheetname]\n", - " for col in worksheet.columns:\n", - " max_length = max(len(str(cell.value)) for cell in col)\n", - " column = col[0]\n", - " adjusted_width = max(max_length, len(str(column.value))) + 4\n", - " worksheet.column_dimensions[get_column_letter(column.column)].width = adjusted_width\n", - "\n", - " # Align \"obs_value\" column to the right\n", - " if \"OBS\" in column.value:\n", - " for cell in col:\n", - " cell.alignment = Alignment(horizontal=\"right\")\n", - "\n", - " except Exception as e:\n", - " # If an error occurs, catch the exception and handle it\n", - " message = f\"process {counter}, {stats_csv_file}, Error: {e}\"\n", - "\n", - " # Get the current time\n", - " current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')\n", - "\n", - " # Write the error message and file name to the error log file\n", - " error_info = pd.DataFrame([[stats_csv_file, str(e), current_time]], columns=['File Name', 'Error Message', 'Time'])\n", - "\n", - " mode = 'w' if not os.path.exists(error_log_file_path) else 'a'\n", - " header = False if os.path.exists(error_log_file_path) else True\n", - "\n", - " # Append or write to the error log file\n", - " error_info.to_csv(error_log_file_path, mode=mode, header=header, index=False)\n", - "\n", - " print(message)\n" - ] - }, - { - "cell_type": "markdown", - "source": [ - "### 10) Combine excel report files into one" - ], - "metadata": { - "id": "qTqI3Ag08k5b" - } - }, - { - "cell_type": "markdown", - "source": [ - "Make a list of files to combine" - ], - "metadata": { - "id": "sVpLtG4Z7Jbe" - } - }, - { - "cell_type": "code", - "source": [ - "# Directory path where Excel reports are stored\n", - "directory_path = os.path.join(drive_home, excel_reports_folder)\n", - "\n", - "# List files in the directory with '.xlsx' extension\n", - "files = [file for file in os.listdir(directory_path) if file.endswith('.xlsx')]\n", - "\n", - "# Create a list of full file paths\n", - "full_file_paths = [os.path.join(directory_path, file) for file in files]\n", - "\n", - "# Print the number of Excel files found in the folder\n", - "print(f\"Number of Excel files in folder: {len(full_file_paths)}\")\n", - "\n", - "# folder to store outputs in google drive\n", - "create_folder_if_not_exists(final_report_folder)\n", - "\n", - "# File path for the combined final report\n", - "reports_combined_file_path = os.path.join(drive_home, final_report_folder, final_report_name)\n" - ], - "metadata": { - "id": "sTyhwne7rr9D" - }, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "##### Run function to combine into a single report" - ], - "metadata": { - "id": "C77flAQu7xWX" - } - }, - { - "cell_type": "code", - "source": [ - "append_excel_files(file_paths=full_file_paths,num_sheets=3,output_file_path=reports_combined_file_path)\n", - "\n", - "print (f\"\\n Complete! Output file for SDG 15.4.2 Sub-indicator A here: {reports_combined_file_path}\")" - ], - "metadata": { - "id": "FkS1ErA9AYj6" - }, - "execution_count": null, - "outputs": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "(test) test-sepal_mgci", - "language": "python", - "name": "test-sepal_mgci" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - }, - "colab": { - "provenance": [], - "include_colab_link": true - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/SDG_15_4_2_Sub_A_Default_values_sepal.ipynb b/SDG_15_4_2_Sub_A_Default_values_sepal.ipynb deleted file mode 100644 index e1f1591..0000000 --- a/SDG_15_4_2_Sub_A_Default_values_sepal.ipynb +++ /dev/null @@ -1,750 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "view-in-github" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "82FWR5yMh0HV" - }, - "source": [ - "# **SDG 15.4.2 Sub-indicator A: Calculate Global Default Values**\n", - "\n", - "* This script allows batch processing for this indicator for all countries.\n", - "\n", - "* Output is a combined excel file on your Google Drive.\n", - "\n", - "* Runs on the cloud using [Google Colab](https://research.google.com/colaboratory/faq.html)\n", - "\n", - "* Requires: [Google Earth Engine](https://earthengine.google.com/) (GEE) account and project and access to Google Drive\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "import ee\n", - "ee.Initialize()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a base directory\n", - "\n", - "base_dir = Path(\"content/sepal_mgci\")\n", - "base_dir.mkdir(parents=True, exist_ok=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "MsQu9VfqZRy3" - }, - "source": [ - "### 5) Import remaining packages\n", - "- imports required packages and functions listed in 'colab_imports.py' script (found here: sepal_mgci/component/scripts)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "id": "NQ9flKZGZRy4" - }, - "outputs": [ - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "/*******************************************************************************\n * remove any links from fontawesome 5 created by jupyter in favor of\n * fontawesome 6. to be removed when Jupyter updates it\n */\n\nfunction remove_fa5() {\n let links = document.querySelectorAll(\n \"link[href^='https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@^5']\"\n );\n\n links.forEach((link) => link.remove());\n}\n\nif (document.readyState != \"loading\") remove_fa5();\nelse document.addEventListener(\"DOMContentLoaded\", remove_fa5);\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import os\n", - "\n", - "from datetime import datetime # for time stamping error log\n", - "import pandas as pd # pandas library for tabular data manipulation\n", - "from unidecode import (\n", - " unidecode,\n", - ") # converting symbols in country names to ascii compliant (required for naming GEE tasks)\n", - "\n", - "# formatting excel report file\n", - "from openpyxl.utils import get_column_letter\n", - "from openpyxl.styles import Alignment\n", - "\n", - "from pathlib import Path\n", - "\n", - "# # # # Import scripts and modules from cloned GitHub repository (i.e., functions for indicator calculation and formatting)\n", - "from component.scripts.gee import (\n", - " reduce_regions,\n", - ") # for running summary statistics in GEE\n", - "\n", - "from component.scripts.scripts import (\n", - " get_a_years,\n", - " map_matrix_to_dict,\n", - " parse_result,\n", - " read_from_csv,\n", - " map_matrix_to_dict,\n", - ") # parameter prep and reformatting\n", - "from component.scripts import (\n", - " sub_a,\n", - " mountain_area as mntn,\n", - ") ###TO DO: ADD DESCRIPTIONS\n", - "\n", - "from component.scripts.colab_combining_files import (\n", - " sanitize_description,\n", - " append_excel_files,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Bi0XpRRDo6V1" - }, - "source": [ - "### 6) Set parameters\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "5aIr_OxkG-Ky" - }, - "source": [ - "Input parameters" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "DEM_DEFAULT = \"CGIAR/SRTM90_V4\"\n", - "\n", - "# Define the translation matrix between ESA and MGCI LC classes\n", - "\n", - "LC_MAP_MATRIX = Path(\"content/corine_lc_map_matrix2.csv\")\n", - "TRANSITION_MATRIX_FILE = Path(\"component/parameter/transition_matrix.csv\")\n", - "\n", - "# Check they both exist\n", - "assert LC_MAP_MATRIX.exists()\n", - "assert TRANSITION_MATRIX_FILE.exists()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "t9C1qT5bGoqt" - }, - "outputs": [], - "source": [ - "# Admin boundaries asset\n", - "admin_asset_id = \"FAO/GAUL/2015/level0\" # administrative units feature collection\n", - "\n", - "admin_asset_property_name = \"ADM0_NAME\" # property/column name for selecting admin boundaries (e.g. ISO3 code or country name)\n", - "\n", - "\n", - "# Land cover assets\n", - "\n", - "# For Sub-indicator A (sub_a), we need to set the following structure.\n", - "a_years = {\n", - " 1: {\"asset\": \"users/amitghosh/sdg_module/esa/cci_landcover/2000\", \"year\": 2000}, # baseline\n", - " 2: {\"year\": 2003, \"asset\": \"users/amitghosh/sdg_module/esa/cci_landcover/2003\"}, # subsequent reporting years...\n", - " 3: {\"year\": 2007, \"asset\": \"users/amitghosh/sdg_module/esa/cci_landcover/2007\"},\n", - " 4: {\"year\": 2010, \"asset\": \"users/amitghosh/sdg_module/esa/cci_landcover/2010\"},\n", - "}\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "naz3Qe4JHFER" - }, - "source": [ - "Output parameters\n", - "\n", - "---\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "mSvTM29TnndR" - }, - "outputs": [], - "source": [ - "final_report_folder = \"sdg_15_4_2_A_combined_report\" # folder name in Google Drive for final output (if doesnt exist creates one)\n", - "\n", - "final_report_name = \"sdg_15_4_2_A_default_global.xlsx\" # file name for final excel output\n", - "\n", - "# export GEE tasks or not\n", - "export = False # default: True. Set to False if debugging or limiting accidental re-exporting of tasks\n", - "\n", - "# prints more messages\n", - "debug = False # default: False. Set to True if debugging code" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "iV8-wbddOJuT" - }, - "source": [ - "Temporary output parameters\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "TCBNkALuOL1N" - }, - "outputs": [], - "source": [ - "stats_csv_folder = \"sdg_15_4_2_A_csvs\" # for storing stats tables exported from GEE for each admin boundary/AOI\n", - "\n", - "excel_reports_folder = \"sdg_15_4_2_A_reports\" # for storing formatted excel tables for each admin boundary/AOI\n", - "\n", - "drive_home =\"/content/drive/MyDrive/\" # Google Drive location. Don't change unless you know this is incorrect\n", - "\n", - "error_log_file_path = drive_home + excel_reports_folder + \"/\"+\"1_error_log\" +\".csv\" # for storing errors\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "c_8UzlUnu_f6" - }, - "source": [ - "### 7) Setup inputs for processing" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "qi5zNGTWN3df" - }, - "source": [ - "Create list of boundaries to process" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "BiuBEJwPue2v" - }, - "outputs": [], - "source": [ - "# admin boundary feature collection\n", - "admin_boundaries = ee.FeatureCollection(admin_asset_id)\n", - "\n", - "# list to process\n", - "list_of_countries = admin_boundaries.aggregate_array(admin_asset_property_name).getInfo()\n", - "\n", - "print (\"Length of admin boundaries to process\", len(list_of_countries))\n", - "\n", - "list_of_countries = list(set(list_of_countries)) # remove dupicates\n", - "\n", - "print (\"Length of distinct admin boundaries to process\", (len(set(list_of_countries))))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "2G1q9TSiUsc1" - }, - "source": [ - "Read the default land cover remapping table and convert it to a dictionary" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "PRSEqq5bu_f7" - }, - "outputs": [], - "source": [ - "default_map_matrix = map_matrix_to_dict(LC_MAP_MATRIX)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "4-Ut_-S35Yg8" - }, - "source": [ - "Select years of land cover to process" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 17 - }, - "id": "PwqJFWR4u_f7", - "outputId": "09d3ab98-6b20-4212-b5ed-f3386c3a32bf" - }, - "outputs": [], - "source": [ - "# extracts the years from the a_years dictionary (as defined in parameters)\n", - "single_years = [y[\"year\"] for y in a_years.values()]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "iNxHtR984cNk" - }, - "source": [ - "### 8) Calculate area statistics by country\n", - "* Runs for each country and each mountain biobelt\n", - "* Gets area of land cover reclassified into the 10 SEAM classes\n", - "* Repeat for each year specified\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "VftKLuY4u_f7" - }, - "outputs": [], - "source": [ - "# you can monitor your GEE tasks here : https://code.earthengine.google.com/tasks\n", - "create_folder_if_not_exists(stats_csv_folder) # to store outputs in google drive\n", - "\n", - "counter=0 # starting place of counter used to keep track of number of tasks that are being run\n", - "\n", - "for aoi_name in list_of_countries:\n", - "\n", - " aoi = admin_boundaries.filter(ee.Filter.eq(admin_asset_property_name,aoi_name))#.first()\n", - "\n", - " # gets areas of landcover in each mountain belt in each country\n", - " # uses reduce_regions function imported from the cloned sepal_mgci git hub repository (see Imports section)\n", - " # pixels counted at native resolution (scale) of input land cover (or DEM if RSA implementation)\n", - " process = ee.FeatureCollection([\n", - " ee.Feature(\n", - " None,\n", - " reduce_regions(\n", - " aoi,\n", - " remap_matrix=default_map_matrix,14 test sepal_mgci /home/dguerrero/module-venv/sepal_mgci\n", - " dem=DEM_DEFAULT, #default digital elevation model (DEM). Relevant for the real surface area (RSA) implementation.\n", - " lc_years= year,\n", - " transition_matrix=False\n", - " )\n", - " ).set(\"process_id\", year[0][\"year\"])\n", - " for year in get_a_years(a_years) # creates GEE images and runs stats on each. Images to run are in the 'a_years\" dictionary (above)\n", - " ])\n", - "\n", - " #make name acceptable for running tasks (i.e., removes special characters)\n", - " task_name = str(sanitize_description(unidecode(aoi_name)))\n", - "\n", - "\n", - " task = ee.batch.Export.table.toDrive(\n", - " **{ #asterisks unpack dictionary into keyword arguments format\n", - " \"collection\": process,\n", - " \"description\": task_name,\n", - " \"fileFormat\": \"CSV\",\n", - " \"folder\":stats_csv_folder,\n", - " \"selectors\": [\n", - " \"process_id\",\n", - " \"sub_a\",\n", - " ],\n", - " }\n", - " )\n", - "\n", - " counter+=1\n", - "\n", - " print (f\"\\r process {counter}/{len(list_of_countries)} {aoi_name} \", end=\"\") #print in place (remove \\r and end=\"\" for verbose version)\n", - "\n", - " if export:\n", - " task.start()\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "vM0SIvJtu_f8" - }, - "source": [ - "### 9) Read and translate results into report tables" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "3x7jwkZJWwE-" - }, - "source": [ - "#####NOTE: you will need to wait until results files for each country have been created in your google drive (from previous step).\n", - "- see here to monitor the tasks https://code.earthengine.google.com/tasks\n", - "- once tasks are complete, you can run the cell below\n", - "\n", - "This cell formats individual excel reports for each country.\n", - "See Error_log.csv for missing files/errors" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "qkpDfHqQu_f9" - }, - "outputs": [], - "source": [ - "# Initialize the counter\n", - "counter = 0\n", - "\n", - "# to store outputs in google drive\n", - "create_folder_if_not_exists(excel_reports_folder)\n", - "\n", - "# Loop over each AOI name in the list of countries\n", - "for aoi_name in list_of_countries:\n", - " counter += 1\n", - "\n", - " # Clean the AOI name\n", - " aoi_name_clean = str(sanitize_description(unidecode(aoi_name)))\n", - "\n", - " # Construct the file path for the stats CSV file\n", - " stats_csv_file = aoi_name_clean + \".csv\"\n", - " stats_csv_file_path = os.path.join(drive_home, stats_csv_folder, stats_csv_file)\n", - "\n", - " message = f\"Process {counter}, {stats_csv_file}\"\n", - "\n", - " try:\n", - " # Read the results from the CSV file and parse it to a dictionary\n", - " dict_results = read_from_csv(stats_csv_file_path)\n", - "\n", - " details = {\n", - " \"geo_area_name\": aoi_name,\n", - " \"ref_area\": \" \",\n", - " \"source_detail\": \" \",\n", - " }\n", - "\n", - " # Generate reports for the sub_a and mtn indicators\n", - " sub_a_reports = [sub_a.get_reports(parse_result(dict_results[year][\"sub_a\"], single=True), year, **details) for year in single_years]\n", - " mtn_reports = [mntn.get_report(parse_result(dict_results[year][\"sub_a\"], single=True), year, **details) for year in single_years]\n", - "\n", - " # Concatenate the mtn reports\n", - " mtn_reports_df = pd.concat(mtn_reports)\n", - "\n", - " # Concatenate the sub a reports\n", - " er_mtn_grnvi_df = pd.concat([report[0] for report in sub_a_reports])\n", - " er_mtn_grncov_df = pd.concat([report[1] for report in sub_a_reports])\n", - "\n", - " # Define the output report file path\n", - " report_file_path = os.path.join(drive_home, excel_reports_folder, aoi_name_clean + \".xlsx\")\n", - "\n", - " # Create the Excel file with the reports\n", - " with pd.ExcelWriter(report_file_path) as writer:\n", - " mtn_reports_df.to_excel(writer, sheet_name=\"Table1_ER_MTN_TOTL\", index=False)\n", - " er_mtn_grncov_df.to_excel(writer, sheet_name=\"Table2_ER_MTN_GRNCOV\", index=False)\n", - " er_mtn_grnvi_df.to_excel(writer, sheet_name=\"Table3_ER_MTN_GRNCVI\", index=False)\n", - "\n", - " # Adjust column widths and alignment for each sheet\n", - " for sheetname in writer.sheets:\n", - " worksheet = writer.sheets[sheetname]\n", - " for col in worksheet.columns:\n", - " max_length = max(len(str(cell.value)) for cell in col)\n", - " column = col[0]\n", - " adjusted_width = max(max_length, len(str(column.value))) + 4\n", - " worksheet.column_dimensions[get_column_letter(column.column)].width = adjusted_width\n", - "\n", - " # Align \"obs_value\" column to the right\n", - " if \"OBS\" in column.value:\n", - " for cell in col:\n", - " cell.alignment = Alignment(horizontal=\"right\")\n", - "\n", - " except Exception as e:\n", - " # If an error occurs, catch the exception and handle it\n", - " message = f\"process {counter}, {stats_csv_file}, Error: {e}\"\n", - "\n", - " # Get the current time\n", - " current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')\n", - "\n", - " # Write the error message and file name to the error log file\n", - " error_info = pd.DataFrame([[stats_csv_file, str(e), current_time]], columns=['File Name', 'Error Message', 'Time'])\n", - "\n", - " mode = 'w' if not os.path.exists(error_log_file_path) else 'a'\n", - " header = False if os.path.exists(error_log_file_path) else True\n", - "\n", - " # Append or write to the error log file\n", - " error_info.to_csv(error_log_file_path, mode=mode, header=header, index=False)\n", - "\n", - " print(message)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "qTqI3Ag08k5b" - }, - "source": [ - "### 10) Combine excel report files into one" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "sVpLtG4Z7Jbe" - }, - "source": [ - "Make a list of files to combine" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "sTyhwne7rr9D" - }, - "outputs": [], - "source": [ - "# Directory path where Excel reports are stored\n", - "directory_path = os.path.join(drive_home, excel_reports_folder)\n", - "\n", - "# List files in the directory with '.xlsx' extension\n", - "files = [file for file in os.listdir(directory_path) if file.endswith('.xlsx')]\n", - "\n", - "# Create a list of full file paths\n", - "full_file_paths = [os.path.join(directory_path, file) for file in files]\n", - "\n", - "# Print the number of Excel files found in the folder\n", - "print(f\"Number of Excel files in folder: {len(full_file_paths)}\")\n", - "\n", - "# folder to store outputs in google drive\n", - "create_folder_if_not_exists(final_report_folder)\n", - "\n", - "# File path for the combined final report\n", - "reports_combined_file_path = os.path.join(drive_home, final_report_folder, final_report_name)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "C77flAQu7xWX" - }, - "source": [ - "##### Run function to combine into a single report" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "FkS1ErA9AYj6" - }, - "outputs": [], - "source": [ - "append_excel_files(file_paths=full_file_paths,num_sheets=3,output_file_path=reports_combined_file_path)\n", - "\n", - "print (f\"\\n Complete! Output file for SDG 15.4.2 Sub-indicator A here: {reports_combined_file_path}\")" - ] - } - ], - "metadata": { - "colab": { - "include_colab_link": true, - "provenance": [] - }, - "kernelspec": { - "display_name": "(test) test-sepal_mgci", - "language": "python", - "name": "test-sepal_mgci" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.4" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/Global_Sepal_SDG_15_4_2_Sub_A_Default_values.ipynb b/Sepal_Global_SDG_15_4_2_Sub_A_Default_values.ipynb similarity index 100% rename from Global_Sepal_SDG_15_4_2_Sub_A_Default_values.ipynb rename to Sepal_Global_SDG_15_4_2_Sub_A_Default_values.ipynb diff --git a/Global_Sepal_SDG_15_4_2_Sub_B_Default_values.ipynb b/Sepal_Global_SDG_15_4_2_Sub_B_Default_values.ipynb similarity index 99% rename from Global_Sepal_SDG_15_4_2_Sub_B_Default_values.ipynb rename to Sepal_Global_SDG_15_4_2_Sub_B_Default_values.ipynb index 3b6cbd8..2a98598 100644 --- a/Global_Sepal_SDG_15_4_2_Sub_B_Default_values.ipynb +++ b/Sepal_Global_SDG_15_4_2_Sub_B_Default_values.ipynb @@ -621,9 +621,9 @@ "provenance": [] }, "kernelspec": { - "display_name": "(test) test-sepal_mgci", + "display_name": "mgci", "language": "python", - "name": "test-sepal_mgci" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -635,7 +635,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.15" } }, "nbformat": 4, diff --git a/component/tile/aoi_view.py b/component/tile/aoi_view.py index 29e1ca4..11875a5 100644 --- a/component/tile/aoi_view.py +++ b/component/tile/aoi_view.py @@ -80,9 +80,10 @@ def _update_legend(result): try: map_.zoom = 4 - aoi = aoi_model.feature_collection.geometry().simplify(1000) + aoi = aoi_model.feature_collection.geometry() map_.zoom_ee_object(aoi.bounds()) - biobelt = ee.Image(BIOBELT).clip(aoi) + + biobelt = ee.Image(BIOBELT).clip(aoi.simplify(1000)) map_.addLayer(biobelt, BIOBELT_VIS, cm.aoi.legend.belts) except Exception as e: