From b23e18140a3971c2af62d22ecba13a93df7ce1e8 Mon Sep 17 00:00:00 2001 From: michaelchin Date: Thu, 8 Aug 2024 17:35:01 +1000 Subject: [PATCH 01/11] add a new folder plotting --- gplately/plotting/pygmt_plotter.py | 0 gplately/plotting/reconstructor.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 gplately/plotting/pygmt_plotter.py create mode 100644 gplately/plotting/reconstructor.py diff --git a/gplately/plotting/pygmt_plotter.py b/gplately/plotting/pygmt_plotter.py new file mode 100644 index 00000000..e69de29b diff --git a/gplately/plotting/reconstructor.py b/gplately/plotting/reconstructor.py new file mode 100644 index 00000000..e69de29b From 642be2d5e1867898b18012b9f11fe79781cf9052 Mon Sep 17 00:00:00 2001 From: michaelchin Date: Thu, 17 Oct 2024 19:29:42 +1100 Subject: [PATCH 02/11] initial effort to add pygmt plot --- docker/env.yaml | 2 + gplately/mapping/plot_engine.py | 23 ++++++ gplately/mapping/pygmt_plot.py | 81 +++++++++++++++++++ gplately/plot.py | 16 +++- pyproject.toml | 1 + setup.py | 1 + tests-dir/unittest/test_plot.py | 4 + tests-dir/unittest/test_pygmt_plot.py | 111 ++++++++++++++++++++++++++ 8 files changed, 235 insertions(+), 4 deletions(-) create mode 100644 gplately/mapping/plot_engine.py create mode 100644 gplately/mapping/pygmt_plot.py create mode 100644 tests-dir/unittest/test_pygmt_plot.py diff --git a/docker/env.yaml b/docker/env.yaml index 9157740c..3e9ab660 100644 --- a/docker/env.yaml +++ b/docker/env.yaml @@ -7,3 +7,5 @@ dependencies: - gplately - jupyter - moviepy + - gmt + - pygmt diff --git a/gplately/mapping/plot_engine.py b/gplately/mapping/plot_engine.py new file mode 100644 index 00000000..77af7ecc --- /dev/null +++ b/gplately/mapping/plot_engine.py @@ -0,0 +1,23 @@ +# +# Copyright (C) 2024 The University of Sydney, Australia +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License, version 2, as published by +# the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +from enum import Enum + + +class PlotEngine(Enum): + CARTOPY = 1 + PYGMT = 2 diff --git a/gplately/mapping/pygmt_plot.py b/gplately/mapping/pygmt_plot.py new file mode 100644 index 00000000..21614e6f --- /dev/null +++ b/gplately/mapping/pygmt_plot.py @@ -0,0 +1,81 @@ +# +# Copyright (C) 2024 The University of Sydney, Australia +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License, version 2, as published by +# the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +from geopandas.geodataframe import GeoDataFrame +import pygmt + +# ----- parameters for plot +region = "d" +width = 10 +projection = "N180/" +x_offset = width + 2 + +# plate boundary stuff +plateboundary_width = "0.5p" + +age_font = "12p,Helvetica,black" + +label_font = "12p,Helvetica,black" +label_offset = "j0/-0.5c" +label_position = "TC" + + +def plot_geo_data_frame(gdf: GeoDataFrame, **kwargs): + + print(gdf) + fig = pygmt.Figure() + pygmt.config( + FONT_ANNOT=8, + FONT_LABEL=8, + FONT=8, + MAP_TICK_PEN="0.75p", + MAP_FRAME_PEN="0.75p", + MAP_TICK_LENGTH_PRIMARY="4p", + ) + + # ---- part a - transforms FROM gplot.get_transforms() + fig.basemap(region=region, projection="%s%sc" % (projection, width), frame="lrtb") + # fig.coast(shorelines=True) + fig.plot(data=gdf.geometry, pen="0.5p,blue") + """ + fig.plot(data=gdf_coastlines, fill=coastline_color, frame=["xa0", "ya0"], transparency=0) + + fig.plot(data=gdf_topo_plates.geometry, pen='%s,%s' % (plateboundary_width, plate_colour), frame="lrtb") + fig.plot(data=gdf_subduction_left, pen='%s,%s' % (plateboundary_width, subduction_zone_colour), fill=subduction_zone_colour, style='f0.2/0.08+l+t') + fig.plot(data=gdf_subduction_right, pen='%s,%s' % (plateboundary_width, subduction_zone_colour), fill=subduction_zone_colour, style='f0.2/0.08+r+t') + fig.plot(data=gdf_ridges_transforms, pen='%s,%s' % (plateboundary_width, ridge_colour)) + fig.plot(data=gplot.get_transforms(), pen='%s,%s' % (plateboundary_width, transform_color)) + + fig.text(text='gplot.get_transforms(): %s Ma' % age, position=label_position, no_clip=True, font=label_font, offset=label_offset) + + fig.shift_origin(xshift=x_offset) + fig.basemap(region=region, projection="%s%sc" % (projection, width), frame="lrtb") + fig.plot(data=gdf_cobs, fill=COB_color, transparency=0, ) + fig.plot(data=gdf_coastlines, fill=coastline_color, frame=["xa0", "ya0"], transparency=0) + + fig.plot(data=gdf_topo_plates.geometry, pen='%s,%s' % (plateboundary_width, plate_colour), frame="lrtb", label='other plate boundary types') + fig.plot(data=gdf_subduction_left, pen='%s,%s' % (plateboundary_width, subduction_zone_colour), fill=subduction_zone_colour, style='f0.2/0.08+l+t', label='subduction zones') + fig.plot(data=gdf_subduction_right, pen='%s,%s' % (plateboundary_width, subduction_zone_colour), fill=subduction_zone_colour, style='f0.2/0.08+r+t') + fig.plot(data=gdf_ridges_transforms, pen='%s,%s' % (plateboundary_width, ridge_colour), label='ridges and transforms') + + # from gpml: transforms + fig.plot(data=gdf_topo_transforms, pen='%s,%s' % (plateboundary_width, transform_color), label = 'transforms') + fig.text(text='FeatureType.gpml_transform: %s Ma' % age, position=label_position, no_clip=True, font=label_font, offset=label_offset) + + fig.legend(position='jBL+o-2.7/0', box="+gwhite+p0.5p") + """ + # fig.show(width=1200) + fig.savefig("test-pygmt-plot.pdf") diff --git a/gplately/plot.py b/gplately/plot.py index b50e1b96..ebcbee16 100644 --- a/gplately/plot.py +++ b/gplately/plot.py @@ -51,6 +51,8 @@ from .utils.feature_utils import shapelify_features as _shapelify_features from .utils.plot_utils import _clean_polygons, _meridian_from_ax from .utils.plot_utils import plot_subduction_teeth as _plot_subduction_teeth +from .mapping.plot_engine import PlotEngine +from .mapping.pygmt_plot import plot_geo_data_frame logger = logging.getLogger("gplately") @@ -298,6 +300,7 @@ def __init__( COBs=None, time=None, anchor_plate_id=0, + plot_engine: PlotEngine = PlotEngine.CARTOPY, ): self.plate_reconstruction = plate_reconstruction @@ -321,6 +324,7 @@ def __init__( self._topologies = None self._anchor_plate_id = self._check_anchor_plate_id(anchor_plate_id) + self._plot_engine = plot_engine # store topologies for easy access # setting time runs the update_time routine @@ -726,12 +730,16 @@ def _plot_feature(self, ax, get_feature_func, **kwargs): logger.warning("No feature found for plotting. Do nothing and return.") return ax - if hasattr(ax, "projection"): - gdf = _clean_polygons(data=gdf, projection=ax.projection) + if self._plot_engine == PlotEngine.PYGMT: + kwargs["ax"] = ax + return plot_geo_data_frame(gdf, **kwargs) else: - kwargs["transform"] = self.base_projection + if hasattr(ax, "projection"): + gdf = _clean_polygons(data=gdf, projection=ax.projection) + else: + kwargs["transform"] = self.base_projection - return gdf.plot(ax=ax, **kwargs) + return gdf.plot(ax=ax, **kwargs) @validate_reconstruction_time @append_docstring(GET_DATE_DOCSTRING.format("coastlines")) diff --git a/pyproject.toml b/pyproject.toml index 3cd2956c..c9319487 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ dependencies = [ "netcdf4", "rasterio", "geopandas", + "gmt", "stripy", "plate-model-manager>=1.2.0", "pyyaml", diff --git a/setup.py b/setup.py index cbf50e70..2eab0371 100644 --- a/setup.py +++ b/setup.py @@ -96,6 +96,7 @@ def _minimal_ext_cmd(cmd): "netcdf4", "rasterio", "geopandas", + "gmt", "stripy", "plate-model-manager", "pyyaml", diff --git a/tests-dir/unittest/test_plot.py b/tests-dir/unittest/test_plot.py index 4132b5aa..3530a284 100755 --- a/tests-dir/unittest/test_plot.py +++ b/tests-dir/unittest/test_plot.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +# import matplotlib + +# matplotlib.use("QtAgg") import sys @@ -11,6 +14,7 @@ import gplately from gplately import PlateReconstruction, PlotTopologies + print(gplately.__file__) # test the plot function with the new PlateModel class diff --git a/tests-dir/unittest/test_pygmt_plot.py b/tests-dir/unittest/test_pygmt_plot.py new file mode 100644 index 00000000..13aeea62 --- /dev/null +++ b/tests-dir/unittest/test_pygmt_plot.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +import sys + +import cartopy.crs as ccrs +import matplotlib.pyplot as plt +import numpy as np +from common import MODEL_REPO_DIR, save_fig +from plate_model_manager import PlateModel, PlateModelManager + +import gplately +from gplately import PlateReconstruction, PlotTopologies +from gplately.mapping.plot_engine import PlotEngine + +print(gplately.__file__) + +# test the plot function with the new PlateModel class + +# MODEL_NAME = "Clennett2020" +# MODEL_NAME = "Muller2019" +MODEL_NAME = "merdith2021" + + +def main(show=True): + try: + model = PlateModelManager().get_model(MODEL_NAME, data_dir=MODEL_REPO_DIR) + except: + model = PlateModel(MODEL_NAME, data_dir=MODEL_REPO_DIR, readonly=True) + + age = 55 + + test_model = PlateReconstruction( + model.get_rotation_model(), + topology_features=model.get_layer("Topologies"), + static_polygons=model.get_layer("StaticPolygons"), + ) + gplot = PlotTopologies( + test_model, + coastlines=model.get_layer("Coastlines"), + COBs=model.get_layer("COBs", return_none_if_not_exist=True), + continents=model.get_layer("ContinentalPolygons"), + time=age, + plot_engine=PlotEngine.PYGMT, + ) + + # age = 100 + # gplot.time = age + + ax = None + + all_flag = 0 + plot_flag = { + "continent_ocean_boundaries": 0, + "coastlines": 0, + "trenches": 0, + "subduction_teeth": 0, + "ridges": 0, + "all_topologies": 0, + "all_topological_sections": 0, + "plate_polygon_by_id": 0, + "unclassified_features": 0, + "slab_edges": 0, + "passive_continental_boundaries": 0, + "extended_continental_crusts": 0, + "continental_crusts": 0, + "sutures": 0, + "orogenic_belts": 0, + "transitional_crusts": 0, + "terrane_boundaries": 0, + "inferred_paleo_boundaries": 0, + "fracture_zones": 0, + "faults": 0, + "continental_rifts": 0, + "misc_boundaries": 0, + "transforms": 1, + "continents": 0, + "topological_plate_boundaries": 0, + } + + for key in plot_flag: + if key == "plate_polygon_by_id": + continue + if key == "continents": + if plot_flag["continents"]: + gplot.plot_continents(ax, color="grey", facecolor="0.8") + continue + if key == "coastlines": + if plot_flag["coastlines"]: + gplot.plot_coastlines(ax, edgecolor="blue", facecolor="0.5") + continue + if all_flag or plot_flag[key]: + getattr(gplot, f"plot_{key}")( + ax, color=list(np.random.choice(range(256), size=3) / 256) + ) + + ids = set([f.get_reconstruction_plate_id() for f in gplot.topologies]) + for id in ids: + if all_flag or plot_flag["plate_polygon_by_id"]: + gplot.plot_plate_polygon_by_id( + ax, + id, + facecolor="None", + edgecolor=list(np.random.choice(range(256), size=3) / 256), + ) + + +if __name__ == "__main__": + if len(sys.argv) == 2 and sys.argv[1] == "save": + main(show=False) + else: + main(show=True) From a2a15aae2ddf3e9e028784b5a8671d51e0c8b954 Mon Sep 17 00:00:00 2001 From: michaelchin Date: Fri, 18 Oct 2024 19:16:16 +1100 Subject: [PATCH 03/11] add a new notebook to test pygmt --- gplately/mapping/pygmt_plot.py | 19 +---- gplately/plot.py | 3 +- tests-dir/unittest/test_pygmt.ipynb | 101 ++++++++++++++++++++++++++ tests-dir/unittest/test_pygmt_plot.py | 22 +++--- 4 files changed, 116 insertions(+), 29 deletions(-) create mode 100644 tests-dir/unittest/test_pygmt.ipynb diff --git a/gplately/mapping/pygmt_plot.py b/gplately/mapping/pygmt_plot.py index 21614e6f..821d7b9b 100644 --- a/gplately/mapping/pygmt_plot.py +++ b/gplately/mapping/pygmt_plot.py @@ -33,22 +33,7 @@ label_position = "TC" -def plot_geo_data_frame(gdf: GeoDataFrame, **kwargs): - - print(gdf) - fig = pygmt.Figure() - pygmt.config( - FONT_ANNOT=8, - FONT_LABEL=8, - FONT=8, - MAP_TICK_PEN="0.75p", - MAP_FRAME_PEN="0.75p", - MAP_TICK_LENGTH_PRIMARY="4p", - ) - - # ---- part a - transforms FROM gplot.get_transforms() - fig.basemap(region=region, projection="%s%sc" % (projection, width), frame="lrtb") - # fig.coast(shorelines=True) +def plot_geo_data_frame(fig: pygmt.Figure, gdf: GeoDataFrame, **kwargs): fig.plot(data=gdf.geometry, pen="0.5p,blue") """ fig.plot(data=gdf_coastlines, fill=coastline_color, frame=["xa0", "ya0"], transparency=0) @@ -77,5 +62,3 @@ def plot_geo_data_frame(gdf: GeoDataFrame, **kwargs): fig.legend(position='jBL+o-2.7/0', box="+gwhite+p0.5p") """ - # fig.show(width=1200) - fig.savefig("test-pygmt-plot.pdf") diff --git a/gplately/plot.py b/gplately/plot.py index ebcbee16..1a0621e4 100644 --- a/gplately/plot.py +++ b/gplately/plot.py @@ -731,8 +731,7 @@ def _plot_feature(self, ax, get_feature_func, **kwargs): return ax if self._plot_engine == PlotEngine.PYGMT: - kwargs["ax"] = ax - return plot_geo_data_frame(gdf, **kwargs) + return plot_geo_data_frame(fig=ax, gdf=gdf, **kwargs) else: if hasattr(ax, "projection"): gdf = _clean_polygons(data=gdf, projection=ax.projection) diff --git a/tests-dir/unittest/test_pygmt.ipynb b/tests-dir/unittest/test_pygmt.ipynb new file mode 100644 index 00000000..78664937 --- /dev/null +++ b/tests-dir/unittest/test_pygmt.ipynb @@ -0,0 +1,101 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "f5003633-363f-4d07-b857-879f9ba8726e", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "\n", + "import cartopy.crs as ccrs\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from common import MODEL_REPO_DIR, save_fig\n", + "from plate_model_manager import PlateModel, PlateModelManager\n", + "\n", + "import gplately\n", + "from gplately import PlateReconstruction, PlotTopologies\n", + "from gplately.mapping.plot_engine import PlotEngine\n", + "import pygmt\n", + "pygmt.config(\n", + " FONT_ANNOT=8,\n", + " FONT_LABEL=8,\n", + " FONT=8,\n", + " MAP_TICK_PEN=\"0.75p\",\n", + " MAP_FRAME_PEN=\"0.75p\",\n", + " MAP_TICK_LENGTH_PRIMARY=\"4p\",\n", + " )\n", + "\n", + "# MODEL_NAME = \"Clennett2020\"\n", + "# MODEL_NAME = \"Muller2019\"\n", + "MODEL_NAME = \"merdith2021\"\n", + "\n", + "try:\n", + " model = PlateModelManager().get_model(MODEL_NAME, data_dir=MODEL_REPO_DIR)\n", + "except:\n", + " model = PlateModel(MODEL_NAME, data_dir=MODEL_REPO_DIR, readonly=True)\n", + "\n", + "if model is None:\n", + " raise Exception(f\"Unable to get model ({MODEL_NAME})\")\n", + "\n", + "age = 55\n", + "\n", + "test_model = PlateReconstruction(\n", + " model.get_rotation_model(),\n", + " topology_features=model.get_layer(\"Topologies\"),\n", + " static_polygons=model.get_layer(\"StaticPolygons\"),\n", + ")\n", + "gplot = PlotTopologies(\n", + " test_model,\n", + " coastlines=model.get_layer(\"Coastlines\"),\n", + " COBs=model.get_layer(\"COBs\", return_none_if_not_exist=True),\n", + " continents=model.get_layer(\"ContinentalPolygons\"),\n", + " time=age,\n", + " plot_engine=PlotEngine.PYGMT,\n", + ")\n", + "\n", + "fig = pygmt.Figure()\n", + "fig.basemap(region=\"d\", projection=\"N180/10c\", frame=\"lrtb\")\n", + "#fig.coast(shorelines=True)\n", + "\n", + "gplot.plot_topological_plate_boundaries(fig)\n", + "gplot.plot_coastlines(fig)\n", + "\n", + "fig.show(width=1200)\n", + "# fig.savefig(\"test-pygmt-plot.pdf\")\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b25b75a3-39f1-4494-912e-7f9f502a67ce", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests-dir/unittest/test_pygmt_plot.py b/tests-dir/unittest/test_pygmt_plot.py index 13aeea62..19448ab6 100644 --- a/tests-dir/unittest/test_pygmt_plot.py +++ b/tests-dir/unittest/test_pygmt_plot.py @@ -27,6 +27,9 @@ def main(show=True): except: model = PlateModel(MODEL_NAME, data_dir=MODEL_REPO_DIR, readonly=True) + if model is None: + raise Exception(f"Unable to get model ({MODEL_NAME})") + age = 55 test_model = PlateReconstruction( @@ -93,15 +96,16 @@ def main(show=True): ax, color=list(np.random.choice(range(256), size=3) / 256) ) - ids = set([f.get_reconstruction_plate_id() for f in gplot.topologies]) - for id in ids: - if all_flag or plot_flag["plate_polygon_by_id"]: - gplot.plot_plate_polygon_by_id( - ax, - id, - facecolor="None", - edgecolor=list(np.random.choice(range(256), size=3) / 256), - ) + if gplot.topologies is not None: + ids = set([f.get_reconstruction_plate_id() for f in gplot.topologies]) + for id in ids: + if all_flag or plot_flag["plate_polygon_by_id"]: + gplot.plot_plate_polygon_by_id( + ax, + id, + facecolor="None", + edgecolor=list(np.random.choice(range(256), size=3) / 256), + ) if __name__ == "__main__": From e523c5a0608d206c0639ddc826b4e3912eaee54a Mon Sep 17 00:00:00 2001 From: michaelchin Date: Fri, 18 Oct 2024 19:34:06 +1100 Subject: [PATCH 04/11] add a new function get_gplot() --- gplately/utils/plot_utils.py | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/gplately/utils/plot_utils.py b/gplately/utils/plot_utils.py index 80930128..5c3e1ea3 100644 --- a/gplately/utils/plot_utils.py +++ b/gplately/utils/plot_utils.py @@ -25,8 +25,13 @@ from shapely.geometry import LineString, MultiPolygon, Point, Polygon, box from shapely.geometry.base import BaseGeometry, BaseMultipartGeometry from shapely.ops import linemerge, substring +from plate_model_manager import PlateModel, PlateModelManager +from typing import Union from .io_utils import get_geometries as _get_geometries +from ..reconstruction import PlateReconstruction +from ..plot import PlotTopologies +from ..mapping.plot_engine import PlotEngine logger = logging.getLogger("gplately") @@ -632,3 +637,48 @@ def plot_subduction_teeth( else: for triangle in triangles: ax.fill(*triangle.exterior.xy, **kwargs) + + +def get_gplot( + model_name: str, model_repo_dir: str, age: Union[int, float] +) -> PlotTopologies: + try: + model = PlateModelManager().get_model(model_name, data_dir=model_repo_dir) + except: + model = PlateModel(model_name, data_dir=model_repo_dir, readonly=True) + + if model is None: + raise Exception(f"Unable to get model ({model_name})") + + topology_features = None + static_polygons = None + coastlines = None + COBs = None + continents = None + + all_layers = model.get_avail_layers() + + if "Topologies" in all_layers: + topology_features = model.get_layer("Topologies") + if "StaticPolygons" in all_layers: + static_polygons = model.get_layer("StaticPolygons") + if "Coastlines" in all_layers: + coastlines = model.get_layer("Coastlines") + if "COBs" in all_layers: + COBs = model.get_layer("COBs") + if "ContinentalPolygons" in all_layers: + continents = (model.get_layer("ContinentalPolygons"),) + + m = PlateReconstruction( + model.get_rotation_model(), + topology_features=topology_features, + static_polygons=static_polygons, + ) + return PlotTopologies( + m, + coastlines=coastlines, + COBs=COBs, + continents=continents, + time=age, + plot_engine=PlotEngine.PYGMT, + ) From 006773c349af4af89f7c5219947e5543ca6e6402 Mon Sep 17 00:00:00 2001 From: michaelchin Date: Fri, 18 Oct 2024 19:41:47 +1100 Subject: [PATCH 05/11] some unfinished code --- gplately/__init__.py | 2 ++ gplately/utils/plot_utils.py | 1 + tests-dir/unittest/test_pygmt.ipynb | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gplately/__init__.py b/gplately/__init__.py index 9b5b399a..99ddabda 100644 --- a/gplately/__init__.py +++ b/gplately/__init__.py @@ -248,6 +248,7 @@ from .tools import EARTH_RADIUS from .utils import io_utils from .utils.io_utils import get_geometries, get_valid_geometries +from .utils.plot_utils import get_gplot __pdoc__ = { "data": False, @@ -267,6 +268,7 @@ "data", "download", "geometry", + "get_gplot", "gpml", "grids", "oceans", diff --git a/gplately/utils/plot_utils.py b/gplately/utils/plot_utils.py index 5c3e1ea3..1619708d 100644 --- a/gplately/utils/plot_utils.py +++ b/gplately/utils/plot_utils.py @@ -642,6 +642,7 @@ def plot_subduction_teeth( def get_gplot( model_name: str, model_repo_dir: str, age: Union[int, float] ) -> PlotTopologies: + """convenient function to get gplot object""" try: model = PlateModelManager().get_model(model_name, data_dir=model_repo_dir) except: diff --git a/tests-dir/unittest/test_pygmt.ipynb b/tests-dir/unittest/test_pygmt.ipynb index 78664937..6e565252 100644 --- a/tests-dir/unittest/test_pygmt.ipynb +++ b/tests-dir/unittest/test_pygmt.ipynb @@ -15,9 +15,9 @@ "from common import MODEL_REPO_DIR, save_fig\n", "from plate_model_manager import PlateModel, PlateModelManager\n", "\n", - "import gplately\n", "from gplately import PlateReconstruction, PlotTopologies\n", "from gplately.mapping.plot_engine import PlotEngine\n", + "from gplately import get_gplot\n", "import pygmt\n", "pygmt.config(\n", " FONT_ANNOT=8,\n", @@ -32,6 +32,7 @@ "# MODEL_NAME = \"Muller2019\"\n", "MODEL_NAME = \"merdith2021\"\n", "\n", + "\"\"\"\n", "try:\n", " model = PlateModelManager().get_model(MODEL_NAME, data_dir=MODEL_REPO_DIR)\n", "except:\n", @@ -55,7 +56,8 @@ " time=age,\n", " plot_engine=PlotEngine.PYGMT,\n", ")\n", - "\n", + "\"\"\"\n", + "gplot = get_gplot(MODEL_NAME,MODEL_REPO_DIR,55)\n", "fig = pygmt.Figure()\n", "fig.basemap(region=\"d\", projection=\"N180/10c\", frame=\"lrtb\")\n", "#fig.coast(shorelines=True)\n", From 0bbcd213880d2d1e5152b35ce34ecaf9cdce3cd8 Mon Sep 17 00:00:00 2001 From: michaelchin Date: Sat, 19 Oct 2024 15:06:53 +1100 Subject: [PATCH 06/11] finish the unfinished code yesterday --- gplately/__init__.py | 2 -- gplately/auxiliary.py | 56 +++++++++++++++++++++++++++++ gplately/plot.py | 6 ++-- gplately/utils/plot_utils.py | 51 -------------------------- pyproject.toml | 1 - tests-dir/unittest/test_pygmt.ipynb | 39 ++------------------ 6 files changed, 62 insertions(+), 93 deletions(-) create mode 100644 gplately/auxiliary.py diff --git a/gplately/__init__.py b/gplately/__init__.py index 99ddabda..9b5b399a 100644 --- a/gplately/__init__.py +++ b/gplately/__init__.py @@ -248,7 +248,6 @@ from .tools import EARTH_RADIUS from .utils import io_utils from .utils.io_utils import get_geometries, get_valid_geometries -from .utils.plot_utils import get_gplot __pdoc__ = { "data": False, @@ -268,7 +267,6 @@ "data", "download", "geometry", - "get_gplot", "gpml", "grids", "oceans", diff --git a/gplately/auxiliary.py b/gplately/auxiliary.py new file mode 100644 index 00000000..27c89983 --- /dev/null +++ b/gplately/auxiliary.py @@ -0,0 +1,56 @@ +from typing import Union + +from plate_model_manager import PlateModel, PlateModelManager + +from .mapping.plot_engine import PlotEngine +from .plot import PlotTopologies +from .reconstruction import PlateReconstruction + + +def get_gplot( + model_name: str, + model_repo_dir: str, + age: Union[int, float], + plot_engine: PlotEngine = PlotEngine.CARTOPY, +) -> PlotTopologies: + """auxiliary function to get gplot object""" + try: + model = PlateModelManager().get_model(model_name, data_dir=model_repo_dir) + except: + model = PlateModel(model_name, data_dir=model_repo_dir, readonly=True) + + if model is None: + raise Exception(f"Unable to get model ({model_name})") + + topology_features = None + static_polygons = None + coastlines = None + COBs = None + continents = None + + all_layers = model.get_avail_layers() + + if "Topologies" in all_layers: + topology_features = model.get_layer("Topologies") + if "StaticPolygons" in all_layers: + static_polygons = model.get_layer("StaticPolygons") + if "Coastlines" in all_layers: + coastlines = model.get_layer("Coastlines") + if "COBs" in all_layers: + COBs = model.get_layer("COBs") + if "ContinentalPolygons" in all_layers: + continents = model.get_layer("ContinentalPolygons") + + m = PlateReconstruction( + model.get_rotation_model(), + topology_features=topology_features, + static_polygons=static_polygons, + ) + return PlotTopologies( + m, + coastlines=coastlines, + COBs=COBs, + continents=continents, + time=age, + plot_engine=plot_engine, + ) diff --git a/gplately/plot.py b/gplately/plot.py index 1a0621e4..37992832 100644 --- a/gplately/plot.py +++ b/gplately/plot.py @@ -45,14 +45,14 @@ validate_topology_availability, ) from .gpml import _load_FeatureCollection +from .mapping.plot_engine import PlotEngine +from .mapping.pygmt_plot import plot_geo_data_frame from .pygplates import FeatureCollection as _FeatureCollection from .reconstruction import PlateReconstruction as _PlateReconstruction from .tools import EARTH_RADIUS from .utils.feature_utils import shapelify_features as _shapelify_features from .utils.plot_utils import _clean_polygons, _meridian_from_ax from .utils.plot_utils import plot_subduction_teeth as _plot_subduction_teeth -from .mapping.plot_engine import PlotEngine -from .mapping.pygmt_plot import plot_geo_data_frame logger = logging.getLogger("gplately") @@ -306,7 +306,7 @@ def __init__( if self.plate_reconstruction.topology_features is None: self.plate_reconstruction.topology_features = [] - logger.warn("Plate model does not have topology features.") + logger.warning("Plate model does not have topology features.") self.base_projection = ccrs.PlateCarree() diff --git a/gplately/utils/plot_utils.py b/gplately/utils/plot_utils.py index 1619708d..80930128 100644 --- a/gplately/utils/plot_utils.py +++ b/gplately/utils/plot_utils.py @@ -25,13 +25,8 @@ from shapely.geometry import LineString, MultiPolygon, Point, Polygon, box from shapely.geometry.base import BaseGeometry, BaseMultipartGeometry from shapely.ops import linemerge, substring -from plate_model_manager import PlateModel, PlateModelManager -from typing import Union from .io_utils import get_geometries as _get_geometries -from ..reconstruction import PlateReconstruction -from ..plot import PlotTopologies -from ..mapping.plot_engine import PlotEngine logger = logging.getLogger("gplately") @@ -637,49 +632,3 @@ def plot_subduction_teeth( else: for triangle in triangles: ax.fill(*triangle.exterior.xy, **kwargs) - - -def get_gplot( - model_name: str, model_repo_dir: str, age: Union[int, float] -) -> PlotTopologies: - """convenient function to get gplot object""" - try: - model = PlateModelManager().get_model(model_name, data_dir=model_repo_dir) - except: - model = PlateModel(model_name, data_dir=model_repo_dir, readonly=True) - - if model is None: - raise Exception(f"Unable to get model ({model_name})") - - topology_features = None - static_polygons = None - coastlines = None - COBs = None - continents = None - - all_layers = model.get_avail_layers() - - if "Topologies" in all_layers: - topology_features = model.get_layer("Topologies") - if "StaticPolygons" in all_layers: - static_polygons = model.get_layer("StaticPolygons") - if "Coastlines" in all_layers: - coastlines = model.get_layer("Coastlines") - if "COBs" in all_layers: - COBs = model.get_layer("COBs") - if "ContinentalPolygons" in all_layers: - continents = (model.get_layer("ContinentalPolygons"),) - - m = PlateReconstruction( - model.get_rotation_model(), - topology_features=topology_features, - static_polygons=static_polygons, - ) - return PlotTopologies( - m, - coastlines=coastlines, - COBs=COBs, - continents=continents, - time=age, - plot_engine=PlotEngine.PYGMT, - ) diff --git a/pyproject.toml b/pyproject.toml index 5f233c3e..7ca1623b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,6 @@ dependencies = [ "netcdf4", "rasterio", "geopandas", - "gmt", "stripy", "plate-model-manager>=1.2.1", "pyyaml", diff --git a/tests-dir/unittest/test_pygmt.ipynb b/tests-dir/unittest/test_pygmt.ipynb index 6e565252..6f9be13a 100644 --- a/tests-dir/unittest/test_pygmt.ipynb +++ b/tests-dir/unittest/test_pygmt.ipynb @@ -9,15 +9,11 @@ "source": [ "import sys\n", "\n", - "import cartopy.crs as ccrs\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "from common import MODEL_REPO_DIR, save_fig\n", "from plate_model_manager import PlateModel, PlateModelManager\n", "\n", "from gplately import PlateReconstruction, PlotTopologies\n", "from gplately.mapping.plot_engine import PlotEngine\n", - "from gplately import get_gplot\n", + "from gplately.auxiliary import get_gplot\n", "import pygmt\n", "pygmt.config(\n", " FONT_ANNOT=8,\n", @@ -28,36 +24,7 @@ " MAP_TICK_LENGTH_PRIMARY=\"4p\",\n", " )\n", "\n", - "# MODEL_NAME = \"Clennett2020\"\n", - "# MODEL_NAME = \"Muller2019\"\n", - "MODEL_NAME = \"merdith2021\"\n", - "\n", - "\"\"\"\n", - "try:\n", - " model = PlateModelManager().get_model(MODEL_NAME, data_dir=MODEL_REPO_DIR)\n", - "except:\n", - " model = PlateModel(MODEL_NAME, data_dir=MODEL_REPO_DIR, readonly=True)\n", - "\n", - "if model is None:\n", - " raise Exception(f\"Unable to get model ({MODEL_NAME})\")\n", - "\n", - "age = 55\n", - "\n", - "test_model = PlateReconstruction(\n", - " model.get_rotation_model(),\n", - " topology_features=model.get_layer(\"Topologies\"),\n", - " static_polygons=model.get_layer(\"StaticPolygons\"),\n", - ")\n", - "gplot = PlotTopologies(\n", - " test_model,\n", - " coastlines=model.get_layer(\"Coastlines\"),\n", - " COBs=model.get_layer(\"COBs\", return_none_if_not_exist=True),\n", - " continents=model.get_layer(\"ContinentalPolygons\"),\n", - " time=age,\n", - " plot_engine=PlotEngine.PYGMT,\n", - ")\n", - "\"\"\"\n", - "gplot = get_gplot(MODEL_NAME,MODEL_REPO_DIR,55)\n", + "gplot = get_gplot(\"merdith2021\", \"plate-model-repo\", age=55, plot_engine=PlotEngine.PYGMT)\n", "fig = pygmt.Figure()\n", "fig.basemap(region=\"d\", projection=\"N180/10c\", frame=\"lrtb\")\n", "#fig.coast(shorelines=True)\n", @@ -95,7 +62,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.11.6" } }, "nbformat": 4, From 8a6134484d01455098474b8de0d5d81fb018e313 Mon Sep 17 00:00:00 2001 From: michaelchin Date: Sat, 19 Oct 2024 15:11:22 +1100 Subject: [PATCH 07/11] remove old placeholder files --- gplately/plotting/pygmt_plotter.py | 0 gplately/plotting/reconstructor.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 gplately/plotting/pygmt_plotter.py delete mode 100644 gplately/plotting/reconstructor.py diff --git a/gplately/plotting/pygmt_plotter.py b/gplately/plotting/pygmt_plotter.py deleted file mode 100644 index e69de29b..00000000 diff --git a/gplately/plotting/reconstructor.py b/gplately/plotting/reconstructor.py deleted file mode 100644 index e69de29b..00000000 From 5aea1542e66daaa5bc6de25a544244c8f878f982 Mon Sep 17 00:00:00 2001 From: michaelchin Date: Sat, 19 Oct 2024 15:12:57 +1100 Subject: [PATCH 08/11] rollback change in setup.py --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 05e81f84..b3e18d42 100644 --- a/setup.py +++ b/setup.py @@ -96,7 +96,6 @@ def _minimal_ext_cmd(cmd): "netcdf4", "rasterio", "geopandas", - "gmt", "stripy", "plate-model-manager>=1.2.1", "pyyaml", From 8753b71bb1d6dffb622b010a9ca70afc96dec2bc Mon Sep 17 00:00:00 2001 From: michaelchin Date: Thu, 16 Jan 2025 13:08:23 +1100 Subject: [PATCH 09/11] add parameters for pygmt plot --- gplately/mapping/pygmt_plot.py | 53 ++++++++++++++++++++++++++++- gplately/plot.py | 5 +++ tests-dir/unittest/test_pygmt.ipynb | 32 +++-------------- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/gplately/mapping/pygmt_plot.py b/gplately/mapping/pygmt_plot.py index 821d7b9b..c6cb7628 100644 --- a/gplately/mapping/pygmt_plot.py +++ b/gplately/mapping/pygmt_plot.py @@ -17,6 +17,16 @@ from geopandas.geodataframe import GeoDataFrame import pygmt +pygmt.config( + FONT_ANNOT=8, + FONT_LABEL=8, + FONT=8, + MAP_TICK_PEN="0.75p", + MAP_FRAME_PEN="0.75p", + MAP_TICK_LENGTH_PRIMARY="4p", +) + + # ----- parameters for plot region = "d" width = 10 @@ -33,8 +43,49 @@ label_position = "TC" +def get_pygmt_basemap_figure(projection="N180/10c", region="d"): + fig = pygmt.Figure() + fig.basemap(region=region, projection=projection, frame="lrtb") + return fig + + def plot_geo_data_frame(fig: pygmt.Figure, gdf: GeoDataFrame, **kwargs): - fig.plot(data=gdf.geometry, pen="0.5p,blue") + line_width = "0.1p" + line_color = "blue" + + if "edgecolor" in kwargs.keys(): + if isinstance(kwargs["edgecolor"], str): + line_color = kwargs["edgecolor"] + else: + raise Exception( + "The edgecolor parameter is not string. Currently, the pygmt plot engine only supports colour name." + ) + + if "linewidth" in kwargs.keys(): + line_width = f"{kwargs['linewidth']}p" + + fill = None + if "facecolor" in kwargs.keys() and kwargs["facecolor"].lower() != "none": + fill = f"{kwargs['facecolor']}" + + if line_color.lower() == "none": + line_width = "0" + line_color = fill + + if "fill" in kwargs.keys(): + fill = kwargs["fill"] + + if "pen" in kwargs.keys(): + pen = kwargs["pen"] + else: + pen = f"{line_width},{line_color}" + + style = None + if "style" in kwargs.keys(): + style = kwargs["style"] + + fig.plot(data=gdf.geometry, pen=pen, fill=fill, style=style) + """ fig.plot(data=gdf_coastlines, fill=coastline_color, frame=["xa0", "ya0"], transparency=0) diff --git a/gplately/plot.py b/gplately/plot.py index 37992832..5d079e2c 100644 --- a/gplately/plot.py +++ b/gplately/plot.py @@ -726,6 +726,11 @@ def _plot_feature(self, ax, get_feature_func, **kwargs): tessellate_degrees=tessellate_degrees, ) + if not isinstance(gdf, gpd.GeoDataFrame): + raise Exception( + f"Expecting a GeoDataFrame object, but the gdf is {type(gdf)}" + ) + if len(gdf) == 0: logger.warning("No feature found for plotting. Do nothing and return.") return ax diff --git a/tests-dir/unittest/test_pygmt.ipynb b/tests-dir/unittest/test_pygmt.ipynb index 6f9be13a..474f39cd 100644 --- a/tests-dir/unittest/test_pygmt.ipynb +++ b/tests-dir/unittest/test_pygmt.ipynb @@ -7,43 +7,21 @@ "metadata": {}, "outputs": [], "source": [ - "import sys\n", - "\n", - "from plate_model_manager import PlateModel, PlateModelManager\n", - "\n", - "from gplately import PlateReconstruction, PlotTopologies\n", "from gplately.mapping.plot_engine import PlotEngine\n", + "from gplately.mapping.pygmt_plot import get_pygmt_basemap_figure\n", "from gplately.auxiliary import get_gplot\n", - "import pygmt\n", - "pygmt.config(\n", - " FONT_ANNOT=8,\n", - " FONT_LABEL=8,\n", - " FONT=8,\n", - " MAP_TICK_PEN=\"0.75p\",\n", - " MAP_FRAME_PEN=\"0.75p\",\n", - " MAP_TICK_LENGTH_PRIMARY=\"4p\",\n", - " )\n", "\n", "gplot = get_gplot(\"merdith2021\", \"plate-model-repo\", age=55, plot_engine=PlotEngine.PYGMT)\n", - "fig = pygmt.Figure()\n", - "fig.basemap(region=\"d\", projection=\"N180/10c\", frame=\"lrtb\")\n", + "fig = get_pygmt_basemap_figure(projection=\"N180/10c\", region=\"d\")\n", "#fig.coast(shorelines=True)\n", "\n", - "gplot.plot_topological_plate_boundaries(fig)\n", - "gplot.plot_coastlines(fig)\n", + "gplot.plot_topological_plate_boundaries(fig, edgecolor=\"blue\", linewidth=1.0, central_meridian=180, style='f0.2/0.08+l+t')\n", + "gplot.plot_coastlines(fig, edgecolor=\"none\", facecolor='gray', linewidth=0.1, central_meridian=180)\n", "\n", "fig.show(width=1200)\n", "# fig.savefig(\"test-pygmt-plot.pdf\")\n", "\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b25b75a3-39f1-4494-912e-7f9f502a67ce", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -62,7 +40,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.11.9" } }, "nbformat": 4, From cc8694cc505a919150913fcd6587b8c02124622d Mon Sep 17 00:00:00 2001 From: michaelchin Date: Fri, 17 Jan 2025 13:40:40 +1100 Subject: [PATCH 10/11] plot subduction with pygmt --- gplately/auxiliary.py | 4 ++-- gplately/mapping/plot_engine.py | 2 +- gplately/mapping/pygmt_plot.py | 29 +++++++++++++++++++++++---- gplately/plot.py | 22 ++++++++++++++------ tests-dir/unittest/test_pygmt.ipynb | 11 +++++++--- tests-dir/unittest/test_pygmt_plot.py | 4 ++-- 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/gplately/auxiliary.py b/gplately/auxiliary.py index 27c89983..43cccdc8 100644 --- a/gplately/auxiliary.py +++ b/gplately/auxiliary.py @@ -2,7 +2,7 @@ from plate_model_manager import PlateModel, PlateModelManager -from .mapping.plot_engine import PlotEngine +from .mapping.plot_engine import PlotEngineType from .plot import PlotTopologies from .reconstruction import PlateReconstruction @@ -11,7 +11,7 @@ def get_gplot( model_name: str, model_repo_dir: str, age: Union[int, float], - plot_engine: PlotEngine = PlotEngine.CARTOPY, + plot_engine: PlotEngineType = PlotEngineType.CARTOPY, ) -> PlotTopologies: """auxiliary function to get gplot object""" try: diff --git a/gplately/mapping/plot_engine.py b/gplately/mapping/plot_engine.py index 77af7ecc..d0949397 100644 --- a/gplately/mapping/plot_engine.py +++ b/gplately/mapping/plot_engine.py @@ -18,6 +18,6 @@ from enum import Enum -class PlotEngine(Enum): +class PlotEngineType(Enum): CARTOPY = 1 PYGMT = 2 diff --git a/gplately/mapping/pygmt_plot.py b/gplately/mapping/pygmt_plot.py index c6cb7628..e48d1ee1 100644 --- a/gplately/mapping/pygmt_plot.py +++ b/gplately/mapping/pygmt_plot.py @@ -26,7 +26,6 @@ MAP_TICK_LENGTH_PRIMARY="4p", ) - # ----- parameters for plot region = "d" width = 10 @@ -35,9 +34,7 @@ # plate boundary stuff plateboundary_width = "0.5p" - age_font = "12p,Helvetica,black" - label_font = "12p,Helvetica,black" label_offset = "j0/-0.5c" label_position = "TC" @@ -49,6 +46,24 @@ def get_pygmt_basemap_figure(projection="N180/10c", region="d"): return fig +def plot_subduction_zones( + fig: pygmt.Figure, + gdf_subduction_left: GeoDataFrame, + gdf_subduction_right: GeoDataFrame, + color="blue", + **kwargs, +): + fig.plot( + data=gdf_subduction_left, pen=f"0.5p,{color}", fill=color, style="f0.2/0.08+l+t" + ) + fig.plot( + data=gdf_subduction_right, + pen=f"0.5p,{color}", + fill=color, + style="f0.2/0.08+r+t", + ) + + def plot_geo_data_frame(fig: pygmt.Figure, gdf: GeoDataFrame, **kwargs): line_width = "0.1p" line_color = "blue" @@ -84,7 +99,13 @@ def plot_geo_data_frame(fig: pygmt.Figure, gdf: GeoDataFrame, **kwargs): if "style" in kwargs.keys(): style = kwargs["style"] - fig.plot(data=gdf.geometry, pen=pen, fill=fill, style=style) + label = None + if "gmtlabel" in kwargs.keys(): + label = kwargs["gmtlabel"] + + fig.plot( + data=gdf.geometry, pen=pen, fill=fill, style=style, transparency=0, label=label + ) """ fig.plot(data=gdf_coastlines, fill=coastline_color, frame=["xa0", "ya0"], transparency=0) diff --git a/gplately/plot.py b/gplately/plot.py index 5d079e2c..6fb3e84c 100644 --- a/gplately/plot.py +++ b/gplately/plot.py @@ -45,8 +45,11 @@ validate_topology_availability, ) from .gpml import _load_FeatureCollection -from .mapping.plot_engine import PlotEngine -from .mapping.pygmt_plot import plot_geo_data_frame +from .mapping.plot_engine import PlotEngineType +from .mapping.pygmt_plot import ( + plot_geo_data_frame, + plot_subduction_zones as pygmt_plot_subduction_zones, +) from .pygplates import FeatureCollection as _FeatureCollection from .reconstruction import PlateReconstruction as _PlateReconstruction from .tools import EARTH_RADIUS @@ -300,7 +303,7 @@ def __init__( COBs=None, time=None, anchor_plate_id=0, - plot_engine: PlotEngine = PlotEngine.CARTOPY, + plot_engine: PlotEngineType = PlotEngineType.CARTOPY, ): self.plate_reconstruction = plate_reconstruction @@ -735,7 +738,7 @@ def _plot_feature(self, ax, get_feature_func, **kwargs): logger.warning("No feature found for plotting. Do nothing and return.") return ax - if self._plot_engine == PlotEngine.PYGMT: + if self._plot_engine == PlotEngineType.PYGMT: return plot_geo_data_frame(fig=ax, gdf=gdf, **kwargs) else: if hasattr(ax, "projection"): @@ -1083,10 +1086,10 @@ def get_subduction_direction(self): trench_right_features = shapelify_feature_lines(self.trench_right) gdf_left = gpd.GeoDataFrame( - {"geometry": trench_left_features}, geometry="geometry" + {"geometry": trench_left_features}, geometry="geometry", crs="EPSG:4326" ) gdf_right = gpd.GeoDataFrame( - {"geometry": trench_right_features}, geometry="geometry" + {"geometry": trench_right_features}, geometry="geometry", crs="EPSG:4326" ) return gdf_left, gdf_right @@ -1128,6 +1131,13 @@ def plot_subduction_teeth( See `Matplotlib` keyword arguments [here](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html). """ + if self._plot_engine == PlotEngineType.PYGMT: + gdf_subduction_left, gdf_subduction_right = self.get_subduction_direction() + pygmt_plot_subduction_zones( + ax, gdf_subduction_left, gdf_subduction_right, color=color, **kwargs + ) + return + if not self.plate_reconstruction.topology_features: logger.warn( "Plate model does not have topology features. Unable to plot_subduction_teeth." diff --git a/tests-dir/unittest/test_pygmt.ipynb b/tests-dir/unittest/test_pygmt.ipynb index 474f39cd..85fbb333 100644 --- a/tests-dir/unittest/test_pygmt.ipynb +++ b/tests-dir/unittest/test_pygmt.ipynb @@ -7,16 +7,21 @@ "metadata": {}, "outputs": [], "source": [ - "from gplately.mapping.plot_engine import PlotEngine\n", + "from gplately.mapping.plot_engine import PlotEngineType\n", "from gplately.mapping.pygmt_plot import get_pygmt_basemap_figure\n", "from gplately.auxiliary import get_gplot\n", "\n", - "gplot = get_gplot(\"merdith2021\", \"plate-model-repo\", age=55, plot_engine=PlotEngine.PYGMT)\n", + "gplot = get_gplot(\"merdith2021\", \"plate-model-repo\", age=55, plot_engine=PlotEngineType.PYGMT)\n", "fig = get_pygmt_basemap_figure(projection=\"N180/10c\", region=\"d\")\n", "#fig.coast(shorelines=True)\n", "\n", - "gplot.plot_topological_plate_boundaries(fig, edgecolor=\"blue\", linewidth=1.0, central_meridian=180, style='f0.2/0.08+l+t')\n", + "gplot.plot_topological_plate_boundaries(fig, edgecolor=\"black\", linewidth=0.25, central_meridian=180)\n", "gplot.plot_coastlines(fig, edgecolor=\"none\", facecolor='gray', linewidth=0.1, central_meridian=180)\n", + "gplot.plot_ridges(fig, pen='0.5p,red', gmtlabel=\"ridges\")\n", + "gplot.plot_subduction_teeth(fig, color=\"blue\")\n", + "\n", + "fig.text(text='what is this', position=\"TC\", no_clip=True, font=\"12p,Helvetica,black\", offset=\"j0/-0.5c\")\n", + "fig.legend(position='jBL+o-2.7/0', box=\"+gwhite+p0.5p\")\n", "\n", "fig.show(width=1200)\n", "# fig.savefig(\"test-pygmt-plot.pdf\")\n", diff --git a/tests-dir/unittest/test_pygmt_plot.py b/tests-dir/unittest/test_pygmt_plot.py index 19448ab6..4d1e9dd0 100644 --- a/tests-dir/unittest/test_pygmt_plot.py +++ b/tests-dir/unittest/test_pygmt_plot.py @@ -10,7 +10,7 @@ import gplately from gplately import PlateReconstruction, PlotTopologies -from gplately.mapping.plot_engine import PlotEngine +from gplately.mapping.plot_engine import PlotEngineType print(gplately.__file__) @@ -43,7 +43,7 @@ def main(show=True): COBs=model.get_layer("COBs", return_none_if_not_exist=True), continents=model.get_layer("ContinentalPolygons"), time=age, - plot_engine=PlotEngine.PYGMT, + plot_engine=PlotEngineType.PYGMT, ) # age = 100 From 0acf995001a64364d871b0a0c9ebc424d5b38398 Mon Sep 17 00:00:00 2001 From: michaelchin Date: Sat, 18 Jan 2025 08:07:59 +1100 Subject: [PATCH 11/11] add PlotEngine class --- gplately/mapping/__init__.py | 1 + gplately/mapping/cartopy_plot.py | 0 gplately/mapping/plot_engine.py | 23 +++++++++++++++++++++++ gplately/mapping/pygmt_plot.py | 24 ++++++++++++++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 gplately/mapping/__init__.py create mode 100644 gplately/mapping/cartopy_plot.py diff --git a/gplately/mapping/__init__.py b/gplately/mapping/__init__.py new file mode 100644 index 00000000..2bf22597 --- /dev/null +++ b/gplately/mapping/__init__.py @@ -0,0 +1 @@ +# This submodule contains code to plot maps. diff --git a/gplately/mapping/cartopy_plot.py b/gplately/mapping/cartopy_plot.py new file mode 100644 index 00000000..e69de29b diff --git a/gplately/mapping/plot_engine.py b/gplately/mapping/plot_engine.py index d0949397..ac0d529a 100644 --- a/gplately/mapping/plot_engine.py +++ b/gplately/mapping/plot_engine.py @@ -16,8 +16,31 @@ # from enum import Enum +from abc import ABC, abstractmethod + +from geopandas.geodataframe import GeoDataFrame class PlotEngineType(Enum): CARTOPY = 1 PYGMT = 2 + + +class PlotEngine(ABC): + @abstractmethod + def plot_geo_data_frame(self, gdf: GeoDataFrame, **kwargs): + pass # This is an abstract method, no implementation here. + + @abstractmethod + def plot_pygplates_features(self, features, **kwargs): + pass # This is an abstract method, no implementation here. + + @abstractmethod + def plot_subduction_zones( + self, + gdf_subduction_left: GeoDataFrame, + gdf_subduction_right: GeoDataFrame, + color="blue", + **kwargs, + ): + pass # This is an abstract method, no implementation here. diff --git a/gplately/mapping/pygmt_plot.py b/gplately/mapping/pygmt_plot.py index e48d1ee1..efaacf46 100644 --- a/gplately/mapping/pygmt_plot.py +++ b/gplately/mapping/pygmt_plot.py @@ -16,6 +16,7 @@ # from geopandas.geodataframe import GeoDataFrame import pygmt +from plot_engine import PlotEngine pygmt.config( FONT_ANNOT=8, @@ -40,6 +41,29 @@ label_position = "TC" +class PygmtPlotEngine(PlotEngine): + def __init__(self, projection="N180/10c", region="d"): + self.fig = pygmt.Figure() + self.fig.basemap(region=region, projection=projection, frame="lrtb") + + def plot_geo_data_frame(self, gdf: GeoDataFrame, **kwargs): + plot_geo_data_frame(self.fig, gdf, **kwargs) + + def plot_pygplates_features(self, features, **kwargs): + pass + + def plot_subduction_zones( + self, + gdf_subduction_left: GeoDataFrame, + gdf_subduction_right: GeoDataFrame, + color="blue", + **kwargs, + ): + plot_subduction_zones( + self.fig, gdf_subduction_left, gdf_subduction_right, color=color, **kwargs + ) + + def get_pygmt_basemap_figure(projection="N180/10c", region="d"): fig = pygmt.Figure() fig.basemap(region=region, projection=projection, frame="lrtb")