Source code for geochemistrypi.data_mining.plot.map_plot

# -*- coding: utf-8 -*-
import logging
import os

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from rich import print

from ..constants import MLFLOW_ARTIFACT_IMAGE_MAP_PATH, OPTION, SECTION
from ..data.data_readiness import limit_num_input, num2option, num_input, show_data_columns
from ..utils.base import clear_output, get_os, save_data, save_fig

logging.captureWarnings(True)


[docs] def map_projected_by_cartopy(col: pd.Series, name_column: str, longitude: pd.DataFrame, latitude: pd.DataFrame) -> None: """Project an element data into world map using cartopy. Parameters ---------- col : pd.Series One selected column from the data sheet. longitude : pd.DataFrame Longitude data of data items. latitude : pd.DataFrame Latitude data of data items. """ try: import cartopy import cartopy.crs as ccrs except ImportError: print("The cartopy package is not installed. Please install it first.") print("For example, you can run the following command in your terminal:") print("pip install cartopy") print("conda install -c conda-forge cartopy") return M = col # Create a new figure with the desired size and DPI plt.figure(figsize=(24, 16), dpi=300) # Set the font style plt.rcParams["font.sans-serif"] = "Arial" # Create a Robinson projection centered at the equator projection = ccrs.Robinson(central_longitude=0, globe=None, false_easting=0, false_northing=0) # Create a new axis with the Robinson projection ax = plt.axes(projection=projection) # Add coastlines and borders ax.coastlines() ax.add_feature(cartopy.feature.BORDERS) # Set the map boundaries and fill color ax.set_global() ax.set_facecolor("white") # Define parallels and meridians parallels = np.arange(-90.0, 90.0, 45.0) meridians = np.arange(-180.0, 180.0, 60.0) # Draw parallels and meridians ax.gridlines(draw_labels=True, linewidth=0.5, color="gray", alpha=0.5, linestyle="--", xlocs=meridians, ylocs=parallels) # Set the color values if type(M) != type(longitude): M = [0.5 for i in range(len(M))] # Create a scatter plot with color and size parameters sc = ax.scatter(longitude, latitude, c=pd.DataFrame(M), edgecolor="grey", transform=ccrs.PlateCarree(), linewidths=0.5, vmax=3, vmin=0, s=25, alpha=0.6, cmap="BuPu") # Add colorbar cbar = plt.colorbar(sc, ax=ax, fraction=0.01, pad=0.1) cbar.ax.tick_params(labelsize=30) cbar.set_label("Counts", fontsize=30) # save figure and data data = pd.concat([col, longitude, latitude], axis=1) save_fig(f"Map Projection - {col.name}", os.getenv("GEOPI_OUTPUT_ARTIFACTS_IMAGE_MAP_PATH"), MLFLOW_ARTIFACT_IMAGE_MAP_PATH) save_data(data, name_column, f"Map Projection - {col.name}", os.getenv("GEOPI_OUTPUT_ARTIFACTS_IMAGE_MAP_PATH"), MLFLOW_ARTIFACT_IMAGE_MAP_PATH)
[docs] def map_projected_by_basemap(col: pd.Series, name_column: str, longitude: pd.DataFrame, latitude: pd.DataFrame) -> None: """Project an element data into world map using basemap. Parameters ---------- col : pd.Series One selected column from the data sheet. longitude : pd.DataFrame Longitude data of data items. latitude : pd.DataFrame Latitude data of data items. """ try: from mpl_toolkits.basemap import Basemap except ImportError: print("The basemap package is not installed. Please install it first.") print("For example, you can run the following command in your terminal:") print("pip install basemap") print("conda install -c conda-forge basemap") return M = col plt.figure(figsize=(24, 16), dpi=300) plt.rcParams["font.sans-serif"] = "Arial" m = Basemap(projection="robin", lat_0=0, lon_0=0) m.drawcoastlines() m.drawcountries() m.drawmapboundary(fill_color="white") parallels = np.arange(-90.0, 90.0, 45.0) m.drawparallels(parallels, labels=[True, True, True, False], fontsize=30) meridians = np.arange(-180.0, 180.0, 60.0) m.drawmeridians(meridians, labels=[True, False, True, True], fontsize=30) lon, lat = m(longitude, latitude) if type(M) != type(longitude): M = [0.5 for i in range(len(M))] m.scatter(lon, lat, c=M, edgecolor="grey", marker="D", linewidths=0.5, vmax=3, vmin=0, s=25, alpha=0.3, cmap="BuPu") cb = m.colorbar(pad=1) cb.ax.tick_params(labelsize=30) cb.set_label("Counts", fontsize=50) data = pd.concat([col, longitude, latitude], axis=1) save_fig(f"Map Projection - {col.name}", os.getenv("GEOPI_OUTPUT_ARTIFACTS_IMAGE_MAP_PATH"), MLFLOW_ARTIFACT_IMAGE_MAP_PATH) save_data(data, name_column, f"Map Projection - {col.name}", os.getenv("GEOPI_OUTPUT_ARTIFACTS_IMAGE_MAP_PATH"), MLFLOW_ARTIFACT_IMAGE_MAP_PATH)
[docs] def process_world_map(data: pd.DataFrame, name_column: str) -> None: """The process of projecting the data on the world map.""" map_flag = 0 is_map_projection = 0 detection_index = 0 lon = ["LONGITUDE", "Longitude (°E)", "longitude", "Longitude", "经度 (°N)", "经度", "lng"] lat = ["LATITUDE", "Latitude (°N)", "latitude", "Latitude", "纬度 (°E)", "纬度", "lat"] j = [j for j in lat if j in data.columns] i = [i for i in lon if i in data.columns] if bool(len(j) > 0): detection_index += 1 if bool(len(i) > 0): detection_index += 2 if detection_index == 2: print("The provided data set is lack of 'LATITUDE' data.") elif detection_index == 1: print("The provided data set is lack of 'LONGITUDE' data.") elif detection_index == 0: print("The provided data set is lack of 'LONGITUDE' and 'LATITUDE' data.") if detection_index != 3: print("Hence, world map projection functionality will be skipped!") clear_output() # If the data set contains both longitude and latitude data, then the user can choose to project the data on the world map. while detection_index == 3: if map_flag != 1: # Check if the user wants to project the data on the world map. print("World Map Projection for A Specific Element Option:") num2option(OPTION) is_map_projection = limit_num_input(OPTION, SECTION[3], num_input) clear_output() if is_map_projection == 1: # If the user chooses to project the data on the world map, then the user can select the element to be projected. print("[bold green]-*-*- Distribution in World Map -*-*-[/bold green]") print("Select one of the elements below to be projected in the World Map: ") show_data_columns(data.columns) elm_num = limit_num_input(data.columns, SECTION[3], num_input) clear_output() latitude = data.loc[:, j] longitude = data.loc[:, i] print("Longitude and latitude data are selected from the provided data set.") # If OS is Windows or Linux, then use basemap to project the data on the world map. # If OS is macOS, then use cartopy to project the data on the world map. my_os = get_os() if my_os == "Windows" or my_os == "Linux": map_projected_by_basemap(data.iloc[:, elm_num - 1], name_column, longitude, latitude) elif my_os == "macOS": map_projected_by_cartopy(data.iloc[:, elm_num - 1], name_column, longitude, latitude) clear_output() print("Do you want to continue to project a new element in the World Map?") num2option(OPTION) map_flag = limit_num_input(OPTION, SECTION[3], num_input) if map_flag == 1: clear_output() continue else: print("Exit Map Projection Mode.") clear_output() break elif is_map_projection == 2: break
# def map_projected(col: pd.Series, longitude: pd.DataFrame, latitude: pd.DataFrame) -> None: # """Project an element data into world map. # Parameters # ---------- # col : pd.Series # One selected column from the data sheet. # longitude : pd.DataFrame # Longitude data of data items. # latitude : pd.DataFrame # Latitude data of data items. # """ # # Create point geometries # geometry = geopandas.points_from_xy(longitude, latitude) # geo_df = geopandas.GeoDataFrame(pd.concat([col, longitude, latitude], axis=1), geometry=geometry) # world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres')) # # Make figure # fig, ax = plt.subplots(figsize=(24, 18)) # divider = make_axes_locatable(ax) # cax = divider.append_axes("right", size="5%", pad=0.1) # world.plot(ax=ax, alpha=0.4, color='grey', edgecolor='black') # geo_df.plot(col.name, ax=ax, s=20, cmap='gist_heat_r', cax=cax, legend=True) # plt.title('colorbar') # save_fig(f"Map Projection - {col.name}", MAP_IMAGE_PATH)