<jupyter_start><jupyter_text>Climate Change Risk Dashboard This dashboard is an example of highlighting risks due to climate change. In this case we study the mainland US and explore risk as a function of global heating, over the period of 1860 - 2100, and comparing the climatic future scenarios A1B and E1.A measure of human vulnerability and risk is also synthesized and shown as points over the centres of each state. Vulnerability to the hazard (global heating) is shown by the brightness of the point, and the risk the hazard poses is shown by the size of the point.<jupyter_code>import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader

import colorcet as cc

import geoviews.feature as gf
import hvplot.pandas

import numpy as np

import geopandas as gpd
import pandas as pd

import panel as pn

import param
pn.extension()
# Load US states shapefile data.
us_states_name = shpreader.natural_earth(
    category="cultural",
    name="admin_1_states_provinces")

us_states = gpd.read_file(us_states_name)
# We only need to keep a few columns of data from the US states geodataframe (gdf).
gdf_drop_cols = list(set(us_states.columns) - set(["name", 'gn_a1_code', "geometry"]))
# Load pre-processed climate data to drive the temperature element of the dashboard.
data = pd.read_csv("../etc/data/preprocessed_data_v2.csv")
# Combine the data into one geodataframe.
all_data = gpd.GeoDataFrame(pd.merge(data, us_states.drop(columns=gdf_drop_cols),
                                     left_on="state", right_on='gn_a1_code')
                           ).drop(columns=["state", "gn_a1_code"])
# Add columns for the area and the centre of the geometry.
all_data["area"] = all_data.apply(lambda r: r["geometry"].area, axis=1)
# We do these two separately for the sake of simplicity.
all_data["latitude"] = all_data.apply(lambda r: r["geometry"].centroid.y, axis=1, result_type="expand")
all_data["longitude"] = all_data.apply(lambda r: r["geometry"].centroid.x, axis=1, result_type="expand")
# Normalisation functions.
def _norm(v, vmin, vmax, dmin, dmax):
    return ((v - vmin) / (vmax - vmin)) * (dmax - dmin) + dmin

def quicknorm(v, vmin, vmax):
    return _norm(v, vmin, vmax, dmin=0, dmax=1)

def offsetnorm(v, vmin, vmax, dmin=10, dmax=50):
    return _norm(v, vmin, vmax, dmin, dmax)
def synthetic_vuln_data(r):
    """
    Generate synthetic vulnerability data for each state and year.
    
    Vulnerability is synthesized as the product of the state area (as a 
    bad proxy for total population), the year offset from 2000 (with years
    prior to this date being normalised to 1) and a random factor between
    0.8 and 1.2.
    
    The entire vulernability value is then normalised into the interval (10, 50).
    
    """
    yc = 2000
    year = r["year"]
    if year > yc:
        y_offset = year - yc
        power_factor = 1
    else:
        y_offset = 1
        power_factor = 0
    
    pop = r["area"]
    rnd_factor = np.random.randint(8000, 12000) / 10000
    
    vuln = (y_offset * pop * rnd_factor) ** power_factor
    return offsetnorm(vuln, 1, 20000, 10, 50)

# Add the synthetic vulnerability data to the geodataframe.
all_data["vuln"] = all_data.apply(synthetic_vuln_data, axis=1)
class ClimateRiskInterface(param.Parameterized):
    # Set params that add specific interactivity to the plot.
    rcp = param.ObjectSelector(default="a1b", objects=["a1b", "e1"], label="RCP")
    anomaly_period = param.ObjectSelector(default="1971-2000",
                                          objects=["1971-2000", "1981-2010", "1991-2020"])
    year = param.Integer(default=2021, bounds=(1860, 2099))
    show_temp = param.ObjectSelector(default="air temp", objects=["air temp", "anomaly"],
                                     label="Temperature displayed")
    alpha = param.Number(default=0.4, bounds=(0.1, 0.9), label="Fill alpha")
    show_vuln = param.Boolean(default=False, label="Show risk")
    
    # Set some defaults.
    tmin = min(all_data["mean_temp"]) - 2.5
    tmax = max(all_data["mean_temp"]) + 2.5
    dmin, dmax = -7.5, 7.5
    
    def prepare_data(self, data):
        """Set up the data to show in the filled polygons."""
        if self.show_temp == "anomaly":
            result = data["mean_temp"] - data[self.anomaly_period]
        else:
            result = data["mean_temp"]
        return result
        
    def risk_data(self, data):
        """Calculate the size of the risk indicator points."""
        return data["vuln"] * (data["mean_temp"] - data[self.anomaly_period]) * 5

    def choose_cmap(self):
        """
        Allow a different colormap for showing absolute temperature data vs
        anomaly data.
        
        """
        return cc.cm.CET_D9 if self.show_temp == "anomaly" else cc.cm.CET_L4

    def choose_clim(self):
        """Allow different colorbar limits (clim) for absolute and anomaly maps."""
        return (self.dmin, self.dmax) if self.show_temp == "anomaly" else (self.tmin, self.tmax)
    
    @param.depends("rcp", "year", "anomaly_period", "show_vuln", "show_temp", "alpha")
    def plot(self):
        """Plot all the elements of the map."""
        data = all_data[(all_data["rcp"] == self.rcp) & (all_data["year"] == self.year)]
        
        # Plot mean / anomaly from climatic period temperature values as filled state polygons.
        polyplot = data.hvplot.polygons(geo=True,
                                        c=self.prepare_data(data),
                                        hover_cols=["name", "mean_temp", "vuln"]).opts(
            toolbar="above", clim=self.choose_clim(), alpha=self.alpha,
            projection=ccrs.LambertConformal(),
            cmap=self.choose_cmap(), colorbar=True)
        
        if self.show_vuln:
            # Optionally also plot varying-size points to indicate risk in each state.
            pointplot = data.hvplot.points("longitude", "latitude", geo=True,
                                           color="vuln", size=self.risk_data(data),
                                           hover_cols="name").opts(
                projection=ccrs.LambertConformal(), cmap="viridis", clim=(5, 30))
            result = (gf.coastline * polyplot * pointplot)
        else:
            result = (gf.coastline * polyplot)
        
        return result.opts(width=1200, height=800)
interface = ClimateRiskInterface()
pn.Row(interface.param, interface.plot).servable()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11140378060117756, 'fraction_numerical': 0.02215680198326619, 'mean_word_length': 2.8468414779499405, 'pattern_counts': {'":': 1, '<': 5, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '329207', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2119, 'n_tokens_neox': 1964, 'n_words': 595, 'path': 'cchd/climate_change_risk_dashboard_eg.ipynb', 'repo_name': 'informatics-lab/cchd', 'size': '6454'}