diff --git a/satpy/Cartopy Plot.ipynb b/satpy/Cartopy Plot.ipynb index b9f2e85..14e93e8 100644 --- a/satpy/Cartopy Plot.ipynb +++ b/satpy/Cartopy Plot.ipynb @@ -115,21 +115,21 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.5" + "pygments_lexer": "ipython3", + "version": "3.8.0" } }, "nbformat": 4, diff --git a/satpy/add_overlays_and_decorate_image.ipynb b/satpy/add_overlays_and_decorate_image.ipynb new file mode 100644 index 0000000..89cf70f --- /dev/null +++ b/satpy/add_overlays_and_decorate_image.ipynb @@ -0,0 +1,274 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "99b04380", + "metadata": {}, + "source": [ + "# Decorate your satellite images to make them ready for publication\n", + "This example demonstrate how you can add various overlays like coastlines, borders and graticules and how to decorate your image with text, points, logos, etc, in order to make it ready for publication.\n", + "\n", + "We load Meteosat SEVIRI data using Satpy and make an RGB using the `overview` composite. Data are resampled to the area defined in the `areas.yaml` file that comes with Satpy.\n", + "\n", + "First we need to locate the logo images we want to use, specify the fonts for overlaying text, and define the area and composite name/type:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d1b041bc", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from glob import glob\n", + "from satpy import Scene\n", + "\n", + "DATA_DIR = \"/home/a000680/data/hrit/20200923\"\n", + "FILES = glob(os.path.join(DATA_DIR, \"*\"))\n", + "\n", + "areaid = 'euro4'\n", + "composite_name = 'overview'\n", + "font = \"/usr/share/fonts/dejavu/DejaVuSerif.ttf\"\n", + "pytroll_logo = \"/home/a000680/data/logos/pytroll_dark_small.png\"\n", + "eumetsat_logo = \"/home/a000680/data/logos/eumetsat_logo.gif\"\n" + ] + }, + { + "cell_type": "markdown", + "id": "8d987a76", + "metadata": {}, + "source": [ + "## Prepare the drawing of graticules (grid lines) and ticks\n", + "\n", + "Then we prepare a dictionary specifying how we want the graticules to be later drawn over the image. Adding graticules is done via the Pycoast package, which in turn is using PIL and aggdraw to draw unaliased lines on images. See https://pycoast.readthedocs.io/en/latest/index.html. It will take the same key word arguments as the `add_grid` method, see https://pycoast.readthedocs.io/en/latest/api/pycoast.html#pycoast.cw_agg.ContourWriterAGG.add_grid." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "250273be", + "metadata": {}, + "outputs": [], + "source": [ + "grid = {'major_lonlat': (10, 10), 'minor_lonlat': (2, 2),\n", + " 'outline': (255, 255, 0), 'outline_opacity': 175,\n", + " 'width': 1.0, 'minor_width': 0.5, 'minor_is_tick': 1,\n", + " 'write_text': True, 'lat_placement': 'lr', 'lon_placement': 'b',\n", + " 'font': font}" + ] + }, + { + "cell_type": "markdown", + "id": "76bfa33d", + "metadata": {}, + "source": [ + "## Define how to draw points showing geographical places\n", + "\n", + "We also want to point out a few geographical places, in this case four capitals in Europe.\n", + "Each city will be marked by a white dot with a black ring around, and for each dot the name of the city is written in a red text box:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ba4354ba", + "metadata": {}, + "outputs": [], + "source": [ + "poi_list = [((2.3522, 48.8566), 'Paris'),\n", + " ((0.1278, 51.5074), 'London'),\n", + " ((12.568, 55.676), 'Copenhagen'),\n", + " ((24.938, 60.170), 'Helsinki')]\n", + "points = {'font': font,\n", + " 'font_size': 20, 'points_list': poi_list, 'symbol': 'circle', 'ptsize': 5,\n", + " 'outline': 'black', 'fill': 'white', 'width': 8, 'fill_opacity': 255, 'box_outline': 'black',\n", + " 'box_linewidth': 2.0, 'box_fill': (255, 0, 0), 'box_opacity': 127}" + ] + }, + { + "cell_type": "markdown", + "id": "83af0deb", + "metadata": {}, + "source": [ + "## Prepare the drawing of coastlines, borders and rivers\n", + "Now prepare the dictionaries with specifications for the coastlines, borders and rivers to be shown on the image:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "f619961a", + "metadata": {}, + "outputs": [], + "source": [ + "coast = {'outline': (255, 255, 255), 'width': 1.5, 'level': 1, 'resolution': 'l'}\n", + "borders = {'outline': (255, 255, 255), 'width': 1.0, 'level': 3, 'resolution': 'i'}\n", + "rivers = {'outline': (0, 0, 255), 'width': 1.0, 'level': 3, 'resolution': 'i'}" + ] + }, + { + "cell_type": "markdown", + "id": "918f6b17", + "metadata": {}, + "source": [ + "Adding points, coastlines, borders and rivers on the image is delegated to Pycoast as well.\n", + "\n", + "## Create the Scene object and load and resample the data\n", + "Now load the Meteosat SEVIRI scene and resample it onto the area specified via its name above (euro4):" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "56f76609", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/a000680/miniconda3/envs/python38/lib/python3.8/site-packages/pyproj/crs/crs.py:543: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems\n", + " proj_string = self.to_proj4()\n", + "/home/a000680/miniconda3/envs/python38/lib/python3.8/site-packages/pyproj/crs/crs.py:543: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems\n", + " proj_string = self.to_proj4()\n" + ] + } + ], + "source": [ + "scn = Scene(filenames=FILES, reader='seviri_l1b_hrit')\n", + "scn.load([composite_name])\n", + "local_scn = scn.resample(areaid, radius_of_influence=35000.0)" + ] + }, + { + "cell_type": "markdown", + "id": "6be1b4af", + "metadata": {}, + "source": [ + "## Define the adding of logos and text on the image\n", + "\n", + "Now we prepare how to decorate the image with logos and a header text including the time of observation, taken from the scene object:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8aa5ca1a", + "metadata": {}, + "outputs": [], + "source": [ + "start_time_txt = local_scn.start_time.strftime('%Y-%m-%d %H:%M')\n", + "\n", + "decoration = [\n", + " {'logo': {'logo_path': pytroll_logo,\n", + " 'height': 60, 'bg': 'white', 'bg_opacity': 120}},\n", + " {'logo': {'logo_path': eumetsat_logo,\n", + " 'height': 60, 'bg': 'white', 'bg_opacity': 120}},\n", + " {'text': {'txt': 'Meteosat-11' + ' ' + start_time_txt +\n", + " \"\\nComposite: \" + composite_name + \", Area: \" + areaid,\n", + " 'font': font,\n", + " 'font_size': 20, 'height': 10, 'bg': 'white', 'bg_opacity': 127, 'line': 'black'}}]" + ] + }, + { + "cell_type": "markdown", + "id": "c83081c9", + "metadata": {}, + "source": [ + "Adding logos and text to images is done via the Pytroll package Pydecorate. See https://pydecorate.readthedocs.io/en/latest/index.html. See the documentation for the `add_logo` and `add_text` methods for what options can be provided." + ] + }, + { + "cell_type": "markdown", + "id": "4fdfba2b", + "metadata": {}, + "source": [ + "## Apply the overlays and decoration defined above and save the image\n", + "\n", + "Now we can either show the image directly or save it to disk. When doing this it is possible to also add the decorations (logos and text) and draw the overlays (coastlines, rivers, borders, graticules and points). This is done using the keyword arguments `overlay` and `decorate` in this case. The path to the shape files with coastlines etc. needs to be specified:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "f11690a9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "seviri_overview_20200923_0815_euro4.tif\n" + ] + } + ], + "source": [ + "output_filename=f'seviri_{composite_name:s}_{local_scn.start_time:%Y%m%d_%H%M}_{areaid:s}.tif'\n", + "print(output_filename)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "18f49bc0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/a000680/miniconda3/envs/python38/lib/python3.8/site-packages/pyproj/crs/crs.py:543: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems\n", + " proj_string = self.to_proj4()\n", + "/home/a000680/miniconda3/envs/python38/lib/python3.8/site-packages/dask/core.py:121: RuntimeWarning: invalid value encountered in cos\n", + " return func(*(_execute_task(a, cache) for a in args))\n", + "/home/a000680/miniconda3/envs/python38/lib/python3.8/site-packages/dask/core.py:121: RuntimeWarning: invalid value encountered in sin\n", + " return func(*(_execute_task(a, cache) for a in args))\n", + "/home/a000680/miniconda3/envs/python38/lib/python3.8/site-packages/dask/core.py:121: RuntimeWarning: invalid value encountered in log\n", + " return func(*(_execute_task(a, cache) for a in args))\n" + ] + } + ], + "source": [ + "local_scn.save_dataset(composite_name,\n", + " filename=output_filename,\n", + " overlay={'coast_dir': '/home/a000680/data/shapes/',\n", + " 'overlays': {'grid': grid,\n", + " 'coasts': coast,\n", + " 'borders': borders,\n", + " 'rivers': rivers,\n", + " 'points': points}},\n", + " decorate={'decorate': decoration})" + ] + }, + { + "cell_type": "markdown", + "id": "ee03dfb6", + "metadata": {}, + "source": [ + "![Final SEVIRI overview RGB image with overlays, logos and text](https://www.kaggleusercontent.com/kf/65796474/eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..ZWve_3NbetaDimdsLVnd7w.Jt7byRDr-fZq62NNy6Qmp-qirYw4BDTzB8X_20Kx1ilMqjeSqbN0kGyAEAioyEucspv6KfgjhecFrM5RQvW8dIG_mSoIQ2AvE19DGKfoKhCxnMLt16eyI2Ebdg4YI2fOqbyrSZs36SKnwULH5sC3BkA5bmrnErPg6DNZnQcJW18rau1PmIj5xe0Q643HM2e_BP_GiFIZLULRUEFv6COKGRc_4Am1Lv6PrR8MW2XW1UwOCTFV7F7SP11qEORC3b0KZrzXWNmXDjw_5j0HVx6o17tRdHZDR1efEspv72a8i5_CnoIW-Gftcml-jCAeA5AiUhGDK315G0ntudjvUuu_sfNlNYwJQ6-OW7lk-VOb9VoQDpYX4-QKv0UhpmnE33bovm73mDQVWgEFFvg2KRvDhPOWfU6U8begv0z6v9bkpMGv0HzVka09HFIkUuP4copPvO56IeP2xFviOnXtme3Gs5VzlXU4pm-zsf6uKrhqyo_1BurT3ogk7QcYllhhMC4pnp58c7ckLzCJWwJenyjVSPBfq40ch0gBxviUXMqWc8DZFjnr9DptZjPGEDnDlwlYtpy4aP1lEAptA718-QzxGRilYo1q4NpsAuh9wvD1ESsHO18KP5fCksvn1MomMs513309bqWB_aYij1It4iqRv810rZAJuQGgGZzCmWSges27v2wPiA6YnJaQiwzpchCQzMJ1mw0gYnF_9mWbyJHAyQ.FU7-SbVowS9l4n6F7USB2A/__results___files/__results___18_0.png)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.8.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}