Source code for RCAIDE.Library.Plots.Topography.plot_elevation_contours

# RCAIDE/Library/Plots/Topography/plot_elevation_contours.py
# 
# 
# Created:  Jul 2023, M. Clarke 

# ----------------------------------------------------------------------------------------------------------------------
#  IMPORT
# ----------------------------------------------------------------------------------------------------------------------   
from RCAIDE.Framework.Core                             import Units
from RCAIDE.Framework.Analyses.Geodesics.Geodesics import Calculate_Distance
from RCAIDE.Library.Plots.Common import plot_style

# python imports 
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
import matplotlib.colors 
import numpy as np 

# ----------------------------------------------------------------------------------------------------------------------
#  PLOTS
# ----------------------------------------------------------------------------------------------------------------------    
[docs] def plot_elevation_contours(topography_file, number_of_latitudinal_points = 100, number_of_longitudinal_points = 100, use_lat_long_coordinates = True, save_figure = False, show_legend = True, save_filename = "Elevation_Contours", file_type = ".png", width = 11, height = 7): """ Creates a contour plot visualization of terrain elevation data. Parameters ---------- topography_file : str Path to file containing topographical data in format: * Column 1: Longitude [degrees] * Column 2: Latitude [degrees] * Column 3: Elevation [meters] number_of_latitudinal_points : int, optional Number of interpolation points in latitude direction (default: 100) number_of_longitudinal_points : int, optional Number of interpolation points in longitude direction (default: 100) use_lat_long_coordinates : bool, optional If True, plot in lat/long coordinates If False, plot in distance coordinates (default: True) save_figure : bool, optional Flag for saving the figure (default: False) show_legend : bool, optional Flag to display elevation legend (default: True) save_filename : str, optional Name of file for saved figure (default: "Elevation_Contours") file_type : str, optional File extension for saved figure (default: ".png") width : float, optional Figure width in inches (default: 11) height : float, optional Figure height in inches (default: 7) Returns ------- fig : matplotlib.figure.Figure Notes ----- Creates visualization showing terrain elevation contours, color-coded elevation levels, geographic or distance-based coordinates, and a custom terrain-specific colormap. When use_lat_long_coordinates is True the X-axis is Longitude [degrees] and the Y-axis is Latitude [degrees]. When use_lat_long_coordinates is False the X-axis is Longitudinal Distance [nmi] and the Y-axis is Latitudinal Distance [nmi]. **Major Assumptions** * Earth is approximated as spherical for distance calculations * Linear interpolation between data points * Sea level reference at 0 elevation * Positive elevations above sea level * Negative elevations below sea level **Definitions** 'Elevation' Height above sea level 'Contour' Line of constant elevation 'Great Circle Distance' Shortest distance between points on sphere 'Terrain' Surface topography of land See Also -------- RCAIDE.Framework.Analyses.Geodesics.Geodesics.Calculate_Distance : Distance calculation """ # get plotting style ps = plot_style() parameters = {'axes.labelsize': ps.axis_font_size, 'xtick.labelsize': ps.axis_font_size, 'ytick.labelsize': ps.axis_font_size, 'axes.titlesize': ps.title_font_size} plt.rcParams.update(parameters) colors_undersea = plt.cm.terrain(np.linspace(0, 0.17, 56)) colors_land = plt.cm.terrain(np.linspace(0.25, 1, 200)) # combine them and build a new colormap colors = np.vstack((colors_undersea, colors_land)) cut_terrain_map = matplotlib.colors.LinearSegmentedColormap.from_list('cut_terrain', colors) data = np.loadtxt(topography_file) Long = data[:,0] Lat = data[:,1] Elev = data[:,2] x_min_coord = np.min(Lat) x_max_coord = np.max(Lat) y_min_coord = np.min(Long) y_max_coord = np.max(Long) if np.min(Long)>180: y_min_coord = np.min(Long)-360 if np.max(Long)>180: y_max_coord = np.max(Long)-360 top_left_map_coords = np.array([x_max_coord,y_min_coord]) bottom_left_map_coords = np.array([x_min_coord,y_min_coord]) top_right_map_coords = np.array([x_max_coord,y_max_coord]) bottom_right_map_coords = np.array([x_min_coord,y_max_coord]) x_dist_max = Calculate_Distance(top_left_map_coords,bottom_left_map_coords) * Units.kilometers y_dist_max = Calculate_Distance(bottom_right_map_coords,bottom_left_map_coords) * Units.kilometers [long_dist,lat_dist] = np.meshgrid(np.linspace(0,y_dist_max,number_of_longitudinal_points),np.linspace(0,x_dist_max,number_of_latitudinal_points)) [long_deg,lat_deg] = np.meshgrid(np.linspace(np.min(Long),np.max(Long),number_of_longitudinal_points),np.linspace(np.min(Lat),np.max(Lat),number_of_latitudinal_points)) elevation = griddata((Lat,Long), Elev, (lat_deg, long_deg), method='linear') elevation = elevation/Units.feet norm = FixPointNormalize(sealevel=0,vmax=np.max(elevation),vmin=np.min(elevation)) fig = plt.figure(save_filename) fig.set_size_inches(width,height) axis = fig.add_subplot(1,1,1) if use_lat_long_coordinates: CS = axis.contourf(long_deg,lat_deg,elevation,cmap =cut_terrain_map,norm=norm,levels = 20) cbar = fig.colorbar(CS, ax=axis) cbar.ax.set_ylabel('Elevation above sea level [ft]', rotation = 90) axis.set_xlabel('Longitude [°]') axis.set_ylabel('Latitude [°]') else: CS = axis.contourf(long_dist/Units.nmi,lat_dist/Units.nmi,elevation,cmap =cut_terrain_map,norm=norm,levels = 20) cbar = fig.colorbar(CS, ax=axis) cbar.ax.set_ylabel('Elevation above sea level [ft]', rotation = 90) axis.set_xlabel('Longitudinal Distance [nmi]') axis.set_ylabel('Latitudinal Distance [nmi]') return fig
[docs] class FixPointNormalize(matplotlib.colors.Normalize): """ Inspired by https://stackoverflow.com/questions/20144529/shifted-colorbar-matplotlib Subclassing Normalize to obtain a colormap with a fixpoint somewhere in the middle of the colormap. This may be useful for a `terrain` map, to set the "sea level" to a color in the blue/turquise range. """
[docs] def __init__(self, vmin=None, vmax=None, sealevel=0, col_val = 0.21875, clip=False): # sealevel is the fix point of the colormap (in data units) self.sealevel = sealevel # col_val is the color value in the range [0,1] that should represent the sealevel. self.col_val = col_val matplotlib.colors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None): x, y = [self.vmin, self.sealevel, self.vmax], [0, self.col_val, 1] return np.ma.masked_array(np.interp(value, x, y))