diff options
| -rw-r--r-- | .github/workflows/doc_build.yml | 17 | ||||
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | docs/plot/environment.yml | 89 | ||||
| -rwxr-xr-x[-rw-r--r--] | docs/plot/plot.py | 95 | ||||
| -rwxr-xr-x | docs/plot/plot.sh | 2 |
5 files changed, 56 insertions, 148 deletions
diff --git a/.github/workflows/doc_build.yml b/.github/workflows/doc_build.yml index 3d4e543d..85f93697 100644 --- a/.github/workflows/doc_build.yml +++ b/.github/workflows/doc_build.yml @@ -6,25 +6,18 @@ jobs: plots: name: Plots runs-on: ubuntu-latest - env: - PROJ_EXE: proj + defaults: + run: + shell: bash -l {0} steps: - name: Checkout uses: actions/checkout@v2 - uses: conda-incubator/setup-miniconda@v2 with: - channels: conda-forge - auto-update-conda: true - - name: Setup - shell: bash -l {0} - run: | - conda update -n base -c defaults conda - conda install descartes shapely geopandas matplotlib proj + environment-file: docs/plot/environment.yml - name: Plot - shell: bash -l {0} working-directory: ./docs/plot - run: | - ./plot.sh + run: ./plot.py plotdefs.json images/ - uses: actions/upload-artifact@v2 with: @@ -98,6 +98,7 @@ install_manifest.txt # docs /docs/.doxygen_up_to_date /docs/build +/docs/plot/images /latex # m4 diff --git a/docs/plot/environment.yml b/docs/plot/environment.yml index 3cf84a16..e6d0f9d4 100644 --- a/docs/plot/environment.yml +++ b/docs/plot/environment.yml @@ -1,86 +1,9 @@ name: proj channels: - - defaults + - conda-forge dependencies: - - blas=1.0=mkl - - bzip2=1.0.6=h1de35cc_5 - - ca-certificates=2018.03.07=0 - - cairo=1.14.12=hc4e6be7_4 - - certifi=2018.8.24=py37_1 - - click=6.7=py37_0 - - click-plugins=1.0.3=py37_1 - - cligj=0.4.0=py37_1 - - curl=7.61.0=ha441bb4_0 - - cycler=0.10.0=py37_0 - - descartes=1.1.0=py37_0 - - expat=2.2.6=h0a44026_0 - - fiona=1.7.12=py37h0dff353_0 - - fontconfig=2.13.0=h5d5b041_1 - - freetype=2.9.1=hb4e5f40_0 - - freexl=1.0.5=h1de35cc_0 - - gdal=2.2.4=py37h6440ff4_1 - - geos=3.6.2=h5470d99_2 - - gettext=0.19.8.1=h15daf44_3 - - giflib=5.1.4=h1de35cc_1 - - glib=2.56.2=hd9629dc_0 - - hdf4=4.2.13=h39711bb_2 - - hdf5=1.10.2=hfa1e0ec_1 - - icu=58.2=h4b95b61_1 - - intel-openmp=2019.0=118 - - jpeg=9b=he5867d9_2 - - json-c=0.13.1=h3efe00b_0 - - kealib=1.4.7=h40e48e4_6 - - kiwisolver=1.0.1=py37h0a44026_0 - - krb5=1.16.1=h24a3359_6 - - libboost=1.67.0=hebc422b_4 - - libcurl=7.61.0=hf30b1f0_0 - - libcxx=4.0.1=h579ed51_0 - - libcxxabi=4.0.1=hebd6815_0 - - libdap4=3.19.1=h3d3e54a_0 - - libedit=3.1.20170329=hb402a30_2 - - libffi=3.2.1=h475c297_4 - - libgdal=2.2.4=h7b1ea53_1 - - libgfortran=3.0.1=h93005f0_2 - - libiconv=1.15=hdd342a3_7 - - libkml=1.3.0=hbe12b63_4 - - libnetcdf=4.6.1=h4e6abe9_1 - - libpng=1.6.34=he12f830_0 - - libpq=10.5=hf30b1f0_0 - - libspatialite=4.3.0a=ha12ebda_19 - - libssh2=1.8.0=h322a93b_4 - - libtiff=4.0.9=hcb84e12_2 - - libuuid=1.0.3=h6bb4b03_2 - - libxml2=2.9.8=hab757c2_1 - - matplotlib=2.2.3=py37h54f8f79_0 - - mkl=2019.0=118 - - mkl_fft=1.0.4=py37h5d10147_1 - - mkl_random=1.0.1=py37h5d10147_1 - - munch=2.3.2=py37_0 - - ncurses=6.1=h0a44026_0 - - numpy=1.15.1=py37h6a91979_0 - - numpy-base=1.15.1=py37h8a80b8c_0 - - openjpeg=2.3.0=hb95cd4c_1 - - openssl=1.0.2p=h1de35cc_0 - - pcre=8.42=h378b8a2_0 - - pip=10.0.1=py37_0 - - pixman=0.34.0=hca0a616_3 - - poppler=0.65.0=ha097c24_1 - - poppler-data=0.4.9=0 - - proj4=5.0.1=h1de35cc_0 - - pyparsing=2.2.0=py37_1 - - python=3.7.0=hc167b69_0 - - python-dateutil=2.7.3=py37_0 - - pytz=2018.5=py37_0 - - readline=7.0=h1de35cc_5 - - setuptools=40.2.0=py37_0 - - shapely=1.6.4=py37h20de77a_0 - - six=1.11.0=py37_1 - - sqlite=3.24.0=ha441bb4_0 - - tk=8.6.8=ha441bb4_0 - - tornado=5.1=py37h1de35cc_0 - - wheel=0.31.1=py37_0 - - xerces-c=3.2.1=h44e365a_0 - - xz=5.2.4=h1de35cc_4 - - zlib=1.2.11=hf3cbc9b_2 -prefix: /usr/local/miniconda3/envs/proj - + - descartes + - geojson + - matplotlib + - proj + - shapely < 1.8 diff --git a/docs/plot/plot.py b/docs/plot/plot.py index 13ed332c..221f5b56 100644..100755 --- a/docs/plot/plot.py +++ b/docs/plot/plot.py @@ -1,5 +1,6 @@ +#!/usr/bin/env python3 ''' -Plot map data in different projections supported by PROJ.4 +Plot map data in different projections supported by PROJ. Call with: @@ -41,30 +42,28 @@ or "line". The rest of the inputs are fairly free form. Change PROJ to path on your local system before running the script. ''' -from __future__ import print_function -from __future__ import division - +import argparse import os -import os.path import shutil import sys import json import subprocess import functools +from pathlib import Path +import geojson import numpy as np import matplotlib.pyplot as plt -from matplotlib.patches import Polygon -import fiona -from shapely.geometry import Polygon -from shapely.geometry import MultiPolygon +from shapely.geometry import MultiPolygon, Polygon, box as Box from shapely.geometry import shape from shapely.ops import transform from descartes import PolygonPatch PROJ_COMMAND = os.environ.get('PROJ_EXE', '../../src/proj') if not os.path.exists(PROJ_COMMAND): - PROJ = shutil.which(PROJ_COMMAND) + PROJ = shutil.which('proj') + if PROJ is None: + raise ValueError("specify PROJ_EXE or modify PATH to find proj") else: PROJ = PROJ_COMMAND PROJ_LIB = os.environ.get('PROJ_LIB', '../../data') @@ -246,25 +245,19 @@ def plotproj(plotdef, data, outdir): ''' axes = plt.axes() - bounds = (plotdef['lonmin'], plotdef['latmin'], plotdef['lonmax'], plotdef['latmax']) - for geom in data.filter(bbox=bounds): - temp_pol = shape(geom['geometry']) - - box = Polygon([ - (plotdef['lonmin'], plotdef['latmin']), - (plotdef['lonmin'], plotdef['latmax']), - (plotdef['lonmax'], plotdef['latmax']), - (plotdef['lonmax'], plotdef['latmin']), - ]) - try: - temp_pol = temp_pol.intersection(box) - except Exception as e: + box = Box( + plotdef['lonmin'], plotdef['latmin'], + plotdef['lonmax'], plotdef['latmax']) + for feat in data["features"]: + geom = shape(feat["geometry"]) + if not geom.intersects(box): continue + temp_pol = geom.intersection(box) if plotdef['type'] == 'poly': if isinstance(temp_pol, MultiPolygon): - polys = [resample_polygon(polygon) for polygon in temp_pol] + polys = [resample_polygon(polygon) for polygon in temp_pol.geoms] pol = MultiPolygon(polys) else: pol = resample_polygon(temp_pol) @@ -326,9 +319,12 @@ def plotproj(plotdef, data, outdir): # Make sure the plot is not stretched axes.set_aspect('equal') - if not os.path.exists(outdir): - os.makedirs(outdir) - plt.savefig(outdir + '/' + plotdef['filename'], + outdir = Path(outdir) + if not outdir.exists(): + outdir.mkdir(parents=True) + if not outdir.is_dir(): + raise OSError("outdir is not a directory") + plt.savefig(outdir / plotdef['filename'], dpi=400, bbox_inches='tight') @@ -338,36 +334,22 @@ def plotproj(plotdef, data, outdir): plt.close() -def main(): +def main(plotdefs, outdir, plots=[]): ''' Main function of plotting script. Parses json-file with plot setups and runs the plotting for each plot setup. ''' + plotdefs = json.loads(Path(plotdefs).read_text()) data = { - ('line', 'low'): fiona.open(LINE_LOW), - ('line', 'med'): fiona.open(LINE_MED), - ('poly', 'low'): fiona.open(POLY_LOW), - ('poly', 'med'): fiona.open(POLY_MED), + ('line', 'low'): geojson.loads(Path(LINE_LOW).read_text()), + ('line', 'med'): geojson.loads(Path(LINE_MED).read_text()), + ('poly', 'low'): geojson.loads(Path(POLY_LOW).read_text()), + ('poly', 'med'): geojson.loads(Path(POLY_MED).read_text()), } - if os.path.exists(sys.argv[1]): - # first argument is the JSON plot definition setup file - with open(sys.argv[1]) as plotsetup: - plotdefs = json.load(plotsetup) - else: - raise ValueError('No plot definition file entered') - - plots = [] - # second argument is the output dir - outdir = sys.argv[2] - - # subsecond arguments are (optional) names of plot in plotdef.json - if len(sys.argv) > 3: - plots = sys.argv[3:len(sys.argv)] - for i, plotdef in enumerate(plotdefs): if plots != [] and plotdef['name'] not in plots: continue @@ -379,9 +361,20 @@ def main(): plotproj(plotdef, data[(plotdef['type'], plotdef['res'])], outdir) - for key in data: - data[key].close() - if __name__ == "__main__": - sys.exit(main()) + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument( + 'plotdefs', + help='A JSON file with setup for each auto-generated plot') + parser.add_argument( + 'outdir', + help='Directory to put the plots in.') + parser.add_argument( + 'plots', nargs='*', + help='A list of plot names within the plotdefs file. ' + 'More than one plotname can be given at once.') + args = parser.parse_args() + sys.exit(main(**vars(args))) diff --git a/docs/plot/plot.sh b/docs/plot/plot.sh deleted file mode 100755 index 3a939f4a..00000000 --- a/docs/plot/plot.sh +++ /dev/null @@ -1,2 +0,0 @@ - -python3 plot.py plotdefs.json images/ |
