{ "cells": [ { "cell_type": "markdown", "id": "rational-surgery", "metadata": {}, "source": [ "# Using Exotic Map Projections: `useCRS=\"provided\"`\n", "\n", "Value \"provided\" tells Lets-Plot that the input `SpatialDataset` already contains coordinates in the desired CRS and should not be reprojected any further.\n", "\n", "This is a workaround for the case when the desired CRS is not naturally supported by Lets-Plot.\n", "\n", "> Note: at the moment, Lets-Plot only supports **WGS84** CRS and the Mercator projection.\n", "\n", "For example, if you try to plot a `SpatialDataset` which uses the **Conus Albers** CRS (EPSG:5070), then Lets-Plot will return an error:\n", "\n", "> Geometry must use WGS84 coordinate reference system but was: NAD83 / Conus Albers.\n", "\n", "Let's see how can we still plot a map in the **Conus Albers** projection in Lets-Plot.\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "relative-skiing", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%useLatestDescriptors\n", "%use lets-plot" ] }, { "cell_type": "code", "execution_count": 2, "id": "mighty-pollution", "metadata": {}, "outputs": [], "source": [ "%use lets-plot-gt" ] }, { "cell_type": "code", "execution_count": 3, "id": "hydraulic-spyware", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Lets-Plot Kotlin API v.4.4.2. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.4.0.0." ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LetsPlot.getInfo()" ] }, { "cell_type": "code", "execution_count": 4, "id": "initial-resident", "metadata": {}, "outputs": [], "source": [ "LetsPlot.theme = themeBW()" ] }, { "cell_type": "markdown", "id": "round-peter", "metadata": {}, "source": [ "#### 1. Load North America `FeatureCollection` from \"natural earth\" Shapefiles\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "hollow-chapel", "metadata": {}, "outputs": [], "source": [ "@file:DependsOn(\"org.geotools:gt-shapefile:[23,)\")\n", "@file:DependsOn(\"org.geotools:gt-cql:[23,)\")\n", "@file:DependsOn(\"org.geotools:gt-epsg-hsql:[23,)\")\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "suspected-therapist", "metadata": {}, "outputs": [], "source": [ "import org.geotools.data.shapefile.ShapefileDataStoreFactory\n", "import org.geotools.data.simple.SimpleFeatureCollection\n", "import org.geotools.filter.text.cql2.CQL\n", "import java.net.URL\n", "\n", "val factory = ShapefileDataStoreFactory()" ] }, { "cell_type": "code", "execution_count": 7, "id": "dying-spending", "metadata": {}, "outputs": [], "source": [ "val worldFeatures : SimpleFeatureCollection = with(\"naturalearth_lowres\") {\n", " val url = \"https://raw.githubusercontent.com/JetBrains/lets-plot-kotlin/master/docs/examples/shp/${this}/${this}.shp\"\n", " factory.createDataStore(URL(url)).featureSource.features\n", "}\n" ] }, { "cell_type": "code", "execution_count": 8, "id": "brilliant-sixth", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Oceania, Africa, North America, Asia, South America, Europe, Seven seas (open ocean), Antarctica]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "worldFeatures.toSpatialDataset()[\"continent\"]?.distinct()" ] }, { "cell_type": "code", "execution_count": 9, "id": "cellular-manitoba", "metadata": {}, "outputs": [], "source": [ "// Obtain North America feature collection.\n", "val northAmFc = worldFeatures.subCollection(\n", " CQL.toFilter(\"continent = 'North America'\")\n", ")" ] }, { "cell_type": "code", "execution_count": 10, "id": "optional-jones", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "GCS_WGS_1984" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Convert \"North America\" Feature Collection to a SpatialDataset.\n", "// Use 10 decimals to encode floating point numbers (this is the default).\n", "val northAmSds = northAmFc.toSpatialDataset(10)\n", "northAmSds.crs" ] }, { "cell_type": "markdown", "id": "distant-conflict", "metadata": {}, "source": [ "#### 2. A Map of North America in the *Mercator* Projection\n", "\n", "The Mercator projection is a map projection used by Lets-Plot by default when plotting a `SpatialDataset`.\n", "\n", "Note that `northAmSds` dataset uses **WGS84** (or *GCS_WGS_1984*) CRS which is naitively supported by Lets-Plot." ] }, { "cell_type": "code", "execution_count": 11, "id": "worthy-korea", "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "letsPlot() + geomMap(map = northAmSds, fill = \"blue\", color = \"white\", size = 1)" ] }, { "cell_type": "markdown", "id": "proud-capture", "metadata": {}, "source": [ "#### 3. Reproject North America Feature Collection Using the *Conus Albers* Projection\n" ] }, { "cell_type": "code", "execution_count": 12, "id": "sized-trading", "metadata": {}, "outputs": [], "source": [ "import org.geotools.referencing.CRS\n", "import org.geotools.data.store.ReprojectingFeatureCollection" ] }, { "cell_type": "code", "execution_count": 13, "id": "numeric-stevens", "metadata": {}, "outputs": [], "source": [ "val сonusAlbers = CRS.decode(\"EPSG:5070\", true)\n", "\n", "val northAmAlbersFc = ReprojectingFeatureCollection(northAmFc, сonusAlbers)" ] }, { "cell_type": "code", "execution_count": 14, "id": "likely-tokyo", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "NAD83 / Conus Albers" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val northAmAlbersSds = northAmAlbersFc.toSpatialDataset(10)\n", "northAmAlbersSds.crs" ] }, { "cell_type": "markdown", "id": "comic-result", "metadata": {}, "source": [ "#### 4. A Map of North America in the *Conus Albers* Projection\n" ] }, { "cell_type": "markdown", "id": "infrared-orbit", "metadata": {}, "source": [ "##### 4.1. Lets-Plot doesn't Support the *Conus Albers* Projection" ] }, { "cell_type": "code", "execution_count": 15, "id": "scenic-nebraska", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "java.lang.IllegalArgumentException: Geometry must use WGS84 coordinate reference system but was: NAD83 / Conus Albers.\n" ] } ], "source": [ "// This attempt to create a map will fail with the error shown below.\n", "\n", "// letsPlot() + geomMap(map = northAmAlbertsSds)\n", "\n", "val p = letsPlot() + geomMap(map = northAmAlbersSds)\n", "\n", "try {\n", " p.toSpec()\n", "} catch(e:Exception) {\n", " println(e)\n", "}" ] }, { "cell_type": "markdown", "id": "labeled-plant", "metadata": {}, "source": [ "##### 4.2. A Map in the Conus Albers Projection with the Help of the `useCRS = \"provided\"` parameter" ] }, { "cell_type": "code", "execution_count": 16, "id": "hispanic-psychiatry", "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "letsPlot() + \n", " geomMap(map = northAmAlbersSds, useCRS = \"provided\", fill = \"blue\", color = \"white\", size = 1) +\n", " theme(axis = \"blank\")" ] } ], "metadata": { "kernelspec": { "display_name": "Kotlin", "language": "kotlin", "name": "kotlin" }, "language_info": { "codemirror_mode": "text/x-kotlin", "file_extension": ".kt", "mimetype": "text/x-kotlin", "name": "kotlin", "nbconvert_exporter": "", "pygments_lexer": "kotlin", "version": "1.8.20" } }, "nbformat": 4, "nbformat_minor": 5 }