Featured paper: Graphical Abstract

Alexander Dunkel, Leibniz Institute of Ecological Urban and Regional Development,
Transformative Capacities & Research Data Centre (IÖR-FDZ)

Publication:
Dunkel, A., Burghardt, D. (2024). Assessing perceived landscape change from opportunistic spatio-temporal occurrence data. Land 2024

No description has been provided for this image

This notebook creates the graphical abstract for use as featured paper in LAND (13/7)

Preparations

We first want to get a globe view of all coordinates under investigation in the paper. For this, we use geoplot.

We can update our base worker_env with this package.

In [16]:
!../py/modules/base/pkginstall.sh "geoplot alphashape"
Installed geoplot 0.5.1.
Installed alphashape 1.3.1.
In [17]:
import sys
import warnings
import alphashape
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
import geopandas as gp
import cartopy
import seaborn as sns
import geoplot
import geoplot.crs as gcrs
from matplotlib.patches import Patch
from matplotlib.lines import Line2D
import matplotlib.patches as mpatches
In [18]:
module_path = str(Path.cwd().parents[0] / "py")
if module_path not in sys.path:
    sys.path.append(module_path)
from modules.base import tools, hll
from modules.base.hll import union_hll, cardinality_hll
In [19]:
%load_ext autoreload
%autoreload 2
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload
In [20]:
OUTPUT = Path.cwd().parents[0] / "out"       # output directory for figures (etc.)
WORK_DIR = Path.cwd().parents[0] / "tmp"     # Working directory
(OUTPUT / "figures").mkdir(exist_ok=True)
(OUTPUT / "svg").mkdir(exist_ok=True)
WORK_DIR.mkdir(exist_ok=True)
In [21]:
DATA_FOLDER = Path.cwd().parents[0] / "00_data"
CRS_WGS = "epsg:4326" # WGS1984
In [22]:
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = ['Times New Roman'] + plt.rcParams['font.serif']

Create globe

In [23]:
world = tools.get_shapes("world", shape_dir=OUTPUT / "shapes")
Already exists
In [24]:
world.crs
Out[24]:
<Geographic 2D CRS: EPSG:4326>
Name: WGS 84
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: World.
- bounds: (-180.0, -90.0, 180.0, 90.0)
Datum: World Geodetic System 1984 ensemble
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich

Create a globe that covers USA and Europe, where most case studies are located

In [25]:
with warnings.catch_warnings():
    # catch extent warning, which will always be trigged with Orthographic/worldwide data
    warnings.simplefilter("ignore")
    ax = geoplot.polyplot(world, projection=gcrs.Orthographic(central_latitude=50, central_longitude=-35), figsize=(10, 5), edgecolor='black', linewidth=0.2)
ax.set_global()
ax.add_feature(cartopy.feature.LAND, edgecolor='gray', facecolor='lightblue', alpha=0.2)
ax.spines['geo'].set_visible(True)
# ax.outline_patch.set_visible(True)
No description has been provided for this image

Load locations for Case Studies

In [26]:
df = pd.read_csv(DATA_FOLDER / "list.csv")
In [27]:
df.head()
Out[27]:
longitude latitude casestudy name
0 -18.183484 63.768843 Case Study 1 NaN
1 6.754167 60.130833 Case Study 1 NaN
2 6.188726 58.986442 Case Study 1 NaN
3 12.075629 46.694710 Case Study 1 NaN
4 8.794212 46.242225 Case Study 1 NaN
In [28]:
df.columns
Out[28]:
Index(['longitude', 'latitude', 'casestudy', 'name'], dtype='object')
In [29]:
cs = gp.GeoDataFrame(
    df, geometry=gp.points_from_xy(df.longitude, df.latitude), crs=CRS_WGS)
In [30]:
cs.head()
Out[30]:
longitude latitude casestudy name geometry
0 -18.183484 63.768843 Case Study 1 NaN POINT (-18.18348 63.76884)
1 6.754167 60.130833 Case Study 1 NaN POINT (6.75417 60.13083)
2 6.188726 58.986442 Case Study 1 NaN POINT (6.18873 58.98644)
3 12.075629 46.694710 Case Study 1 NaN POINT (12.07563 46.69471)
4 8.794212 46.242225 Case Study 1 NaN POINT (8.79421 46.24222)
In [31]:
df_hotspots = gp.read_file(
    Path.cwd().parents[0] / "00_data" / "hotspots" / "hotspots2021.shp")
In [32]:
df_4 = df_hotspots.geometry.centroid.to_crs(CRS_WGS)
In [33]:
gdf_4 = gp.GeoDataFrame(df_4)
gdf_4.set_geometry(0, inplace=True)
gdf_4.rename_geometry("geometry", inplace=True)
In [34]:
gdf_4["latitude"] = gdf_4.geometry.y
gdf_4["longitude"] = gdf_4.geometry.x
gdf_4["casestudy"] = "Case Study 4"
In [35]:
cs = pd.concat([cs, gdf_4])
In [36]:
cs.tail()
Out[36]:
longitude latitude casestudy name geometry
25 8.803433 53.274441 Case Study 4 NaN POINT (8.80343 53.27444)
26 13.931602 53.936987 Case Study 4 NaN POINT (13.9316 53.93699)
27 12.769376 54.376000 Case Study 4 NaN POINT (12.76938 54.376)
28 9.967633 51.260864 Case Study 4 NaN POINT (9.96763 51.26086)
29 11.234471 53.943055 Case Study 4 NaN POINT (11.23447 53.94305)

Get alphashapes

In [37]:
cs_1_a = alphashape.alphashape(cs[cs["casestudy"]=="Case Study 1"], 0.)
cs_2_a = alphashape.alphashape(cs[cs["casestudy"]=="Case Study 2"], 0.)
cs_4_a = alphashape.alphashape(cs[cs["casestudy"]=="Case Study 4"], 0.)
In [38]:
cs_5_a = gp.read_file(
    OUTPUT/ 'Milvusmilvus_range.gpkg', layer='Milvus milvus')  

Plot world map

Styling

Chose any of the great color palettes from seaborn: https://seaborn.pydata.org/generated/seaborn.color_palette.html

In [39]:
colors=sns.color_palette("Spectral", as_cmap=True)
colors
Out[39]:
Spectral
Spectral colormap
under
bad
over
In [40]:
legend_kwds = {
    "bbox_to_anchor": (1.0, 1),
    "loc":'upper left',
    "fontsize":10, "frameon":False,
    "title":"Location of Case Studies", "title_fontsize":12,
    "alignment":"left"}
In [41]:
plt_kwds = {
    "projection":gcrs.Orthographic(central_latitude=50, central_longitude=-35),     # projection and center focus
}
In [42]:
def add_patch(legend):
    ax = legend.axes
    handles, labels = ax.get_legend_handles_labels()
    handles.append(Patch(facecolor='orange', edgecolor='r'))
    labels.append("Color Patch")

    legend._legend_box = None
    legend._init_legend_box(handles, labels)
    legend._set_loc(legend._loc)
    legend.set_title(legend.get_title().get_text())

Create plot

In [44]:
with warnings.catch_warnings():
    # catch extent warning, which will always be trigged with Orthographic/worldwide data
    warnings.simplefilter("ignore")
    ax = geoplot.polyplot(
        world, figsize=(10, 5), edgecolor='black',
        linewidth=0.2, **plt_kwds)
    pt_kwds = {
        "marker":'.',
        "s":5,
    }
    alpha_shapes_kwds = {
        "edgecolor":'None',
        "alpha":0.2
    }
    ax = geoplot.polyplot(
        cs_5_a, ax=ax, facecolor=colors(0.2), edgecolor='None', alpha=0.4,
        **plt_kwds)
    ax = geoplot.polyplot(
        cs_1_a, ax=ax, facecolor=colors(0.0), 
        **plt_kwds, **alpha_shapes_kwds)
    ax = geoplot.polyplot(
        cs_2_a, ax=ax, facecolor=colors(1.0), 
        **plt_kwds, **alpha_shapes_kwds)
    ax = geoplot.polyplot(
        cs_4_a, ax=ax, facecolor=colors(0.5), edgecolor='None', alpha=1.0,
        **plt_kwds)
    ax = geoplot.pointplot(
        cs[cs["casestudy"]=="Case Study 2"],
        ax=ax, color=colors(1.0), **pt_kwds, **plt_kwds)
    ax = geoplot.pointplot(
        cs[cs["casestudy"]=="Case Study 4"],
        ax=ax, color=colors(0.5), alpha=0.5, **pt_kwds, **plt_kwds)
    ax = geoplot.pointplot(
        cs[cs["casestudy"]=="Case Study 1"],
        ax=ax, color=colors(0.0), **pt_kwds, **plt_kwds)

# manually create legend
cs1_patch = plt.scatter([], [], label='Case Study 1', color=colors(0.0), s=12)
cs2_patch = plt.scatter([], [], label='Case Study 2', color=colors(1.0), s=12)
cs3_patch = Line2D([0], [0], label='Case Study 3', color=colors(0.8), linewidth=2)
cs4_patch = plt.scatter([], [], label='Case Study 4', color=colors(0.5), edgecolor="grey", linewidth=0.25, s=25)
cs5_patch = mpatches.Patch(color=colors(0.2), label='Case Study 5', alpha=0.4)
plt.legend(handles=[cs1_patch, cs2_patch, cs3_patch, cs4_patch, cs5_patch], **legend_kwds)
# Add l1 as a separate artist to the axes
ax.set_global()
ax.add_feature(
    cartopy.feature.LAND, edgecolor='gray', 
    facecolor='lightblue', alpha=0.2)
ax.gridlines(alpha=0.4)
ax.spines['geo'].set_visible(True)
ax.spines['geo'].set_edgecolor(colors(0.8))
ax.spines['geo'].set_linewidth(2)
No description has been provided for this image
In [45]:
fig = ax.get_figure()
tools.save_fig(fig, output=OUTPUT, name="overview")

Create notebook HTML

In [46]:
!jupyter nbconvert --to html_toc \
    --output-dir=../resources/html/ ./11_graphical_abstract.ipynb \
    --template=../nbconvert.tpl \
    --ExtractOutputPreprocessor.enabled=False >&- 2>&-
In [ ]:
 

IOER RDC Jupyter Base Template v0.10.0