changeset 3:663268794710 draft

"planemo upload for repository https://github.com/galaxyecology/tools-ecology/tree/master/tools/data_manipulation/xarray/ commit 57b6d23e3734d883e71081c78e77964d61be82ba"
author ecology
date Sun, 06 Jun 2021 08:49:43 +0000
parents e8650cdf092f
children 9bbaab36a5d4
files macros.xml test-data/all.netcdf test-data/dataset-ibi-reanalysis-bio-005-003-monthly-regulargrid_1510914389133_time0.png test-data/dataset-ibi-reanalysis-bio-005-003-monthly-regulargrid_1510914389133_time1.png test-data/dataset-ibi-reanalysis-bio-005-003-monthly-regulargrid_1510914389133_time50.png test-data/depth.tabular test-data/latitude.tabular test-data/longitude.tabular test-data/small.netcdf test-data/time.tabular test-data/version.tabular xarray_mapplot.py xarray_metadata_info.xml xarray_netcdf2netcdf.py xarray_tool.py
diffstat 15 files changed, 1209 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/macros.xml	Sun Jun 06 08:49:43 2021 +0000
@@ -0,0 +1,185 @@
+<macros>
+    <token name="@TOOL_VERSION@">0.18.2</token>
+    <token name="@VERSION_SUFFIX@">0</token>
+    <xml name="edam_ontology">
+        <edam_topics>
+            <edam_topic>topic_0610</edam_topic>
+            <edam_topic>topic_3050</edam_topic>
+        </edam_topics>
+    </xml>
+    <xml name="citations">
+        <citations>
+            <citation type="bibtex">
+                @article{hoyer2017xarray,
+                    title     = {xarray: {N-D} labeled arrays and datasets in {Python}},
+                    author    = {Hoyer, S. and J. Hamman},
+                    journal   = {Journal of Open Research Software},
+                    volume    = {5},
+                    number    = {1},
+                    year      = {2017},
+                    publisher = {Ubiquity Press},
+                    doi       = {10.5334/jors.148},
+                    url       = {http://doi.org/10.5334/jors.148}
+                }
+            </citation>
+        </citations>
+    </xml>
+    <xml name="customize_appearance_plots">
+        <param name="borders" type="float" optional="true" label="Add country borders with alpha value [0-1] (optional)" />
+        <param name="coastline" type="float" optional="true" label="Add coastline with alpha value [0-1] (optional)" />
+        <param name="ocean" type="float" optional="true" label="Add ocean with alpha value [0-1] (optional)" />
+        <param name="land" type="float" optional="true" label="Add land with alpha value [0-1] (optional)" />
+        <param name="title" type="text" optional="true" label="Specify plot title (optional)" />
+        <param name="colorbar_label" type="text"  optional="true" label="Set a label for colormap (optional)" />
+        <param name="cmap" type="select" optional="true" label="Specify which colormap to use for plotting (optional)">
+            <option value="cm.batlow">batlow</option>
+            <option value="cm.batlowW">batlowW</option>
+            <option value="cm.batlowK">batlowK</option>
+            <option value="cm.devon">devon</option>
+            <option value="cm.davos">davos</option>
+            <option value="cm.oslo">oslo</option>
+            <option value="cm.lapaz">lapaz</option>
+            <option value="cm.acton">acton</option>
+            <option value="cm.lajolla">lajolla</option>
+            <option value="cm.bilbao">bilbao</option>
+            <option value="cm.grayC">grayC</option>
+            <option value="cm.tokyo">tokyo</option>
+            <option value="cm.turku">turku</option>
+            <option value="cm.bamako">bamako</option>
+            <option value="cm.nuuk">nuuk</option>
+            <option value="cm.hawaii">hawaii</option>
+            <option value="cm.buda">buda</option>
+            <option value="cm.imola">imola</option>
+            <option value="cm.broc">broc</option>
+            <option value="cm.lisbon">lisbon</option>
+            <option value="cm.roma">roma</option>
+            <option value="cm.cork">cork</option>
+            <option value="cm.tofino">tofino</option>
+            <option value="cm.bam">bam</option>
+            <option value="cm.vik">vik</option>
+            <option value="cm.berlin">berlin</option>
+            <option value="cm.vanimo">vanimo</option>
+            <option value="cm.oleron">oleron</option>
+            <option value="cm.bukavu">bukavu</option>
+            <option value="cm.fes">fes</option>
+            <option value="cm.romaO">romaO</option>
+            <option value="cm.bamO">bamO</option>
+            <option value="cm.brocO">brocO</option>
+            <option value="cm.corkO">corkO</option>
+            <option value="cm.vikO">vikO</option>
+            <option value="cm.batlow_r">batlow_r</option>
+            <option value="cm.batlowW_r">batlowW_r</option>
+            <option value="cm.batlowK_r">batlowK_r</option>
+            <option value="cm.devon_r">devon_r</option>
+            <option value="cm.davos_r">davos_r</option>
+            <option value="cm.oslo_r">oslo_r</option>
+            <option value="cm.lapaz_r">lapaz_r</option>
+            <option value="cm.acton_r">acton_r</option>
+            <option value="cm.lajolla_r">lajolla_r</option>
+            <option value="cm.bilbao_r">bilbao_r</option>
+            <option value="cm.grayC_r">grayC_r</option>
+            <option value="cm.tokyo_r">tokyo_r</option>
+            <option value="cm.turku_r">turku_r</option>
+            <option value="cm.bamako_r">bamako_r</option>
+            <option value="cm.nuuk_r">nuuk_r</option>
+            <option value="cm.hawaii_r">hawaii_r</option>
+            <option value="cm.buda_r">buda_r</option>
+            <option value="cm.imola_r">imola_r</option>
+            <option value="cm.broc_r">broc_r</option>
+            <option value="cm.lisbon_r">lisbon_r</option>
+            <option value="cm.roma_r">roma_r</option>
+            <option value="cm.cork_r">cork_r</option>
+            <option value="cm.tofino_r">tofino_r</option>
+            <option value="cm.bam_r">bam_r</option>
+            <option value="cm.vik_r">vik_r</option>
+            <option value="cm.berlin_r">berlin_r</option>
+            <option value="cm.vanimo_r">vanimo_r</option>
+            <option value="cm.oleron_r">oleron_r</option>
+            <option value="cm.bukavu_r">bukavu_r</option>
+            <option value="cm.fes_r">fes_r</option>
+            <option value="cm.romaO_r">romaO_r</option>
+            <option value="cm.bamO_r">bamO_r</option>
+            <option value="cm.brocO_r">brocO_r</option>
+            <option value="cm.corkO_r">corkO_r</option>
+            <option value="cm.vikO_r">vikO_r</option>
+            <option value="Accent">Accent</option>
+            <option value="Blues">Blues</option>
+            <option value="BrBG">BrBG</option>
+            <option value="BuGn">BuGn</option>
+            <option value="BuPu">BuPu</option>
+            <option value="CMRmap">CMRmap</option>
+            <option value="Dark2">Dark2</option>
+            <option value="GnBu">GnBu</option>
+            <option value="Greens">Greens</option>
+            <option value="Greys">Greys</option>
+            <option value="OrRd">OrRd</option>
+            <option value="Oranges">Oranges</option>
+            <option value="PRGn">PRGn</option>
+            <option value="Paired">Paired</option>
+            <option value="Pastel1">Pastel1</option>
+            <option value="Pastel2">Pastel2</option>
+            <option value="PiYG">PiYG</option>
+            <option value="PuBu">PuBu</option>
+            <option value="PuBuGn">PuBuGn</option>
+            <option value="PuOr">PuOr</option>
+            <option value="PuRd">PuRd</option>
+            <option value="Purples">Purples</option>
+            <option value="RdBu">RdBu</option>
+            <option value="RdGy">RdGy</option>
+            <option value="RdPu">RdPu</option>
+            <option value="RdBu_r">RdBu_r</option>
+            <option value="RdGy_r">RdGy_r</option>
+            <option value="RdPu_r">RdPu_r</option>
+            <option value="RdYlBu">RdYlBu</option>
+            <option value="RdYlGn">RdYlGn</option>
+            <option value="Reds">Reds</option>
+            <option value="Set1">Set1</option>
+            <option value="Set2">Set2</option>
+            <option value="Set3">Set3</option>
+            <option value="Spectral">Spectral</option>
+            <option value="Wistia">Wistia</option>
+            <option value="YlGn">YlGn</option>
+            <option value="YlGnBu">YlGnBu</option>
+            <option value="YlOrBr">YlOrBr</option>
+            <option value="YlOrRd">YlOrRd</option>
+            <option value="afmhot">afmhot</option>
+            <option value="autumn">autumn</option>
+            <option value="binary">binary</option>
+            <option value="bone">bone</option>
+            <option value="brg">brg</option>
+            <option value="bwr">bwr</option>
+            <option value="cool">cool</option>
+            <option value="coolwarm" selected="true">coolwarm</option>
+            <option value="copper">copper</option>
+            <option value="cubehelix">cubehelix</option>
+            <option value="flag">flag</option>
+            <option value="gist_earth">gist_earth</option>
+            <option value="gist_gray">gist_gray</option>
+            <option value="gist_heat">gist_heat</option>
+            <option value="gist_ncar">gist_ncar</option>
+            <option value="gist_rainbow">gist_rainbow</option>
+            <option value="gist_stern">gist_stern</option>
+            <option value="gist_yarg">gist_yarg</option>
+            <option value="gnuplot">gnuplot</option>
+            <option value="gnuplot2">gnuplot2</option>
+            <option value="gray">gray</option>
+            <option value="hot">hot</option>
+            <option value="hsv">hsv</option>
+            <option value="jet">jet</option>
+            <option value="nipy_spectral">nipy_spectral</option>
+            <option value="ocean">ocean</option>
+            <option value="pink">pink</option>
+            <option value="prism">prism</option>
+            <option value="rainbow">rainbow</option>
+            <option value="seismic">seismic</option>
+            <option value="spring">spring</option>
+            <option value="summer">summer</option>
+            <option value="tab10">tab10</option>
+            <option value="tab20">tab20</option>
+            <option value="tab20b">tab20b</option>
+            <option value="tab20c">tab20c</option>
+            <option value="terrain">terrain</option>
+            <option value="winter">winter</option>
+        </param>
+    </xml>
+</macros>
Binary file test-data/all.netcdf has changed
Binary file test-data/dataset-ibi-reanalysis-bio-005-003-monthly-regulargrid_1510914389133_time0.png has changed
Binary file test-data/dataset-ibi-reanalysis-bio-005-003-monthly-regulargrid_1510914389133_time1.png has changed
Binary file test-data/dataset-ibi-reanalysis-bio-005-003-monthly-regulargrid_1510914389133_time50.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/depth.tabular	Sun Jun 06 08:49:43 2021 +0000
@@ -0,0 +1,1 @@
+0	0.50576
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/latitude.tabular	Sun Jun 06 08:49:43 2021 +0000
@@ -0,0 +1,97 @@
+0	43.0
+1	43.083332
+2	43.166664
+3	43.25
+4	43.333332
+5	43.416664
+6	43.5
+7	43.583332
+8	43.666664
+9	43.75
+10	43.833332
+11	43.916664
+12	44.0
+13	44.083332
+14	44.166664
+15	44.25
+16	44.333332
+17	44.416664
+18	44.5
+19	44.583332
+20	44.666664
+21	44.75
+22	44.833332
+23	44.916664
+24	45.0
+25	45.083332
+26	45.166664
+27	45.25
+28	45.333332
+29	45.416664
+30	45.5
+31	45.583332
+32	45.666664
+33	45.75
+34	45.833332
+35	45.916664
+36	46.0
+37	46.083332
+38	46.166664
+39	46.25
+40	46.333332
+41	46.416664
+42	46.5
+43	46.583332
+44	46.666664
+45	46.75
+46	46.833332
+47	46.916664
+48	47.0
+49	47.083332
+50	47.166664
+51	47.25
+52	47.333332
+53	47.416664
+54	47.5
+55	47.583332
+56	47.666664
+57	47.75
+58	47.833332
+59	47.916664
+60	48.0
+61	48.083332
+62	48.166664
+63	48.25
+64	48.333332
+65	48.416664
+66	48.5
+67	48.583332
+68	48.666664
+69	48.75
+70	48.833332
+71	48.916664
+72	49.0
+73	49.083332
+74	49.166664
+75	49.25
+76	49.333332
+77	49.416664
+78	49.5
+79	49.583332
+80	49.666664
+81	49.75
+82	49.833332
+83	49.916664
+84	50.0
+85	50.083332
+86	50.166664
+87	50.25
+88	50.333332
+89	50.416664
+90	50.5
+91	50.583332
+92	50.666664
+93	50.75
+94	50.833332
+95	50.916664
+96	51.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/longitude.tabular	Sun Jun 06 08:49:43 2021 +0000
@@ -0,0 +1,103 @@
+0	-6.0000005
+1	-5.916667
+2	-5.833334
+3	-5.7500005
+4	-5.666667
+5	-5.583334
+6	-5.5000005
+7	-5.416667
+8	-5.333334
+9	-5.2500005
+10	-5.166667
+11	-5.083334
+12	-5.0000005
+13	-4.9166675
+14	-4.833334
+15	-4.7500005
+16	-4.6666675
+17	-4.583334
+18	-4.5000005
+19	-4.4166675
+20	-4.333334
+21	-4.2500005
+22	-4.1666675
+23	-4.083334
+24	-4.0000005
+25	-3.9166672
+26	-3.833334
+27	-3.7500007
+28	-3.6666672
+29	-3.583334
+30	-3.5000007
+31	-3.4166672
+32	-3.333334
+33	-3.2500007
+34	-3.1666672
+35	-3.083334
+36	-3.0000007
+37	-2.9166672
+38	-2.833334
+39	-2.7500007
+40	-2.6666672
+41	-2.583334
+42	-2.5000007
+43	-2.4166672
+44	-2.333334
+45	-2.2500007
+46	-2.1666672
+47	-2.083334
+48	-2.0000007
+49	-1.9166673
+50	-1.833334
+51	-1.7500007
+52	-1.6666673
+53	-1.5833341
+54	-1.5000007
+55	-1.4166673
+56	-1.3333341
+57	-1.2500007
+58	-1.1666673
+59	-1.0833341
+60	-1.0000007
+61	-0.9166674
+62	-0.8333341
+63	-0.7500007
+64	-0.6666674
+65	-0.5833341
+66	-0.5000007
+67	-0.4166674
+68	-0.3333341
+69	-0.25000075
+70	-0.16666742
+71	-0.08333409
+72	-7.6e-07
+73	0.08333257
+74	0.1666659
+75	0.24999923
+76	0.33333257
+77	0.41666588
+78	0.49999923
+79	0.58333254
+80	0.66666585
+81	0.7499992
+82	0.83333254
+83	0.91666585
+84	0.9999992
+85	1.0833325
+86	1.1666659
+87	1.2499992
+88	1.3333325
+89	1.4166658
+90	1.4999992
+91	1.5833325
+92	1.6666658
+93	1.7499992
+94	1.8333325
+95	1.9166658
+96	1.9999992
+97	2.0833325
+98	2.1666658
+99	2.249999
+100	2.3333325
+101	2.4166658
+102	2.499999
Binary file test-data/small.netcdf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/time.tabular	Sun Jun 06 08:49:43 2021 +0000
@@ -0,0 +1,145 @@
+0	2002-12-15
+1	2003-01-15
+2	2003-02-15
+3	2003-03-15
+4	2003-04-15
+5	2003-05-15
+6	2003-06-15
+7	2003-07-15
+8	2003-08-15
+9	2003-09-15
+10	2003-10-15
+11	2003-11-15
+12	2003-12-15
+13	2004-01-15
+14	2004-02-15
+15	2004-03-15
+16	2004-04-15
+17	2004-05-15
+18	2004-06-15
+19	2004-07-15
+20	2004-08-15
+21	2004-09-15
+22	2004-10-15
+23	2004-11-15
+24	2004-12-15
+25	2005-01-15
+26	2005-02-15
+27	2005-03-15
+28	2005-04-15
+29	2005-05-15
+30	2005-06-15
+31	2005-07-15
+32	2005-08-15
+33	2005-09-15
+34	2005-10-15
+35	2005-11-15
+36	2005-12-15
+37	2006-01-15
+38	2006-02-15
+39	2006-03-15
+40	2006-04-15
+41	2006-05-15
+42	2006-06-15
+43	2006-07-15
+44	2006-08-15
+45	2006-09-15
+46	2006-10-15
+47	2006-11-15
+48	2006-12-15
+49	2007-01-15
+50	2007-02-15
+51	2007-03-15
+52	2007-04-15
+53	2007-05-15
+54	2007-06-15
+55	2007-07-15
+56	2007-08-15
+57	2007-09-15
+58	2007-10-15
+59	2007-11-15
+60	2007-12-15
+61	2008-01-15
+62	2008-02-15
+63	2008-03-15
+64	2008-04-15
+65	2008-05-15
+66	2008-06-15
+67	2008-07-15
+68	2008-08-15
+69	2008-09-15
+70	2008-10-15
+71	2008-11-15
+72	2008-12-15
+73	2009-01-15
+74	2009-02-15
+75	2009-03-15
+76	2009-04-15
+77	2009-05-15
+78	2009-06-15
+79	2009-07-15
+80	2009-08-15
+81	2009-09-15
+82	2009-10-15
+83	2009-11-15
+84	2009-12-15
+85	2010-01-15
+86	2010-02-15
+87	2010-03-15
+88	2010-04-15
+89	2010-05-15
+90	2010-06-15
+91	2010-07-15
+92	2010-08-15
+93	2010-09-15
+94	2010-10-15
+95	2010-11-15
+96	2010-12-15
+97	2011-01-15
+98	2011-02-15
+99	2011-03-15
+100	2011-04-15
+101	2011-05-15
+102	2011-06-15
+103	2011-07-15
+104	2011-08-15
+105	2011-09-15
+106	2011-10-15
+107	2011-11-15
+108	2011-12-15
+109	2012-01-15
+110	2012-02-15
+111	2012-03-15
+112	2012-04-15
+113	2012-05-15
+114	2012-06-15
+115	2012-07-15
+116	2012-08-15
+117	2012-09-15
+118	2012-10-15
+119	2012-11-15
+120	2012-12-15
+121	2013-01-15
+122	2013-02-15
+123	2013-03-15
+124	2013-04-15
+125	2013-05-15
+126	2013-06-15
+127	2013-07-15
+128	2013-08-15
+129	2013-09-15
+130	2013-10-15
+131	2013-11-15
+132	2013-12-15
+133	2014-01-15
+134	2014-02-15
+135	2014-03-15
+136	2014-04-15
+137	2014-05-15
+138	2014-06-15
+139	2014-07-15
+140	2014-08-15
+141	2014-09-15
+142	2014-10-15
+143	2014-11-15
+144	2014-12-15
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/version.tabular	Sun Jun 06 08:49:43 2021 +0000
@@ -0,0 +1,1 @@
+Galaxy xarray version 0.18.2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xarray_mapplot.py	Sun Jun 06 08:49:43 2021 +0000
@@ -0,0 +1,457 @@
+#!/usr/bin/env python3
+#
+#
+# usage: xarray_mapplot.py [-h] [--proj PROJ]
+#                               [--cmap CMAP]
+#                               [--output OUTPUT]
+#                               [--time TIMES]
+#                               [--nrow NROW]
+#                               [--ncol NCOL]
+#                               [--title title]
+#                               [--latitude LATITUDE]
+#                               [--longitude LONGITUDE]
+#                               [--land ALPHA-LAND]
+#                               [--ocean ALPHA-OCEAN]
+#                               [--coastline ALPHA-COASTLINE]
+#                               [--borders ALPHA-BORDERS]
+#                               [--xlim "x1,x2"]
+#                               [--ylim "y1,y2"]
+#                               [--range "valmin,valmax"]
+#                               [--threshold VAL]
+#                               [--label label-colorbar]
+#                               [--shift]
+#                               [-v]
+#                               input varname
+#
+# positional arguments:
+#  input            input filename with geographical coordinates (netCDF
+#                   format)
+#  varname          Specify which variable to plot (case sensitive)
+#
+# optional arguments:
+#  -h, --help       show this help message and exit
+#  --proj PROJ      Specify the projection on which we draw
+#  --cmap CMAP      Specify which colormap to use for plotting
+#  --output OUTPUT  output filename to store resulting image (png format)
+#  --time TIMES     time index from the file for multiple plots ("0 1 2 3")
+#  --title          plot or subplot title
+#  --latitude        variable name for latitude
+#  --longitude       variable name for longitude
+#  --land            add land on plot with alpha value [0-1]
+#  --ocean           add oceans on plot with alpha value [0-1]
+#  --coastline       add coastline with alpha value [0-1]
+#  --borders         add country borders with alpha value [0-1]
+#  --xlim            limited geographical area longitudes "x1,x2"
+#  --ylim            limited geographical area latitudes "y1,y2"
+#  --range           "valmin,valmax" for plotting
+#  --threshold       do not plot values below threshold
+#  --label           set a label for colormap
+#  --shift           shift longitudes if specified
+#  -v, --verbose    switch on verbose mode
+#
+
+import argparse
+import ast
+import warnings
+from pathlib import Path
+
+import cartopy.crs as ccrs
+import cartopy.feature as feature
+
+from cmcrameri import cm
+
+import matplotlib as mpl
+mpl.use('Agg')
+from matplotlib import pyplot  # noqa: I202,E402
+
+import xarray as xr  # noqa: E402
+
+
+class MapPlotXr ():
+    def __init__(self, input, proj, varname, cmap, output, verbose=False,
+                 time=[], title="", latitude="latitude",
+                 longitude="longitude", land=0, ocean=0,
+                 coastline=0, borders=0, xlim=[], ylim=[],
+                 threshold="", label="", shift=False,
+                 range_values=[]):
+        self.input = input
+        print("PROJ", proj)
+        if proj != "" and proj is not None:
+            self.proj = proj.replace('X', ':')
+        else:
+            self.proj = proj
+        self.varname = varname
+        self.get_cmap(cmap)
+        self.time = time
+        self.latitude = latitude
+        self.longitude = longitude
+        self.land = land
+        self.ocean = ocean
+        self.coastline = coastline
+        self.borders = borders
+        self.xlim = xlim
+        self.ylim = ylim
+        self.range = range_values
+        self.threshold = threshold
+        self.shift = shift
+        self.xylim_supported = False
+        self.colorbar = True
+        self.title = title
+        if output is None:
+            self.output = Path(input).stem + '.png'
+        else:
+            self.output = output
+        self.verbose = verbose
+        self.dset = xr.open_dataset(self.input, use_cftime=True)
+
+        self.label = {}
+        if label != "" and label is not None:
+            self.label['label'] = label
+        if verbose:
+            print("input: ", self.input)
+            print("proj: ", self.proj)
+            print("varname: ", self.varname)
+            print("time: ", self.time)
+            print("minval, maxval: ", self.range)
+            print("title: ", self.title)
+            print("output: ", self.output)
+            print("label: ", self.label)
+            print("shift: ", self.shift)
+            print("ocean: ", self.ocean)
+            print("land: ", self.land)
+            print("coastline: ", self.coastline)
+            print("borders: ", self.borders)
+            print("latitude: ", self.latitude)
+            print("longitude: ", self.longitude)
+            print("xlim: ", self.xlim)
+            print("ylim: ", self.ylim)
+
+    def get_cmap(self, cmap):
+        if cmap[0:3] == 'cm.':
+            self.cmap = cm.__dict__[cmap[3:]]
+        else:
+            self.cmap = cmap
+
+    def projection(self):
+        if self.proj is None:
+            return ccrs.PlateCarree()
+
+        proj_dict = ast.literal_eval(self.proj)
+
+        user_proj = proj_dict.pop("proj")
+        if user_proj == 'PlateCarree':
+            self.xylim_supported = True
+            return ccrs.PlateCarree(**proj_dict)
+        elif user_proj == 'AlbersEqualArea':
+            return ccrs.AlbersEqualArea(**proj_dict)
+        elif user_proj == 'AzimuthalEquidistant':
+            return ccrs.AzimuthalEquidistant(**proj_dict)
+        elif user_proj == 'EquidistantConic':
+            return ccrs.EquidistantConic(**proj_dict)
+        elif user_proj == 'LambertConformal':
+            return ccrs.LambertConformal(**proj_dict)
+        elif user_proj == 'LambertCylindrical':
+            return ccrs.LambertCylindrical(**proj_dict)
+        elif user_proj == 'Mercator':
+            return ccrs.Mercator(**proj_dict)
+        elif user_proj == 'Miller':
+            return ccrs.Miller(**proj_dict)
+        elif user_proj == 'Mollweide':
+            return ccrs.Mollweide(**proj_dict)
+        elif user_proj == 'Orthographic':
+            return ccrs.Orthographic(**proj_dict)
+        elif user_proj == 'Robinson':
+            return ccrs.Robinson(**proj_dict)
+        elif user_proj == 'Sinusoidal':
+            return ccrs.Sinusoidal(**proj_dict)
+        elif user_proj == 'Stereographic':
+            return ccrs.Stereographic(**proj_dict)
+        elif user_proj == 'TransverseMercator':
+            return ccrs.TransverseMercator(**proj_dict)
+        elif user_proj == 'UTM':
+            return ccrs.UTM(**proj_dict)
+        elif user_proj == 'InterruptedGoodeHomolosine':
+            return ccrs.InterruptedGoodeHomolosine(**proj_dict)
+        elif user_proj == 'RotatedPole':
+            return ccrs.RotatedPole(**proj_dict)
+        elif user_proj == 'OSGB':
+            self.xylim_supported = False
+            return ccrs.OSGB(**proj_dict)
+        elif user_proj == 'EuroPP':
+            self.xylim_supported = False
+            return ccrs.EuroPP(**proj_dict)
+        elif user_proj == 'Geostationary':
+            return ccrs.Geostationary(**proj_dict)
+        elif user_proj == 'NearsidePerspective':
+            return ccrs.NearsidePerspective(**proj_dict)
+        elif user_proj == 'EckertI':
+            return ccrs.EckertI(**proj_dict)
+        elif user_proj == 'EckertII':
+            return ccrs.EckertII(**proj_dict)
+        elif user_proj == 'EckertIII':
+            return ccrs.EckertIII(**proj_dict)
+        elif user_proj == 'EckertIV':
+            return ccrs.EckertIV(**proj_dict)
+        elif user_proj == 'EckertV':
+            return ccrs.EckertV(**proj_dict)
+        elif user_proj == 'EckertVI':
+            return ccrs.EckertVI(**proj_dict)
+        elif user_proj == 'EqualEarth':
+            return ccrs.EqualEarth(**proj_dict)
+        elif user_proj == 'Gnomonic':
+            return ccrs.Gnomonic(**proj_dict)
+        elif user_proj == 'LambertAzimuthalEqualArea':
+            return ccrs.LambertAzimuthalEqualArea(**proj_dict)
+        elif user_proj == 'NorthPolarStereo':
+            return ccrs.NorthPolarStereo(**proj_dict)
+        elif user_proj == 'OSNI':
+            return ccrs.OSNI(**proj_dict)
+        elif user_proj == 'SouthPolarStereo':
+            return ccrs.SouthPolarStereo(**proj_dict)
+
+    def plot(self, ts=None):
+        if self.shift:
+            if self.longitude == 'longitude':
+                self.dset = self.dset.assign_coords(
+                                 longitude=(((
+                                        self.dset[self.longitude]
+                                        + 180) % 360) - 180))
+            elif self.longitude == 'lon':
+                self.dset = self.dset.assign_coords(
+                                 lon=(((self.dset[self.longitude]
+                                        + 180) % 360) - 180))
+
+        pyplot.figure(1, figsize=[20, 10])
+
+        # Set the projection to use for plotting
+        ax = pyplot.subplot(1, 1, 1, projection=self.projection())
+        if self.land:
+            ax.add_feature(feature.LAND, alpha=self.land)
+
+        if self.ocean:
+            ax.add_feature(feature.OCEAN, alpha=self.ocean)
+        if self.coastline:
+            ax.coastlines(resolution='10m', alpha=self.coastline)
+        if self.borders:
+            ax.add_feature(feature.BORDERS, linestyle=':', alpha=self.borders)
+
+        if self.xlim:
+            min_lon = min(self.xlim[0], self.xlim[1])
+            max_lon = max(self.xlim[0], self.xlim[1])
+        else:
+            min_lon = self.dset[self.longitude].min()
+            max_lon = self.dset[self.longitude].max()
+
+        if self.ylim:
+            min_lat = min(self.ylim[0], self.ylim[1])
+            max_lat = max(self.ylim[0], self.ylim[1])
+        else:
+            min_lat = self.dset[self.latitude].min()
+            max_lat = self.dset[self.latitude].max()
+
+        if self.xylim_supported:
+            pyplot.xlim(min_lon, max_lon)
+            pyplot.ylim(min_lat, max_lat)
+
+        # Fix extent
+        if self.threshold == "" or self.threshold is None:
+            threshold = self.dset[self.varname].min()
+        else:
+            threshold = float(self.threshold)
+
+        if self.range == []:
+            minval = self.dset[self.varname].min()
+            maxval = self.dset[self.varname].max()
+        else:
+            minval = self.range[0]
+            maxval = self.range[1]
+
+        if self.verbose:
+            print("minval: ", minval)
+            print("maxval: ", maxval)
+
+        # pass extent with vmin and vmax parameters
+        proj_t = ccrs.PlateCarree()
+        if ts is None:
+            self.dset.where(
+                 self.dset[self.varname] > threshold
+                 )[self.varname].plot(ax=ax,
+                                      vmin=minval,
+                                      vmax=maxval,
+                                      transform=proj_t,
+                                      cmap=self.cmap,
+                                      cbar_kwargs=self.label
+                                      )
+            if self.title != "" and self.title is not None:
+                pyplot.title(self.title)
+            pyplot.savefig(self.output)
+        else:
+            if self.colorbar:
+                self.dset.where(
+                     self.dset[self.varname] > threshold
+                     )[self.varname].isel(time=ts).plot(ax=ax,
+                                                        vmin=minval,
+                                                        vmax=maxval,
+                                                        transform=proj_t,
+                                                        cmap=self.cmap,
+                                                        cbar_kwargs=self.label
+                                                        )
+            else:
+                self.dset.where(
+                     self.dset[self.varname] > minval
+                     )[self.varname].isel(time=ts).plot(ax=ax,
+                                                        vmin=minval,
+                                                        vmax=maxval,
+                                                        transform=proj_t,
+                                                        cmap=self.cmap,
+                                                        add_colorbar=False)
+            if self.title != "" and self.title is not None:
+                pyplot.title(self.title + "(time = " + str(ts) + ')')
+            pyplot.savefig(self.output[:-4] + "_time" + str(ts) +
+                           self.output[-4:])  # assume png format
+
+
+if __name__ == '__main__':
+    warnings.filterwarnings("ignore")
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        'input',
+        help='input filename with geographical coordinates (netCDF format)'
+    )
+
+    parser.add_argument(
+        '--proj',
+        help='Specify the projection on which we draw'
+    )
+    parser.add_argument(
+        'varname',
+        help='Specify which variable to plot (case sensitive)'
+    )
+    parser.add_argument(
+        '--cmap',
+        help='Specify which colormap to use for plotting'
+    )
+    parser.add_argument(
+        '--output',
+        help='output filename to store resulting image (png format)'
+    )
+    parser.add_argument(
+        '--time',
+        help='list of times to plot for multiple plots'
+    )
+    parser.add_argument(
+        '--title',
+        help='plot title'
+    )
+    parser.add_argument(
+        '--latitude',
+        help='variable name for latitude'
+    )
+    parser.add_argument(
+        '--longitude',
+        help='variable name for longitude'
+    )
+    parser.add_argument(
+        '--land',
+        help='add land on plot with alpha value [0-1]'
+    )
+    parser.add_argument(
+        '--ocean',
+        help='add oceans on plot with alpha value [0-1]'
+    )
+    parser.add_argument(
+        '--coastline',
+        help='add coastline with alpha value [0-1]'
+    )
+    parser.add_argument(
+        '--borders',
+        help='add country borders with alpha value [0-1]'
+    )
+    parser.add_argument(
+        '--xlim',
+        help='limited geographical area longitudes "x1,x2"'
+    )
+    parser.add_argument(
+        '--ylim',
+        help='limited geographical area latitudes "y1,y2"'
+    )
+    parser.add_argument(
+        '--range',
+        help='min and max values for plotting "minval,maxval"'
+    )
+    parser.add_argument(
+        '--threshold',
+        help='do not plot values below threshold'
+    )
+    parser.add_argument(
+        '--label',
+        help='set a label for colorbar'
+    )
+    parser.add_argument(
+        '--shift',
+        help='shift longitudes if specified',
+        action="store_true"
+    )
+    parser.add_argument(
+        "-v", "--verbose",
+        help="switch on verbose mode",
+        action="store_true")
+    args = parser.parse_args()
+
+    if args.time is None:
+        time = []
+    else:
+        time = list(map(int, args.time.split(",")))
+    if args.xlim is None:
+        xlim = []
+    else:
+        xlim = list(map(float, args.xlim.split(",")))
+    if args.ylim is None:
+        ylim = []
+    else:
+        ylim = list(map(float, args.ylim.split(",")))
+    if args.range is None:
+        range_values = []
+    else:
+        range_values = list(map(float, args.range.split(",")))
+    if args.latitude is None:
+        latitude = "latitude"
+    else:
+        latitude = args.latitude
+    if args.longitude is None:
+        longitude = "longitude"
+    else:
+        longitude = args.longitude
+    if args.land is None:
+        land = 0
+    else:
+        land = float(args.land)
+    if args.ocean is None:
+        ocean = 0
+    else:
+        ocean = float(args.ocean)
+    if args.coastline is None:
+        coastline = 0
+    else:
+        coastline = float(args.coastline)
+    if args.borders is None:
+        borders = 0
+    else:
+        borders = float(args.borders)
+
+    dset = MapPlotXr(input=args.input, proj=args.proj, varname=args.varname,
+                     cmap=args.cmap, output=args.output, verbose=args.verbose,
+                     time=time, title=args.title,
+                     latitude=latitude, longitude=longitude, land=land,
+                     ocean=ocean, coastline=coastline, borders=borders,
+                     xlim=xlim, ylim=ylim, threshold=args.threshold,
+                     label=args.label, shift=args.shift,
+                     range_values=range_values)
+
+    if dset.time == []:
+        dset.plot()
+    else:
+        for t in dset.time:
+            dset.plot(t)
+            dset.shift = False   # only shift once
+            dset.colorbar = True
--- a/xarray_metadata_info.xml	Sat Oct 31 11:00:53 2020 +0000
+++ b/xarray_metadata_info.xml	Sun Jun 06 08:49:43 2021 +0000
@@ -1,11 +1,15 @@
-<tool id="xarray_metadata_info" name="NetCDF xarray Metadata Info" version="0.15.1">
+<tool id="xarray_metadata_info" name="NetCDF xarray Metadata Info" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@">
     <description>summarize content of a Netcdf file</description>
+    <macros>
+        <import>macros.xml</import>
+    </macros>
+    <expand macro="edam_ontology"/>
     <requirements>
         <requirement type="package" version="3">python</requirement>
-        <requirement type="package" version="1.5.3">netcdf4</requirement>
-        <requirement type="package" version="0.15.1">xarray</requirement>
-        <requirement type="package" version="0.7.0">geopandas</requirement>
-        <requirement type="package" version="1.7.0">shapely</requirement>
+        <requirement type="package" version="1.5.6">netcdf4</requirement>
+        <requirement type="package" version="@TOOL_VERSION@">xarray</requirement>
+        <requirement type="package" version="0.9.0">geopandas</requirement>
+        <requirement type="package" version="1.7.1">shapely</requirement>
     </requirements>
     <command detect_errors="exit_code"><![CDATA[
         python3 '$__tool_directory__/xarray_tool.py' '$input' --info '$info' --summary '$output'
@@ -43,10 +47,6 @@
              </output>
         </test>
     </tests>
-    <edam_topics>
-       <edam_topic>topic_0610</edam_topic>
-       <edam_topic>topic_3050</edam_topic>
-    </edam_topics>
     <help><![CDATA[
 **What it does**
 
@@ -82,5 +82,5 @@
 
 Run this tool before considering using Netcdf Read.
     ]]></help>
-
+    <expand macro="citations"/>
 </tool>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xarray_netcdf2netcdf.py	Sun Jun 06 08:49:43 2021 +0000
@@ -0,0 +1,133 @@
+#!/usr/bin/env python3
+#
+#  Apply operations on selected variables
+# - scale
+# one can also select the range of time (for timeseries)
+# to apply these operations over the range only
+# when a range of time is selected and when scaling, one
+# can choose to save the entire timeseries or
+# the selected range only.
+# when scaling, one can add additional filters on dimensions
+# (typically used to filter over latitudes and longitudes)
+
+
+import argparse
+import warnings
+
+import xarray as xr  # noqa: E402
+
+
+class netCDF2netCDF ():
+    def __init__(self, infile, varname, scale="",
+                 output="output.netcdf",
+                 write_all=False,
+                 filter_list="",
+                 verbose=False):
+        self.infile = infile
+        self.verbose = verbose
+        self.varname = varname
+        self.write_all = write_all
+        self.filter = filter_list
+        self.selection = {}
+        if scale == "" or scale is None:
+            self.scale = 1
+        else:
+            self.scale = float(scale)
+        if output is None:
+            self.output = "output.netcdf"
+        else:
+            self.output = output
+        # initialization
+        self.dset = None
+        self.subset = None
+        if self.verbose:
+            print("infile: ", self.infile)
+            print("varname: ", self.varname)
+            print("filter_list: ", self.filter)
+            print("scale: ", self.scale)
+            print("write_all: ", self.write_all)
+            print("output: ", self.output)
+
+    def dimension_selection(self, single_filter):
+        split_filter = single_filter.split('#')
+        dimension_varname = split_filter[0]
+        op = split_filter[1]
+        ll = int(split_filter[2])
+        if (op == 'sl'):
+            rl = int(split_filter[3])
+            self.selection[dimension_varname] = slice(ll, rl)
+        elif (op == 'to'):
+            self.selection[dimension_varname] = slice(None, ll)
+        elif (op == 'from'):
+            self.selection[dimension_varname] = slice(ll, None)
+        elif (op == 'is'):
+            self.selection[dimension_varname] = ll
+
+    def filter_selection(self):
+        for single_filter in self.filter:
+            self.dimension_selection(single_filter)
+        if self.write_all:
+            self.ds[self.varname] = \
+                self.ds[self.varname].isel(self.selection)*self.scale
+        else:
+            self.dset = \
+                self.ds[self.varname].isel(self.selection)*self.scale
+
+    def compute(self):
+        if self.dset is None:
+            self.ds = xr.open_dataset(self.infile)
+            if self.filter:
+                self.filter_selection()
+                if self.verbose:
+                    print(self.selection)
+            elif self.write_all is not None:
+                self.dset = self.ds[self.varname]
+
+    def save(self):
+        if self.write_all:
+            self.ds.to_netcdf(self.output)
+        else:
+            self.dset.to_netcdf(self.output)
+
+
+if __name__ == '__main__':
+    warnings.filterwarnings("ignore")
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        'input',
+        help='input filename in netCDF format'
+    )
+    parser.add_argument(
+        'varname',
+        help='Specify which variable to plot (case sensitive)'
+    )
+    parser.add_argument(
+        '--filter',
+        nargs="*",
+        help='Filter list variable#operator#value_s#value_e'
+    )
+    parser.add_argument(
+        '--output',
+        help='Output filename to store the resulting netCDF file'
+    )
+    parser.add_argument(
+        '--scale',
+        help='scale factor to apply to selection (float)'
+    )
+    parser.add_argument(
+        "--write_all",
+        help="write all data to netCDF",
+        action="store_true")
+    parser.add_argument(
+        "-v", "--verbose",
+        help="switch on verbose mode",
+        action="store_true")
+    args = parser.parse_args()
+
+    dset = netCDF2netCDF(infile=args.input, varname=args.varname,
+                         scale=args.scale, output=args.output,
+                         filter_list=args.filter,
+                         write_all=args.write_all,
+                         verbose=args.verbose)
+    dset.compute()
+    dset.save()
--- a/xarray_tool.py	Sat Oct 31 11:00:53 2020 +0000
+++ b/xarray_tool.py	Sun Jun 06 08:49:43 2021 +0000
@@ -4,6 +4,7 @@
 
 import argparse
 import csv
+import os
 import warnings
 
 import geopandas as gdp
@@ -21,8 +22,8 @@
                  select="", outfile="", outputdir="", latname="",
                  latvalN="", latvalS="", lonname="", lonvalE="",
                  lonvalW="", filter_list="", coords="", time="",
-                 verbose=False
-                 ):
+                 verbose=False, no_missing=False, coords_info=None,
+                 tolerance=None):
         self.infile = infile
         self.outfile_info = outfile_info
         self.outfile_summary = outfile_summary
@@ -30,6 +31,10 @@
         self.outfile = outfile
         self.outputdir = outputdir
         self.latname = latname
+        if tolerance != "" and tolerance is not None:
+            self.tolerance = float(tolerance)
+        else:
+            self.tolerance = -1
         if latvalN != "" and latvalN is not None:
             self.latvalN = float(latvalN)
         else:
@@ -51,9 +56,11 @@
         self.time = time
         self.coords = coords
         self.verbose = verbose
+        self.no_missing = no_missing
         # initialization
         self.dset = None
         self.gset = None
+        self.coords_info = coords_info
         if self.verbose:
             print("infile: ", self.infile)
             print("outfile_info: ", self.outfile_info)
@@ -71,6 +78,7 @@
             print("filter: ", self.filter)
             print("time: ", self.time)
             print("coords: ", self.coords)
+            print("coords_info: ", self.coords_info)
 
     def info(self):
         f = open(self.outfile_info, 'w')
@@ -113,7 +121,9 @@
         if filter_varname == self.select:
             # filter on values of the selected variable
             if op == 'bi':
-                self.dset = self.dset.where((self.dset <= rl) & (self.dset >= ll))
+                self.dset = self.dset.where(
+                     (self.dset <= rl) & (self.dset >= ll)
+                     )
             elif op == 'le':
                 self.dset = self.dset.where(self.dset <= ll)
             elif op == 'ge':
@@ -141,9 +151,21 @@
                 self.filter_selection()
 
         self.area_selection()
-        # convert to dataframe
-        self.gset = self.gset.to_dataframe().dropna(how='all').reset_index()
-        self.gset.to_csv(self.outfile, header=True, sep='\t')
+        if self.gset.count() > 1:
+            # convert to dataframe if several rows and cols
+            self.gset = self.gset.to_dataframe().dropna(how='all'). \
+                        reset_index()
+            self.gset.to_csv(self.outfile, header=True, sep='\t')
+        else:
+            data = {
+                self.latname: [self.gset[self.latname].values],
+                self.lonname: [self.gset[self.lonname].values],
+                self.select: [self.gset.values]
+            }
+
+            df = pd.DataFrame(data, columns=[self.latname, self.lonname,
+                                             self.select])
+            df.to_csv(self.outfile, header=True, sep='\t')
 
     def datetime_selection(self):
         split_filter = self.time.split('#')
@@ -165,6 +187,7 @@
             self.rowfilter(single_filter)
 
     def area_selection(self):
+
         if self.latvalS != "" and self.lonvalW != "":
             # Select geographical area
             self.gset = self.dset.sel({self.latname:
@@ -173,10 +196,21 @@
                                        slice(self.lonvalW, self.lonvalE)})
         elif self.latvalN != "" and self.lonvalE != "":
             # select nearest location
-            self.nearest_location()  # find nearest location without NaN values
-            self.gset = self.dset.sel({self.latname: self.nearest_latvalN,
-                                       self.lonname: self.nearest_lonvalE},
-                                      method='nearest')
+            if self.no_missing:
+                self.nearest_latvalN = self.latvalN
+                self.nearest_lonvalE = self.lonvalE
+            else:
+                # find nearest location without NaN values
+                self.nearest_location()
+            if self.tolerance > 0:
+                self.gset = self.dset.sel({self.latname: self.nearest_latvalN,
+                                           self.lonname: self.nearest_lonvalE},
+                                          method='nearest',
+                                          tolerance=self.tolerance)
+            else:
+                self.gset = self.dset.sel({self.latname: self.nearest_latvalN,
+                                           self.lonname: self.nearest_lonvalE},
+                                          method='nearest')
         else:
             self.gset = self.dset
 
@@ -206,9 +240,21 @@
         for row in fcoords.itertuples():
             self.latvalN = row[0]
             self.lonvalE = row[1]
-            self.outfile = (self.outputdir + '/' + self.select + '_' + str(row.Index) + '.tabular')
+            self.outfile = (os.path.join(self.outputdir,
+                            self.select + '_' +
+                            str(row.Index) + '.tabular'))
             self.selection()
 
+    def get_coords_info(self):
+        ds = xr.open_dataset(self.infile)
+        for c in ds.coords:
+            filename = os.path.join(self.coords_info,
+                                    c.strip() +
+                                    '.tabular')
+            pd = ds.coords[c].to_pandas()
+            pd.index = range(len(pd))
+            pd.to_csv(filename, header=False, sep='\t')
+
 
 if __name__ == '__main__':
     warnings.filterwarnings("ignore")
@@ -255,11 +301,21 @@
         help='West longitude value'
     )
     parser.add_argument(
+        '--tolerance',
+        help='Maximum distance between original and selected value for '
+             ' inexact matches e.g. abs(index[indexer] - target) <= tolerance'
+    )
+    parser.add_argument(
         '--coords',
         help='Input file containing Latitude and Longitude'
              'for geographical selection'
     )
     parser.add_argument(
+        '--coords_info',
+        help='output-folder where for each coordinate, coordinate values '
+             ' are being printed in the corresponding outputfile'
+    )
+    parser.add_argument(
         '--filter',
         nargs="*",
         help='Filter list variable#operator#value_s#value_e'
@@ -283,13 +339,20 @@
         help="switch on verbose mode",
         action="store_true"
     )
+    parser.add_argument(
+        "--no_missing",
+        help="""Do not take into account possible null/missing values
+                (only valid for single location)""",
+        action="store_true"
+    )
     args = parser.parse_args()
 
     p = XarrayTool(args.infile, args.info, args.summary, args.select,
                    args.outfile, args.outputdir, args.latname,
                    args.latvalN, args.latvalS, args.lonname,
                    args.lonvalE, args.lonvalW, args.filter,
-                   args.coords, args.time, args.verbose)
+                   args.coords, args.time, args.verbose,
+                   args.no_missing, args.coords_info, args.tolerance)
     if args.info:
         p.info()
     if args.summary:
@@ -298,3 +361,5 @@
         p.selection_from_coords()
     elif args.select:
         p.selection()
+    elif args.coords_info:
+        p.get_coords_info()