diff --git a/LICENSE b/LICENSE
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d75091f8e781453b4ab5c8875336bf6858858e8b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -0,0 +1,192 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2021 Barcelona Supercomputing Center
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
diff --git a/bin/map_main.py b/bin/map_main.py
index a4c204ae6ea42ed0bffcf91b0c2433128606f5c9..477d92f162438b9555927bd766f63ffc9d6e7186 100755
--- a/bin/map_main.py
+++ b/bin/map_main.py
@@ -1,22 +1,3 @@
-#!/usr/bin/env python
-
-# Copyright 2016 Earth Sciences Department, BSC-CNS
-
-# This file is part of MapGenerator.
-
-# MapGenerator is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# MapGenerator 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 MapGenerator. If not, see .
-
"""
Main module for MapGenerator. Only contains an interface class to all functionality implemented on MapGenerator.
"""
diff --git a/mapgenerator/mg_exceptions.py b/mapgenerator/mg_exceptions.py
index 1d51c94fe55bcd9d478a9fa6f6ebdf3d9aeb7210..b8e518ab246ef42e5eb37d47152421a89bac0333 100644
--- a/mapgenerator/mg_exceptions.py
+++ b/mapgenerator/mg_exceptions.py
@@ -1,21 +1,4 @@
-#!/usr/bin/env python
-# Copyright 2016 Earth Sciences Department, BSC-CNS
-
-# This file is part of MapGenerator.
-
-# MapGenerator is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# MapGenerator 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 MapGenerator. If not, see .
class ArgumentParserException(Exception):
diff --git a/mapgenerator/plotting/definitions.py b/mapgenerator/plotting/definitions.py
index 8607b5b74b4f9c43520ece80fd6b8f4293f38a9f..97783d0b7834b152f96fc373863efa58732763f1 100644
--- a/mapgenerator/plotting/definitions.py
+++ b/mapgenerator/plotting/definitions.py
@@ -16,6 +16,8 @@ from datetime import timedelta
import os
import os.path
import copy
+from cartopy.img_transform import mesh_projection, regrid
+from cartopy.crs import PlateCarree
import logging
@@ -58,37 +60,30 @@ def do_interpolation(data, lon, lat):
""" Takes a not regular grid (curvilinear, whatever kind) and interpolate
to regular one derived from the first. Very demanding operation, try to
avoid """
- # lon as second dimension
- # lat as first dimension
LOG.info("Irregular grid, performing interpolation ...")
- lat_s = lat.shape[0]
- lon_s = lon.shape[1]
- reglon = np.linspace(lon.min(), lon.max(), lon_s)
- reglat = np.linspace(lat.min(), lat.max(), lat_s)
- LOG.info("LAT: %s, LON: %s, DATA: %s", reglon.shape, reglat.shape,
- data.shape)
- regx, regy = np.meshgrid(reglon, reglat)
- result = np.empty(data.shape)*np.nan
- if ma.is_masked(data):
- data = data.filled(np.nan)
-
+ projection = PlateCarree()
+ new_lon, new_lat, _ = mesh_projection(
+ projection, data.shape[-1], data.shape[-2],
+ # x_extents=(lon.min(), lon.max()),
+ # y_extents=(lat.min(), lat.max())
+ )
+
+ def _interpolate(to_regrid):
+ return regrid(to_regrid, lon, lat, projection, projection, new_lon, new_lat)
+
+ result = np.empty_like(data)
+ result.fill(np.nan)
# assuming that lat and lon are the latest dimensions
if len(data.shape) == 2:
- result = griddata((lon.ravel(), lat.ravel()), data.ravel(), (regx,
- regy))
+ result = _interpolate(data)
elif len(data.shape) == 3:
for i in range(data.shape[0]):
- tmp = griddata((lon.ravel(), lat.ravel()), data[i].ravel(), (regx,
- regy))
- result[i] = tmp.reshape(result[i].shape)
+ result[i, :, :] = _interpolate(data[i])
elif len(data.shape) == 4:
for i in range(data.shape[0]):
for j in range(data.shape[1]):
- tmp = griddata((lon.ravel(), lat.ravel()), data[i, j].ravel(),
- (regx, regy))
- result[i, j, :, :] = tmp.reshape(result[i, j, :, :].shape)
- # elif len(data.shape) == 5:
- return np.ma.masked_where(np.isnan(result), result), regx, regy
+ result[i, j, :, :] = _interpolate(data[i, j])
+ return result, new_lon[0], new_lat[:, 0]
def extract_coords(self, var, coord='lons'):
@@ -127,7 +122,7 @@ def parse_parameters_list(plist):
if len(plist) == 1:
plist = plist[0]
else:
- return list(plist)
+ return [float(val) for val in plist]
if str(plist).find('-') > 0:
tmp = plist.strip('[]')
try:
@@ -715,6 +710,7 @@ class MapGenerator(object):
self.orig_projection_kwargs = kwargs.get('orig_projection_kwargs', dict())
self.projection = kwargs.get('projection', 'PlateCarree')
self.projection_kwargs = kwargs.get('projection_kwargs', dict())
+ self.extent = kwargs.get('extent', 'auto')
self.subsetting = kwargs.get('subsetting', True)
self.dimension = kwargs.get('dimension', None)
self.continents = kwargs.get('continents', None)
@@ -740,9 +736,9 @@ class MapGenerator(object):
if cube.attributes.get('plot_name', None):
show_name = cube.attributes['plot_name']
elif cube.long_name and len(cube.long_name) < 45:
- show_name = cube.long_name
+ show_name = f"{cube.long_name} ({cube.var_name})"
elif cube.standard_name and len(cube.standard_name) < 45:
- show_name = cube.standard_name
+ show_name = f"{cube.standard_name} ({cube.var_name})"
else:
show_name = cube.var_name
return f"{show_name} ({cube.units})"
@@ -770,6 +766,7 @@ class MapCross(MapGenerator):
self.contours_int = kwargs.get('contours_int', 1)
self.smooth = kwargs.get('smooth', False)
self.colorbar = kwargs.get('colorbar', True)
+ self.colorbar_location = kwargs.get('colorbar_location', 'right')
self.formats = kwargs.get('formats', None)
self.noruntime = kwargs.get('noruntime', False)
self.timesteps = kwargs.get('timesteps', '0')
diff --git a/mapgenerator/plotting/plotmap.py b/mapgenerator/plotting/plotmap.py
index 5dc08363a82506662d32a455c3341eb4e48c3753..037df997aa2d772a5c2bd8e8cd0cfba9fadd407c 100644
--- a/mapgenerator/plotting/plotmap.py
+++ b/mapgenerator/plotting/plotmap.py
@@ -6,12 +6,14 @@
import matplotlib as mpl
import matplotlib.pyplot as plt
+import matplotlib.ticker as mticker
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import cartopy.io.shapereader as shpreader
+
+from cartopy.util import add_cyclic_point
from matplotlib.cbook import delete_masked_points
from matplotlib.path import Path
-# from matplotlib.image import imread
import numpy as np
from datetime import datetime
import os.path
@@ -33,10 +35,6 @@ from .tools import set_title
from .tools import set_resolution
from .tools import gen_kml
from .tools import gen_anim
-# try:
-# from urllib2 import urlopen
-# except ImportError:
-# from urllib.request import urlopen
import copy
from glob import glob
import logging
@@ -47,14 +45,12 @@ LOG = logging.getLogger(__name__)
class PlotCross(object):
""" Main class for plotting cross sections """
-
def __init__(self, loglevel='WARNING', **kwargs):
pass
class PlotMap(MapCross, MapDrawOptions):
""" Main class for plotting maps """
-
def __init__(self, loglevel='WARNING', **kwargs):
""" Initialize class with attributes """
MapCross.__init__(self, loglevel, **kwargs)
@@ -75,22 +71,17 @@ class PlotMap(MapCross, MapDrawOptions):
self.mgplot = None
self.stamen_terrain = None
self.zoom_level = None
- # self.map = None #Map
self.first_image = False # Is is the first image of the batch?
self.map_name = None # name of the figure to map animation colors
-# self.drawopts = {'coastlines':
-# {'linewidth': 0.5, 'color': 'grey', },
-# 'countries':
-# {'linewidth': 0.3, 'color': 'grey', },
-# }
+ self.draw_labels = None
def __setattr__(self, key, value):
LOG.debug("SETATTR: %s - %s", key, value)
super(PlotMap, self).__setattr__(key, parse_parameter(key, value))
def _build_orig_projection(self):
- self._orig_crs = getattr(ccrs, self.orig_projection)(
- **self.orig_projection_kwargs)
+ self._orig_crs = getattr(
+ ccrs, self.orig_projection)(**self.orig_projection_kwargs)
def _build_projection(self):
if self.background:
@@ -98,36 +89,56 @@ class PlotMap(MapCross, MapDrawOptions):
self.stamen_terrain = cimgt.Stamen('terrain-background')
self._crs = self.stamen_terrain.crs
self.projection = 'Stamen'
+ elif self.projection.lower().startswith('epsg'):
+ self._crs = ccrs.epsg(self.projection[4:])
else:
- self._crs = getattr(ccrs, self.projection)(
- **self.projection_kwargs)
+ self._crs = getattr(ccrs,
+ self.projection)(**self.projection_kwargs)
+
+ def set_resolution(self):
+ """ 110m, 50m, 10m """
+ minlat, maxlat = self.lat[0], self.lat[-1]
+ minlon, maxlon = self.lon[0], self.lon[-1]
+ lats = maxlat + abs(minlat)
+ lons = maxlon + abs(minlon)
+ if lats > 100 and lons > 200:
+ self.resolution = '110m'
+ elif lats > 45 and lons > 75:
+ self.resolution = '50m'
+ elif lats <= 45 and lons <= 75:
+ self.resolution = '10m'
+ else:
+ self._crs = getattr(ccrs,
+ self.projection)(**self.projection_kwargs)
def set_color_map(self):
""" Create color map """
extend_opts = {
'max': {
- 'cmap_arg': lambda colors: colors[:-1],
+ 'cmap_arg':
+ lambda colors: colors[:-1],
'cmap_ext': ('set_over'),
'ext_arg': (lambda colors: colors[-1]),
- 'norm_arg': (lambda bounds: bounds+[np.inf],
- lambda cmap: cmap.N+1)
+ 'norm_arg':
+ (lambda bounds: bounds + [np.inf], lambda cmap: cmap.N + 1)
},
'min': {
- 'cmap_arg': lambda colors: colors[1:],
+ 'cmap_arg':
+ lambda colors: colors[1:],
'cmap_ext': ('set_under'),
'ext_arg': (lambda colors: colors[0]),
- 'norm_arg': (lambda bounds: [-np.inf]+bounds,
- lambda cmap: cmap.N+1)
+ 'norm_arg':
+ (lambda bounds: [-np.inf] + bounds, lambda cmap: cmap.N + 1)
},
'both': {
- 'cmap_arg': self.colors[1:-1],
+ 'cmap_arg':
+ self.colors[1:-1],
'cmap_ext': ('set_over', 'set_under'),
- 'ext_arg': (lambda colors: colors[-1],
- lambda colors: colors[0]),
- 'norm_arg': (lambda bounds: [-np.inf]+bounds+[np.inf],
+ 'ext_arg':
+ (lambda colors: colors[-1], lambda colors: colors[0]),
+ 'norm_arg': (lambda bounds: [-np.inf] + bounds + [np.inf],
lambda cmap: cmap.N + 2)
-
}
}
@@ -139,8 +150,8 @@ class PlotMap(MapCross, MapDrawOptions):
if len(self.bounds) < len(self.colors):
self.colors = self.colors[:len(self.bounds)]
elif self.extend == 'both':
- if len(self.bounds)+1 < len(self.colors):
- self.colors = self.colors[:len(self.bounds)+1]
+ if len(self.bounds) + 1 < len(self.colors):
+ self.colors = self.colors[:len(self.bounds) + 1]
if self.extend in extend_opts:
self.cmap = mpl.colors.ListedColormap(
@@ -168,16 +179,16 @@ class PlotMap(MapCross, MapDrawOptions):
if self.extend in ('min', 'both'):
self.cmap.set_under(color=(0, 0, 0, 0))
else:
- self.cmap.colors = [(0, 0, 0, 0), ] + [c for c in
- self.cmap.colors[1:]]
+ self.cmap.colors = [
+ (0, 0, 0, 0),
+ ] + [c for c in self.cmap.colors[1:]]
# normalize colormap
if self.bounds and self.smooth and not custom_cmap:
if self.extend in ('min', 'max', 'both'):
self.norm = mpl.colors.BoundaryNorm(
extend_opts[self.extend]['norm_arg'][0](self.bounds),
- extend_opts[self.extend]['norm_arg'][1](self.cmap)
- )
+ extend_opts[self.extend]['norm_arg'][1](self.cmap))
else:
self.norm = mpl.colors.BoundaryNorm(self.bounds, self.cmap.N)
elif self.bounds:
@@ -185,10 +196,6 @@ class PlotMap(MapCross, MapDrawOptions):
def set_color_bar(self, mco, location='right', drawedges=False, cax=None):
""" Create color bar """
-# xs = self.xsize
-# nap = .8-((1-xs)*0.4)
-# a = plt.axes([nap, 0, .14, 1])#, frameon=False)
-# plt.axis('off')
mpl.rcParams['axes.linewidth'] = 0.1
mpl.rcParams['axes.formatter.useoffset'] = False
if self.ticks:
@@ -200,13 +207,21 @@ class PlotMap(MapCross, MapDrawOptions):
self.ticks = mco.levels
LOG.debug("***** Formats: %s *****", self.formats)
- cax, kwargs = mpl.colorbar.make_axes(self.mgaxis, location=location,
- pad=0.02, shrink=0.8)
- cbar = self.mgplot.colorbar(mco, cax=cax, ax=self.mgaxis,
- ticks=self.ticks, format=self.formats,
- pad=.06, extend=self.extend,
- drawedges=drawedges, **kwargs)
-
+ pad = {'bottom': 0.05, 'right': 0.02}
+ pad = pad.get(location, 0.02)
+ cax, kwargs = mpl.colorbar.make_axes(self.mgaxis,
+ location=location,
+ pad=pad,
+ shrink=0.9)
+ cbar = self.mgplot.colorbar(mco,
+ cax=cax,
+ ax=self.mgaxis,
+ ticks=self.ticks,
+ format=self.formats,
+ pad=.06,
+ extend=self.extend,
+ drawedges=drawedges,
+ **kwargs)
cbar.ax.tick_params(labelsize=float(self.coordsopts[1]))
for lin in cbar.ax.yaxis.get_ticklines():
lin.set_visible(False)
@@ -225,22 +240,27 @@ class PlotMap(MapCross, MapDrawOptions):
else:
ticks = mco.levels
- fac = span/float(len(ticks) - 1)
+ fac = span / float(len(ticks) - 1)
for i in arrows:
for j in range(0, len(ticks) - 1):
- if i >= ticks[j] and i <= ticks[j+1]:
- if i == ticks[j+1]:
- idx = j+1
+ if i >= ticks[j] and i <= ticks[j + 1]:
+ if i == ticks[j + 1]:
+ idx = j + 1
add = 0
else:
idx = j
- add = (float(i - ticks[j])/float(ticks[j+1] -
- ticks[j]))*fac
- pos = fac*idx + lower
- plt.arrow(0.88, pos + add, 0.10, 0,
- length_includes_head=True, head_length=0.10,
- head_width=0.025, fill=True, color='k')
- # plt.colorbar(drawedges=drawedges, cax=cax, ticks=self.bounds)
+ add = (float(i - ticks[j]) /
+ float(ticks[j + 1] - ticks[j])) * fac
+ pos = fac * idx + lower
+ plt.arrow(0.88,
+ pos + add,
+ 0.10,
+ 0,
+ length_includes_head=True,
+ head_length=0.10,
+ head_width=0.025,
+ fill=True,
+ color='k')
def init_map(self, grid):
""" Initialize a map. Initialization should be performed only once
@@ -248,25 +268,16 @@ class PlotMap(MapCross, MapDrawOptions):
glon, glat = grid
# print("***",self.lon, self.lat,"***")
if not self.lat: # or len(self.lat) not in (2,3):
- self.lat = "%s-%s" % (str(round(glat.min(), 1)).replace('-', 'm'),
- str(round(glat.max(), 1)).replace('-', 'm'))
+ self.lat = "%s-%s" % (str(round(glat.min(), 1)).replace(
+ '-', 'm'), str(round(glat.max(), 1)).replace('-', 'm'))
if not self.lon: # or len(self.lon) not in (2,3):
- self.lon = "%s-%s" % (str(round(glon.min(), 1)).replace('-', 'm'),
- str(round(glon.max(), 1)).replace('-', 'm'))
+ self.lon = "%s-%s" % (str(round(glon.min(), 1)).replace(
+ '-', 'm'), str(round(glon.max(), 1)).replace('-', 'm'))
self._build_orig_projection()
self._build_projection()
- # print(self.lon, self.lat)
-# # Fix the printout of tick values to avoid .0 decimals in integers
-# strs = []
-# if self.bounds:
-# for b in self.bounds:
-# if (b == int(b)):
-# strs.append("%d" % b)
-# else:
-# strs.append(str(b))
-#
+ #
# Set the colormap
self.set_color_map()
if not self.resolution:
@@ -277,8 +288,13 @@ class PlotMap(MapCross, MapDrawOptions):
self.first_image = True
- def gen_image_map(self, fig_name, grid, data, img_title,
- cur_scatter_data=None, **kwargs):
+ def gen_image_map(self,
+ fig_name,
+ grid,
+ data,
+ img_title,
+ cur_scatter_data=None,
+ **kwargs):
""" Generate image map """
# overwrite option
@@ -291,59 +307,19 @@ class PlotMap(MapCross, MapDrawOptions):
map_data = data.map_data
# FIXME
scatter_data = data.scatter_data or cur_scatter_data
- # if self.subplot is None:
- # self.mgplot.clear()
-
-# params = {
-# 'font.size': 14,
-# 'text.fontsize': 28,
-# 'axes.titlesize': 11,
-# 'savefig.dpi': self.dpi
-# }
-#
-# mpl.rcParams.update(params)
# Draw filled contour
- self.mgaxis.set_aspect(self.xsize/self.ysize)
-
+ self.mgaxis.set_aspect(self.xsize / self.ysize)
+ self._set_extent()
if self.projection.lower().endswith('polarstereo'):
- self.mgaxis.set_extent([-180, 179.9999999999999,
- self.lat[0], self.lat[-1]],
- self._orig_crs)
# Compute a circle in axes coordinates, which we can use as a
# boundary for the map. We can pan/zoom as much as we like - the
# boundary will be permanently circular.
- theta = np.linspace(0, 2*np.pi, 100)
+ theta = np.linspace(0, 2 * np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = Path(verts * radius + center)
self.mgaxis.set_boundary(circle, transform=self.mgaxis.transAxes)
- else:
- self.mgaxis.set_extent([self.lon[0], self.lon[-1],
- self.lat[0], self.lat[-1]],
- self._orig_crs)
-
-# if self.subplot:
-# self.map = Basemap(
-# ax=self.mgaxis,
-# projection=self.projection, resolution=self.resolution,
-# llcrnrlon=self.lon[0], llcrnrlat=self.lat[0],
-# urcrnrlon=self.lon[-1], urcrnrlat=self.lat[-1],
-# lon_0=lon_0, lat_0=lat_0,
-# fix_aspect=self.keep_aspect,
-# area_thresh=self.area_thresh,
-# boundinglat=self.boundinglat,
-# )
-# else:
-# self.map = Basemap(
-# projection=self.projection, resolution=self.resolution,
-# llcrnrlon=self.lon[0], llcrnrlat=self.lat[0],
-# urcrnrlon=self.lon[-1], urcrnrlat=self.lat[-1],
-# lon_0=lon_0, lat_0=lat_0,
-# fix_aspect=self.keep_aspect,
-# area_thresh=self.area_thresh,
-# boundinglat=self.boundinglat,
-# )
glon, glat = grid
LOG.debug("0. GLON: %s, GLAT: %s", str(glon.shape), str(glat.shape))
@@ -354,74 +330,36 @@ class PlotMap(MapCross, MapDrawOptions):
LOG.debug("1. GLON: %s, GLAT: %s", str(glon.shape), str(glat.shape))
# if curvilinear grid do interpolation, return already gridded coords
- if not is_grid_regular(glon, glat):
+ if is_grid_regular(glon, glat):
+ if len(glon.shape)==2:
+ glon = glon[0]
+ glat = glat[:, 0]
+ else:
map_data[0], glon, glat = do_interpolation(map_data[0], glon, glat)
- LOG.info("2. GLON: %s, GLAT: %s", str(glon.shape), str(glat.shape))
+ try:
+ map_data[0], glon = add_cyclic_point(map_data[0], coord=glon)
+ except ValueError:
+ LOG.debug('Can not add cyclic point.')
+ pass
-# if not self.nomap:
-# x, y = self.map(*(glon, glat))
-# else:
+ LOG.info("2. GLON: %s, GLAT: %s", str(glon.shape), str(glat.shape))
xloc, yloc = glon, glat
LOG.info("3. GLON: %s, GLAT: %s", str(xloc.shape), str(yloc.shape))
-# print "map_data", map_data[0].shape
-
- # self.print_time("meshgrid")
- # LOG.info("X: %s, Y: %s" % (str(x.shape), str(y.shape)))
-
-# # nomap option
-# if self.nomap and os.path.exists("%s-%s/%s.png" % (run_date, var_name,
-# fig_name)) and not self.overwrite:
-# print fig_name, " already exists."
-# plt.clf()
-# return fig_name
if self.nomap:
self.mgplot.frameon = False
-# if self.alpha is not None and self.bounds is not None:
-# if self.extend in ('min', 'both'):
-# map_data[0] = np.ma.masked_where(map_data[0] <
-# self.bounds[0], map_data[0])
-# else:
-# map_data[0] = np.ma.masked_where((map_data[0] >=
-# self.bounds[0]) &
-# (map_data[0] <
-# self.bounds[1]),
-# map_data[0])
-
mco = None
LOG.info(type(map_data[0]))
map_data[0] = np.ma.filled(map_data[0], np.nan)
LOG.info(type(map_data[0]))
-# if not self.nocontourf and not self.nomap and self.smooth:
-# LOG.info("X: %s, Y: %s, DATA: %s" % (x.shape, y.shape,
-# map_data[0]))
-# mco = self.map.contourf(x, y,
-# map_data[0],
-# cmap=self.cmap,
-# norm=self.norm,
-# levels=self.bounds,
-# extend=self.extend,
-# horizontalalignment='center',
-# alpha=self.alpha,
-# antialiased=True)
-#
-# elif not self.nocontourf and not self.nomap and not self.smooth:
-# LOG.info("X: %s, Y: %s, DATA: %s" % (x.shape, y.shape,
-# map_data[0]))
-# mco = self.map.pcolormesh(x, y,
-# map_data[0],
-# cmap=self.cmap,
-# norm=self.norm,
-# alpha=self.alpha,
-# antialiased=True)
-
if not self.nocontourf and self.smooth:
- mco = self.mgaxis.contourf(xloc, yloc,
+ mco = self.mgaxis.contourf(xloc,
+ yloc,
map_data[0],
cmap=self.cmap,
norm=self.norm,
@@ -430,9 +368,12 @@ class PlotMap(MapCross, MapDrawOptions):
alpha=self.alpha,
transform=self._orig_crs,
antialiased=True)
+ if self.bad:
+ self.mgaxis.set_facecolor(self.bad)
elif not self.nocontourf and not self.smooth:
- mco = self.mgaxis.pcolormesh(xloc, yloc,
+ mco = self.mgaxis.pcolormesh(xloc,
+ yloc,
map_data[0],
cmap=self.cmap,
norm=self.norm,
@@ -447,20 +388,18 @@ class PlotMap(MapCross, MapDrawOptions):
LOG.info("Processing shape file: %s with line width: %s",
shapef, line_w)
adm1_shapes = list(shpreader.Reader(shapef).geometries())
- self.mgaxis.add_geometries(adm1_shapes, self._crs,
+ self.mgaxis.add_geometries(adm1_shapes,
+ self._crs,
linewidth=line_w,
edgecolor=self.countropts[1])
- # self.map.readshapefile(shapef, "%s" %
- # os.path.basename(shapef), linewidth=line_w,
- # color=self.countropts[1])
- line_w = max(self.shapef_width_step, line_w -
- self.shapef_width_step)
+ line_w = max(self.shapef_width_step,
+ line_w - self.shapef_width_step)
# FIXME Modify to use scatter inside DATA
# if DATA.hasScatterData()... etc...
if scatter_data is not None:
- LOG.info("Plotting scatter data: %s of keys %s",
- str(scatter_data), str(scatter_data.keys()))
+ LOG.info("Plotting scatter data: %s of keys %s", str(scatter_data),
+ str(scatter_data.keys()))
if mco and self.bounds:
self.mgaxis.scatter(scatter_data['lon'].tolist(),
scatter_data['lat'].tolist(),
@@ -513,14 +452,14 @@ class PlotMap(MapCross, MapDrawOptions):
if data.wind_data:
winds = data.wind_data
x_vec, y_vec, u_vec, v_vec = delete_masked_points(
- xloc.ravel(),
- yloc.ravel(),
- winds['u'].ravel(),
- winds['v'].ravel()
- )
+ xloc.ravel(), yloc.ravel(), winds['u'].ravel(),
+ winds['v'].ravel())
if 'barbs' in winds:
- self.mgaxis.barbs(x_vec, y_vec, u_vec, v_vec,
+ self.mgaxis.barbs(x_vec,
+ y_vec,
+ u_vec,
+ v_vec,
units=self.wind_units,
headlength=self.wind_head_length,
headwidth=self.wind_head_width,
@@ -530,7 +469,10 @@ class PlotMap(MapCross, MapDrawOptions):
transform=self._orig_crs,
color='k')
else:
- quiv = self.mgaxis.quiver(x_vec, y_vec, u_vec, v_vec,
+ quiv = self.mgaxis.quiver(x_vec,
+ y_vec,
+ u_vec,
+ v_vec,
units=self.wind_units,
headlength=self.wind_head_length,
headwidth=self.wind_head_width,
@@ -546,7 +488,8 @@ class PlotMap(MapCross, MapDrawOptions):
self.wind_label_scale,
label='%s m/s' % self.wind_label_scale,
coordinates='axes',
- labelpos='S', labelsep=0.05)
+ labelpos='S',
+ labelsep=0.05)
if data.contour_data:
interval = self.contours_int
@@ -555,13 +498,11 @@ class PlotMap(MapCross, MapDrawOptions):
cupp_bound = 99999
cdata = data.contour_data
try:
- # cmin = min(filter (lambda a: a > clow_bound, cdata.ravel()))
cmin = cdata.where(cdata > clow_bound).min()
adjcmin = int(cmin - (cmin % interval) - interval * 2)
except ValueError:
cmin = 0
try:
- # cmax = max(filter (lambda a: a < cupp_bound, cdata.ravel()))
cmax = cdata.where(cdata < cupp_bound).max()
adjcmax = int(cmax - (cmax % interval) + interval * 2)
except ValueError:
@@ -570,7 +511,8 @@ class PlotMap(MapCross, MapDrawOptions):
for exc in exclude:
lvls = [exc for exc in lvls if exc != 0]
if (len(lvls) > 0) and map_data is not None:
- mco = plt.contourf(xloc, yloc,
+ mco = plt.contourf(xloc,
+ yloc,
map_data[0],
cmap=self.cmap,
norm=self.norm,
@@ -581,7 +523,8 @@ class PlotMap(MapCross, MapDrawOptions):
if map_data is not None and (map_data[0] == cdata).all():
LOG.debug(":::::::::::::::::::::: SAME !!! ::::::::::::::::")
- mcs = plt.contour(xloc, yloc,
+ mcs = plt.contour(xloc,
+ yloc,
cdata,
levels=self.bounds,
colors=self.contours_color,
@@ -590,7 +533,8 @@ class PlotMap(MapCross, MapDrawOptions):
else:
LOG.debug(":::::::::::::::::::: DIFFERENT !!! :::::::::::::")
LOG.debug("MIN: %s - MAX: %s", cmin, cmax)
- mcs = plt.contour(xloc, yloc,
+ mcs = plt.contour(xloc,
+ yloc,
cdata,
levels=lvls,
colors=self.contours_color,
@@ -598,20 +542,17 @@ class PlotMap(MapCross, MapDrawOptions):
alpha=self.alpha)
if self.contours_label:
- self.mgplot.clabel(mcs,
- inline=1,
- fontsize=self.contours_label_fontsize,
- # backgroundcolor='r',
- fmt=self.contours_label_format)
-
- # coords normalization
-# lat_offset = abs(self.lat[0]) % self.lat[2]
-# lon_offset = abs(self.lon[0]) % self.lon[2]
+ self.mgplot.clabel(
+ mcs,
+ inline=1,
+ fontsize=self.contours_label_fontsize,
+ # backgroundcolor='r',
+ fmt=self.contours_label_format)
if not self.nomap and not self.kml and not self.kmz:
-
if self.continents:
- self.mgaxis.add_feature(cfeature.LAND, color=self.continents,
+ self.mgaxis.add_feature(cfeature.LAND,
+ color=self.continents,
zorder=10)
self.mgaxis.coastlines(resolution=self.resolution,
@@ -619,66 +560,46 @@ class PlotMap(MapCross, MapDrawOptions):
color=str(self.coastsopts[1]),
zorder=15)
- self.mgaxis.add_feature(cfeature.BORDERS
- .with_scale(self.resolution),
+ self.mgaxis.add_feature(cfeature.BORDERS.with_scale(
+ self.resolution),
linewidth=float(self.countropts[0]),
edgecolor=str(self.countropts[1]),
zorder=15)
- draw_labels = bool(self.projection == 'PlateCarree')
- grl = self.mgaxis.gridlines(xlocs=self.lon, ylocs=self.lat,
- crs=self._crs,
- draw_labels=draw_labels,
- linestyle='--',
- linewidth=float(self.coordsopts[0]),
- color=str(self.coordsopts[2]),
- zorder=20)
+ if self.draw_labels is None:
+ self.draw_labels = bool(self.projection == 'PlateCarree')
+
- if draw_labels:
+ grl = self.mgaxis.gridlines(
+ xlocs=self.lon,
+ ylocs=self.lat,
+ draw_labels=self.draw_labels,
+ linestyle='--',
+ linewidth=float(self.coordsopts[0]),
+ color=str(self.coordsopts[2]),
+ zorder=20,
+ auto_inline=True,
+ )
+
+ if self.draw_labels and bool(self.projection == 'PlateCarree'):
grl.xlabels_top = False
grl.ylabels_right = False
+ if self.draw_labels:
grl.xlabel_style = {'size': float(self.coordsopts[1])}
grl.ylabel_style = grl.xlabel_style
# Change axes for colorbar
if self.colorbar and not self.kml and not self.kmz and \
(not self.nocontourf or scatter_data is not None):
- self.set_color_bar(mco)
+ self.set_color_bar(mco, self.colorbar_location)
if self.background:
self.mgaxis.add_image(self.stamen_terrain, self.zoom_level)
-# if self.background == 'shadedrelief':
-# #m.bluemarble()
-# if self.background == 'shadedrelief':
-# self.map.shadedrelief()
-# if self.background == 'bluemarble':
-# self.map.bluemarble()
-# if self.background == 'etopo':
-# self.map.etopo()
-# if self.background == 'GIS':
-# h0 = float(self.lat[-1] - self.lat[0])
-# w0 = float(self.lon[-1] - self.lon[0])
-# ff = h0/w0 # form factor
-# height = 1024*ff # height
-# size = "%d,%d" % (1024, height)
-# basemap_url =
-# "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/export?\
-# bbox=%s,%s,%s,%s&\
-# bboxSR=4326&\
-# imageSR=4326&\
-# size=%s&\
-# dpi=%d&\
-# format=png24&\
-# f=image" % (self.lon[0], self.lat[0], self.lon[-1], self.lat[-1], size,
-# self.dpi) self.map.imshow(imread(urlopen(basemap_url)), origin='upper')
# logo
if self.logo:
img = Image.open(self.logo[0])
-# height = im.size[1]
-# width = im.size[0]
-
# We need a float array between 0-1, rather than
# a uint8 array between 0-255
nim = np.array(img).astype(np.float) / 255
@@ -687,38 +608,43 @@ class PlotMap(MapCross, MapDrawOptions):
# use the "zorder" kwarg to make the image overlay
# the plot, rather than hide behind it... (e.g. zorder=10)
self.mgplot.figimage(nim, self.logo[1], self.logo[2], zorder=10)
-
+ plt.setp(self.mgaxis.spines.values(), color='black')
# SAVEFIG
fullname = "{}.{}".format(fig_name, self.filefmt)
LOG.info("printing %s", fullname)
if self.kml or self.kmz:
- # self.mgplot.axes(frameon=0)
if self.save:
- self.mgplot.savefig(fullname, bbox_inches='tight',
- frameon=0, pad_inches=0, dpi=self.dpi,
+ self.mgplot.savefig(fullname,
+ bbox_inches='tight',
+ frameon=0,
+ pad_inches=0,
+ dpi=self.dpi,
transparent=True)
else:
self.mgaxis.set_title(img_title, fontsize=self.fontsize, zorder=0)
if self.save:
- self.mgplot.savefig(fullname, bbox_inches='tight',
- pad_inches=.2, dpi=self.dpi)
+ self.mgplot.savefig(fullname,
+ frame_on = True,
+ bbox_inches='tight',
+ pad_inches=.2,
+ dpi=self.dpi)
return fig_name
+ def _set_extent(self):
+ if not self.extent:
+ return
+ if self.extent == 'auto':
+ if self.projection.lower().endswith('polarstereo'):
+ extent = [-180, 179.9999999999999, self.lat[0], self.lat[-1]]
+ else:
+ extent = [self.lon[0], self.lon[-1], self.lat[0], self.lat[-1]]
+ self.mgaxis.set_extent(extent, ccrs.PlateCarree())
+
def compare_maps(self, map_names, outdir, date, steps, tpl=''):
""" Generate maps comparison """
-
os.chdir(outdir)
-
- # print "MAPNAMES", map_names
- # for map_name in map_names:
-# newMapNames = map_names[0]
-# items = {} #[i[0] for i in map_names]
-# for i in range(0, len(map_names)-1):
-# items, newMapNames, newMapNameTpl =
-# self.twoMapsCompare([newMapNames, map_names[i+1]], items)
-
mnames = np.array(map_names)
k_s = mnames.T
@@ -735,25 +661,6 @@ class PlotMap(MapCross, MapDrawOptions):
_, _ = subprocess.getstatusoutput(comm)
idx += 1
- # montage -tile 2x -geometry 800x600+1+1
-
- # rename from 00-06-... to 00-01 ...
-# st, out = commands.getstatusoutput("ls %s*" % newMapNameTpl)
-# if st != 0:
-# print "Error: %s" % str(out)
-# else:
-# names = out.split('\n')
-# #print names
-# for num in range(0, len(names)):
-# snum = "%02d" % num
-# #print "mv %s %s.gif" % (names[num],
-# newMapNameTpl.replace("??", snum)) st2, out2 =
-# commands.getstatusoutput("mv -f %s %s.gif" % (names[num],
-# newMapNameTpl.replace("??", snum)))
-# if st2 != 0:
-# print "Error: %s" % str(out2)
-
-# newMapNameTpl2 = newMapNameTpl.replace("??", "loop")
nimg0 = "??"
nimg1 = "loop"
if tpl:
@@ -782,12 +689,19 @@ class PlotMap(MapCross, MapDrawOptions):
self.wind_scale = int(self.windopts[3])
LOG.info("SHP %s", str(self.shapefiles))
if self.shapefiles:
- self.shapefiles = [f.replace(".shp", "") for f in
- glob(self.shapefiles)]
+ self.shapefiles = [
+ f.replace(".shp", "") for f in glob(self.shapefiles)
+ ]
LOG.info("SHP %s", str(self.shapefiles))
- def aplot(self, xloc, yloc, map_data=None, wind_data=None,
- contour_data=None, scatter_data=None, **kwargs):
+ def aplot(self,
+ xloc,
+ yloc,
+ map_data=None,
+ wind_data=None,
+ contour_data=None,
+ scatter_data=None,
+ **kwargs):
""" Plot one or more maps directly from numerical arrays """
# store options to be restored at the end
@@ -809,8 +723,7 @@ class PlotMap(MapCross, MapDrawOptions):
map_data=[map_data], # temporarily
wind_data=wind_data,
contour_data=contour_data,
- scatter_data=scatter_data
- )
+ scatter_data=scatter_data)
grid = (xloc, yloc)
self.init_map(grid)
@@ -821,15 +734,17 @@ class PlotMap(MapCross, MapDrawOptions):
fig_name = "%s/%s" % (self.outdir, f_name)
if self.subplot is None:
plt.clf()
- self.mgaxis = plt.axes(projection=self._crs)
+ self.mgaxis = plt.axes(projection=self._crs, frame_on=True)
self.mgplot = plt.gcf()
else:
self.mgaxis = plt.subplot(self.subplot[0],
self.subplot[1],
self.subplot[2],
- projection=self._crs)
+ projection=self._crs,
+ frame_on=True)
self.mgplot = plt.gcf()
-
+ self.mgaxis.patch.set_edgecolor('black')
+ self.mgaxis.patch.set_linewidth('1')
self.gen_image_map(
fig_name,
grid,
@@ -838,21 +753,6 @@ class PlotMap(MapCross, MapDrawOptions):
# scatter_data=scatter_data
)
-# # Create Max at required intervals
-# if self.maxdata and n_time in self.maxdata:
-# if (self.maxtitle != None):
-# fig_name = "%s_%s" % (f_name, 'MAXD%d' % (n_time/24))
-# p_title = self.set_title(self.maxtitle, s_date, curr_date,
-# s_time)
-# self.gen_image_map(
-# fig_name,
-# grid,
-# nc_handler.get_current_max_data(),
-# p_title
-# )
-# else:
-# print "Missing MAXTITLE, thus not generating MAX images!"
-
# restore options without local function parameters
vars(self).update(localvars)
@@ -862,12 +762,10 @@ class PlotMap(MapCross, MapDrawOptions):
if 'title' not in kwargs:
kwargs['title'] = self._get_default_title(cube)
- self.aplot(
- cube.coord('longitude').points,
- cube.coord('latitude').points,
- map_data=cube.data,
- **kwargs
- )
+ self.aplot(cube.coord('longitude').points,
+ cube.coord('latitude').points,
+ map_data=cube.data,
+ **kwargs)
def plot(self, **kwargs):
""" Plot one or more maps from netCDF file(s) """
@@ -913,8 +811,10 @@ class PlotMap(MapCross, MapDrawOptions):
self.transf,
self.subsetting,
self.dimension,
- winds={'src': self.wind,
- 'opts': self.windopts},
+ winds={
+ 'src': self.wind,
+ 'opts': self.windopts
+ },
contours={'var': self.contours},
varconds=self.varconds,
)
@@ -939,20 +839,16 @@ class PlotMap(MapCross, MapDrawOptions):
# if not NOMAP:
self.init_map(grid)
- s_date = datetime.strptime("%s %s %s %s" % (run_tmp[-4:],
- run_tmp[-7:-4],
- run_tmp[-9:-7],
- run_tmp[0:2]),
- "%Y %b %d %H")
+ s_date = datetime.strptime(
+ "%s %s %s %s" %
+ (run_tmp[-4:], run_tmp[-7:-4], run_tmp[-9:-7], run_tmp[0:2]),
+ "%Y %b %d %H")
ss_date = s_date.strftime("%Y%m%d")
steps = []
start = self.timesteps[0]
- # LOG.info("Start @ %s - s_date: %s - run_tmp: %s" % (START, s_date,
- # run_tmp))
-
if start is None:
start = 0
@@ -969,48 +865,40 @@ class PlotMap(MapCross, MapDrawOptions):
self.mgplot = plt.gcf()
valid_tmp = dims[n_time]
- curr_date = datetime.strptime("%s %s %s %s" % (valid_tmp[-4:],
- valid_tmp[-7:-4],
- valid_tmp[-9:-7],
- valid_tmp[0:2]),
- "%Y %b %d %H")
+ curr_date = datetime.strptime(
+ "%s %s %s %s" % (valid_tmp[-4:], valid_tmp[-7:-4],
+ valid_tmp[-9:-7], valid_tmp[0:2]),
+ "%Y %b %d %H")
s_time = "%02d" % n_time
steps.append(s_time)
- p_time = (curr_date - s_date).total_seconds()/3600
- # s_time24 = "%02d" % (p_time%24)
- # s_time3d = "%03d" % p_time # Currently unused, only for
- # Valentina who has more than 99 img in a set
+ p_time = (curr_date - s_date).total_seconds() / 3600
if self.img_template:
f_name = self.img_template % {'date': ss_date, 'step': s_time}
fig_name = "%s/%s" % (self.outdir, f_name)
- loop_name = self.img_template % {'date': ss_date,
- 'step': 'loop'}
+ loop_name = self.img_template % {
+ 'date': ss_date,
+ 'step': 'loop'
+ }
else:
- f_name = '.'.join(os.path.basename(self.srcfiles[0])
- .split('.')[:-1])
+ f_name = '.'.join(
+ os.path.basename(self.srcfiles[0]).split('.')[:-1])
fig_name = "%s/%s_%s" % (self.outdir, f_name, s_time)
loop_name = "%s_loop" % (f_name)
- # valid = "%02dUTC %s" % (p_time % 24, curr_date.strftime("%d %b
- # %Y"))
-
- # stime = "%02d" % (int(run_tmp.split('Z')[0])+p_time)
stime = "%02d" % (p_time)
p_title = set_title(self.title, s_date, curr_date, s_time, stime)
cur_scatter_data = None
if scatter_data is not None and (curr_date in scatter_data):
cur_scatter_data = scatter_data[curr_date]
- fname = self.gen_image_map(
- fig_name,
- grid,
- nc_handler.get_data_for_tstep(n_time),
- p_title,
- cur_scatter_data=cur_scatter_data
- )
+ fname = self.gen_image_map(fig_name,
+ grid,
+ nc_handler.get_data_for_tstep(n_time),
+ p_title,
+ cur_scatter_data=cur_scatter_data)
fig_names.append(fname)
plt_names.append((self.mgplot, self.mgaxis))
@@ -1018,15 +906,12 @@ class PlotMap(MapCross, MapDrawOptions):
# Create Max at required intervals
if self.maxdata and n_time in self.maxdata:
if self.maxtitle is not None:
- fig_name = "%s_%s" % (f_name, 'MAXD%d' % (n_time/24))
+ fig_name = "%s_%s" % (f_name, 'MAXD%d' % (n_time / 24))
p_title = set_title(self.maxtitle, s_date, curr_date,
s_time, stime)
- self.gen_image_map(
- fig_name,
- grid,
- nc_handler.get_current_max_data(),
- p_title
- )
+ self.gen_image_map(fig_name, grid,
+ nc_handler.get_current_max_data(),
+ p_title)
else:
LOG.info("Missing MAXTITLE, not generating MAX images!")
@@ -1038,10 +923,9 @@ class PlotMap(MapCross, MapDrawOptions):
mpl.rcParams['axes.linewidth'] = 0.1
fig = plt.figure(figsize=(.1, 12))
cax = fig.add_axes([0.05, 0.80, 0.9, 0.15])
- # , axisbg=(1, 1, 1, 0))
print("...", self.bounds, "...")
cbar = mpl.colorbar.ColorbarBase(
- cax, # =self.mgaxis,
+ cax,
cmap=self.cmap,
norm=self.norm,
values=self.bounds,
@@ -1050,11 +934,6 @@ class PlotMap(MapCross, MapDrawOptions):
drawedges=False)
if self.bounds:
cbar.set_ticklabels(self.bounds)
-# else:
-# try:
-# cbar.set_ticklabels(mco.levels)
-# except:
-# pass
cbar.ax.tick_params(labelsize=6)
plt.setp(plt.getp(cax, 'yticklabels'), color='w')
plt.setp(plt.getp(cax, 'yticklabels'), fontsize=6)
@@ -1064,12 +943,11 @@ class PlotMap(MapCross, MapDrawOptions):
tit = str(p_title)
idx1 = tit.find('(')
idx2 = tit.find(')')
- var_unit = tit[idx1:idx2+1]
+ var_unit = tit[idx1:idx2 + 1]
if var_unit.find("%s") >= 0:
var_unit = ''
plt.xlabel(
p_title,
- # "%s\n%s" % (self.srcvars[0], var_unit),
horizontalalignment='left',
color='w',
fontsize=6,
@@ -1079,55 +957,36 @@ class PlotMap(MapCross, MapDrawOptions):
os.makedirs("%s-%s" % (run_date, self.srcvars[0]))
if self.save:
- fig.savefig(
- "%s/%s-%s/%s-colorbar.png" % (self.outdir, run_date,
- self.srcvars[0], run_date),
- bbox_inches='tight',
- pad_inches=0, dpi=self.dpi,
- transparent=True
- )
+ fig.savefig("%s/%s-%s/%s-colorbar.png" %
+ (self.outdir, run_date, self.srcvars[0], run_date),
+ bbox_inches='tight',
+ pad_inches=0,
+ dpi=self.dpi,
+ transparent=True)
# generate KMZ/KML - Offline/Online - online priority
if self.kmz or self.kml:
online = self.kml
LOG.info("Generating KMZ ...")
- gen_kml(fig_names, self.srcvars[0], self.lon, self.lat, dims,
- self.outdir, online=online)
+ gen_kml(fig_names,
+ self.srcvars[0],
+ self.lon,
+ self.lat,
+ dims,
+ self.outdir,
+ online=online)
# generate animation.
if self.anim:
- gen_anim(
- "%s.%s" % (loop_name.replace('loop', '*'), self.filefmt),
- "%s.gif" % loop_name,
- self.outdir,
- self.anim_delay
- )
-# fulloutdir = os.path.join(self.outdir,
-# os.path.dirname(self.img_template))
-# loop_name = os.path.basename(loop_name)
-# self.gen_anim(
-# fulloutdir,
-# "%s.%s" % (loop_name.replace('loop','*'),
-# self.filefmt),
-# fulloutdir,
-# "%s.gif" % loop_name
-# )
-
+ gen_anim("%s.%s" % (loop_name.replace('loop', '*'), self.filefmt),
+ "%s.gif" % loop_name, self.outdir, self.anim_delay)
map_names.append(fig_names)
# restore options without local function parameters
vars(self).update(localvars)
- # print "Returning ", plt_names
- # return plt_names
-
-# num = len(map_names)
-# if num > 1:
-# mg.compare_maps(map_names, OUTDIR, ss_date, steps, JOINT_TEMPLATE )
-
def reset_conf(self):
""" Back to the initial conditions. """
-
self.__init__()
def load_conf(self, section=None, fpath=None, reset=False):
@@ -1173,8 +1032,7 @@ class PlotMap(MapCross, MapDrawOptions):
self.reset_conf()
defaults = copy.deepcopy(vars(self))
# calculate diff
- diff = {k: curropts[k] for k in curropts if curropts[k] !=
- defaults[k]}
+ diff = {k: curropts[k] for k in curropts if curropts[k] != defaults[k]}
# reload diff
vars(self).update(diff)
# save diff
diff --git a/mapgenerator/plotting/tools.py b/mapgenerator/plotting/tools.py
index ce3708c9b4a11cf41ae3596eaa7929e5ad18687f..a5a51ee2855556706694a68197b3d8ad2a2b5af2 100644
--- a/mapgenerator/plotting/tools.py
+++ b/mapgenerator/plotting/tools.py
@@ -73,6 +73,7 @@ def set_resolution(lon, lat):
zoom = 1
elif lats > 45 and lons > 75:
resolution = '50m'
+ zoom = 2
elif lats <= 45 and lons <= 75:
resolution = '10m'
zoom = 4
diff --git a/mapgenerator/test/unit/test_argument_parser.py b/mapgenerator/test/unit/test_argument_parser.py
index 79d74ed2555d621bc820d708dcb4b396a35b1d16..3984ce8f3ed48a8dc042e5fe2cf1fbdc778363fa 100644
--- a/mapgenerator/test/unit/test_argument_parser.py
+++ b/mapgenerator/test/unit/test_argument_parser.py
@@ -1,21 +1,4 @@
-#!/usr/bin/env python
-# Copyright 2016 Earth Sciences Department, BSC-CNS
-
-# This file is part of MapGenerator.
-
-# MapGenerator is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# MapGenerator 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 MapGenerator. If not, see .
import unittest
from mapgenerator.plotting.config import ArgumentParser
diff --git a/mapgenerator/test/unit/test_environment.py b/mapgenerator/test/unit/test_environment.py
index 5ab7bde7e96f8f8bd3a4ddc85ed82c4e3bc61674..a78e96b0b2d1d8e353e9742a7544a258ee272dba 100644
--- a/mapgenerator/test/unit/test_environment.py
+++ b/mapgenerator/test/unit/test_environment.py
@@ -1,22 +1,3 @@
-#!/usr/bin/env python
-
-# Copyright 2016 Earth Sciences Department, BSC-CNS
-
-# This file is part of R2D2.
-
-# R2D2 is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# R2D2 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 R2D2. If not, see .
-
from unittest import TestCase
diff --git a/mapgenerator/test/unit/test_http.py b/mapgenerator/test/unit/test_http.py
index c95f476b081b1775f45f9cf46f03c93f2bdd891e..3c9dd5e0df61e6378ec303de43fb4b90649c4493 100644
--- a/mapgenerator/test/unit/test_http.py
+++ b/mapgenerator/test/unit/test_http.py
@@ -1,22 +1,3 @@
-#!/usr/bin/env python
-
-# Copyright 2016 Earth Sciences Department, BSC-CNS
-
-# This file is part of R2D2.
-
-# R2D2 is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# R2D2 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 R2D2. If not, see .
-
import unittest
from r2d2.argument_parser import ArgumentParser
from r2d2.http.dataset import DatasetHTTP
diff --git a/setup.py b/setup.py
index b3175a35e991cd3af97db0233add8b173f9e4ac7..818fcf3640bbe6fb603870852686807de86be2da 100644
--- a/setup.py
+++ b/setup.py
@@ -1,24 +1,3 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Copyright 2018 Barcelona Supercomputing Center - Centro Nacional de
-# Supercomputación (BSC-CNS)
-
-# This file is part of MapGenerator.
-
-# MapGenerator is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# MapGenerator 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 MapGenerator. If not, see .
-
from setuptools import setup
from mapgenerator import __version__
@@ -41,7 +20,7 @@ REQUIREMENTS = {
setup(
# Application name:
name="mapgenerator",
- license='GNU GPL v3',
+ license='Apache 2.0',
# Version number (initial):
version=__version__,
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391