diff --git a/CHANGES b/CHANGES index 34098ea632..154a5d43fe 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,17 @@ +Release 1.0 +=========== + +Incompatible changes +-------------------- +* With the change to cartopy, the function iris.plot.gcm() is obsolete + and has been removed. +* Three functions have been removed from iris.analysis.cartography: + lat_lon_range(), get_lat_lon_grids(), and + get_lat_lon_contiguous_grids(). They have been replaced with + generalised versions: xy_range(), get_xy_grids(), + and get_xy_contiguous_bounded_grids(). + + Release 0.9 (14 Aug, 2012) ========================== diff --git a/docs/iris/example_code/graphics/COP_maps.py b/docs/iris/example_code/graphics/COP_maps.py index 9b69a730e6..68b120cede 100644 --- a/docs/iris/example_code/graphics/COP_maps.py +++ b/docs/iris/example_code/graphics/COP_maps.py @@ -86,8 +86,7 @@ def main(): plt.subplot(121) plt.title('HadGEM2 E1 Scenario', fontsize=10) iplt.contourf(delta_e1, levels, colors=colors, linewidth=0, extend='both') - current_map = iplt.gcm() - current_map.drawcoastlines() + plt.gca().coastlines() # get the current axes' subplot for use later on plt1_ax = plt.gca() @@ -95,8 +94,7 @@ def main(): plt.subplot(122) plt.title('HadGEM2 A1B-Image Scenario', fontsize=10) contour_result = iplt.contourf(delta_a1b, levels, colors=colors, linewidth=0, extend='both') - current_map = iplt.gcm() - current_map.drawcoastlines() + plt.gca().coastlines() # get the current axes' subplot for use later on plt2_ax = plt.gca() diff --git a/docs/iris/example_code/graphics/TEC.py b/docs/iris/example_code/graphics/TEC.py index 460b531241..2360431af7 100644 --- a/docs/iris/example_code/graphics/TEC.py +++ b/docs/iris/example_code/graphics/TEC.py @@ -41,8 +41,8 @@ def main(): plt.title('Total Electron Content') plt.xlabel('longitude / degrees') plt.ylabel('latitude / degrees') - iplt.gcm().bluemarble(zorder=-1) - iplt.gcm().drawcoastlines() + plt.gca().bluemarble() + plt.gca().coastlines() plt.show() diff --git a/docs/iris/example_code/graphics/custom_file_loading.py b/docs/iris/example_code/graphics/custom_file_loading.py index 9e96ed52be..5035dfaf49 100644 --- a/docs/iris/example_code/graphics/custom_file_loading.py +++ b/docs/iris/example_code/graphics/custom_file_loading.py @@ -215,15 +215,11 @@ def main(): # Callback shown as None to illustrate where a cube-level callback function would be used if required cube = iris.load_strict(fname, boundary_volc_ash_constraint, callback=None) - map = iplt.map_setup(lon_range=[-70, 20], lat_range=[20, 75], resolution='i') - - map.drawcoastlines() - - iplt.contourf(cube, - levels=(0.0002, 0.002, 0.004, 1), + iplt.map_setup(xlim=(-70, 20), ylim=(20, 75)) + plt.gca().coastlines() + iplt.contourf(cube, levels=(0.0002, 0.002, 0.004, 1), colors=('#80ffff', '#939598', '#e00404'), - extend='max' - ) + extend='max') time = cube.coord('time') time_date = time.units.num2date(time.points[0]).strftime(UTC_format) diff --git a/docs/iris/example_code/graphics/global_map.py b/docs/iris/example_code/graphics/global_map.py index d5bad243d4..f20673b1be 100644 --- a/docs/iris/example_code/graphics/global_map.py +++ b/docs/iris/example_code/graphics/global_map.py @@ -18,7 +18,7 @@ def main(): temperature = iris.load_strict(fname) qplt.contourf(temperature, 15) - iplt.gcm().drawcoastlines() + plt.gca().coastlines() plt.show() diff --git a/docs/iris/example_code/graphics/lagged_ensemble.py b/docs/iris/example_code/graphics/lagged_ensemble.py index 056c699495..906bf2cefa 100644 --- a/docs/iris/example_code/graphics/lagged_ensemble.py +++ b/docs/iris/example_code/graphics/lagged_ensemble.py @@ -76,8 +76,7 @@ def main(): cf = iplt.contourf(cube, contour_levels) # add coastlines - m = iplt.gcm() - m.drawcoastlines() + plt.gca().coastlines() # make an axes to put the shared colorbar in colorbar_axes = plt.gcf().add_axes([0.35, 0.1, 0.3, 0.05]) diff --git a/docs/iris/example_code/graphics/rotated_pole_mapping.py b/docs/iris/example_code/graphics/rotated_pole_mapping.py index 829f077eca..59d5036218 100644 --- a/docs/iris/example_code/graphics/rotated_pole_mapping.py +++ b/docs/iris/example_code/graphics/rotated_pole_mapping.py @@ -23,36 +23,27 @@ def main(): fname = iris.sample_data_path('rotated_pole.nc') temperature = iris.load_strict(fname) - # Calculate the lat lon range and buffer it by 10 degrees - lat_range, lon_range = iris.analysis.cartography.lat_lon_range(temperature) - lat_range = lat_range[0] - 10, lat_range[1] + 10 - lon_range = lon_range[0] - 10, lon_range[1] + 10 - - # Plot #1: Point plot showing data values & a colorbar plt.figure() - iplt.map_setup(temperature, lat_range=lat_range, lon_range=lon_range) points = qplt.points(temperature, c=temperature.data) cb = plt.colorbar(points, orientation='horizontal') cb.set_label(temperature.units) - iplt.gcm().drawcoastlines() + plt.gca().coastlines() plt.show() # Plot #2: Contourf of the point based data plt.figure() - iplt.map_setup(temperature, lat_range=lat_range, lon_range=lon_range) qplt.contourf(temperature, 15) - iplt.gcm().drawcoastlines() + plt.gca().coastlines() plt.show() # Plot #3: Contourf overlayed by coloured point data plt.figure() - iplt.map_setup(temperature, lat_range=lat_range, lon_range=lon_range) qplt.contourf(temperature) iplt.points(temperature, c=temperature.data) - iplt.gcm().drawcoastlines() + plt.gca().coastlines() plt.show() @@ -64,10 +55,9 @@ def main(): # Plot #4: Block plot plt.figure() - iplt.map_setup(temperature, lat_range=lat_range, lon_range=lon_range) iplt.pcolormesh(temperature) - iplt.gcm().bluemarble() - iplt.gcm().drawcoastlines() + plt.gca().bluemarble() + plt.gca().coastlines() plt.show() diff --git a/docs/iris/src/conf.py b/docs/iris/src/conf.py index c3764031d3..9b91ca3722 100644 --- a/docs/iris/src/conf.py +++ b/docs/iris/src/conf.py @@ -146,7 +146,6 @@ 'numpy': ('http://docs.scipy.org/doc/numpy/', None), 'scipy': ('http://docs.scipy.org/doc/scipy/reference/', None), 'matplotlib': ('http://matplotlib.sourceforge.net/', None), - 'basemap': ('http://matplotlib.github.com/basemap/', None), } diff --git a/docs/iris/src/userguide/plotting_a_cube.rst b/docs/iris/src/userguide/plotting_a_cube.rst index 049058536a..1f47f46190 100644 --- a/docs/iris/src/userguide/plotting_a_cube.rst +++ b/docs/iris/src/userguide/plotting_a_cube.rst @@ -207,15 +207,15 @@ Plotting 2-dimensional cubes Creating maps ------------- -Whenever a 2D plot is created and the x and y coordinates are longitude and latitude a -:class:`mpl_toolkits.basemap.Basemap` instance is created which can be accessed with the :func:`iris.plot.gcm` function. +Whenever a 2D plot is created using an :class:`iris.coord_systems.CoordSystem` a +cartopy :class:`~cartopy.mpl_integration.GenericProjectionAxes` instance is created +which can be accessed with the :func:`matplotlib.pyplot.gca` function. -Given the current map, you can draw meridians, parallels and coastlines amongst other things. +Given the current map, you can draw gridlines and coastlines amongst other things. .. seealso:: - :meth:`Basemap.drawmeridians() `, - :meth:`Basemap.drawparallels() ` and - :meth:`Basemap.drawcoastlines() `. + :meth:`cartopy's gridlines() `, + :meth:`cartopy's coastlines() `. Cube contour diff --git a/docs/iris/src/userguide/plotting_examples/cube_blockplot.py b/docs/iris/src/userguide/plotting_examples/cube_blockplot.py index 23b644012b..6cdc3bafbd 100644 --- a/docs/iris/src/userguide/plotting_examples/cube_blockplot.py +++ b/docs/iris/src/userguide/plotting_examples/cube_blockplot.py @@ -14,10 +14,7 @@ # Draw the contour with 25 levels qplt.pcolormesh(temperature_cube) -# Get the map created by pcolormesh -current_map = iplt.gcm() - -# Add coastlines to the map -current_map.drawcoastlines() +# Add coastlines to the map created by pcolormesh +plt.gca().coastlines() plt.show() diff --git a/docs/iris/src/userguide/plotting_examples/cube_contour.py b/docs/iris/src/userguide/plotting_examples/cube_contour.py index bb5633cda4..9ada3cfb9b 100644 --- a/docs/iris/src/userguide/plotting_examples/cube_contour.py +++ b/docs/iris/src/userguide/plotting_examples/cube_contour.py @@ -11,11 +11,8 @@ # Add a contour, and put the result in a variable called contour. contour = qplt.contour(temperature_cube) -# Get the map created by contourf -current_map = iplt.gcm() - -# Add coastlines to the map -current_map.drawcoastlines() +# Add coastlines to the map created by contour +plt.gca().coastlines() # Add contour labels based on the contour we have just created plt.clabel(contour) diff --git a/docs/iris/src/userguide/plotting_examples/cube_contourf.py b/docs/iris/src/userguide/plotting_examples/cube_contourf.py index dd35b4024e..d11148bf5a 100644 --- a/docs/iris/src/userguide/plotting_examples/cube_contourf.py +++ b/docs/iris/src/userguide/plotting_examples/cube_contourf.py @@ -10,10 +10,7 @@ # Draw the contour with 25 levels qplt.contourf(temperature_cube, 25) -# Get the map created by contourf -current_map = iplt.gcm() - -# Add coastlines to the map -current_map.drawcoastlines() +# Add coastlines to the map created by contourf +plt.gca().coastlines() plt.show() diff --git a/lib/iris/analysis/cartography.py b/lib/iris/analysis/cartography.py index 4bd4bf6392..c91ae12fea 100644 --- a/lib/iris/analysis/cartography.py +++ b/lib/iris/analysis/cartography.py @@ -22,8 +22,9 @@ import math import warnings -from mpl_toolkits.basemap import pyproj +import pyproj import numpy +import cartopy.crs import iris.analysis import iris.coords @@ -95,18 +96,26 @@ def _get_lat_lon_coords(cube): lat_coords = filter(lambda coord: "latitude" in coord.name(), cube.coords()) lon_coords = filter(lambda coord: "longitude" in coord.name(), cube.coords()) if len(lat_coords) > 1 or len(lon_coords) > 1: - raise ValueError("Calling lat_lon_range() with multiple lat or lon coords is currently disallowed") + raise ValueError("Calling _get_lat_lon_coords() with multiple lat or lon coords is currently disallowed") lat_coord = lat_coords[0] lon_coord = lon_coords[0] return (lat_coord, lon_coord) -def lat_lon_range(cube, mode=None): +def xy_range(cube, mode=None, projection=None): """ - Return the lat & lon range of this Cube. + Return the x & y range of this Cube. - If the coordinate has both points & bounds, the mode keyword can be set to determine which should be - used in the min/max calculation. (Must be one of iris.coords.POINT_MODE or iris.coords.BOUND_MODE) + Args: + + * cube - The cube for which to calculate xy extents. + + Kwargs: + + * mode - If the coordinate has bounds, use the mode keyword to specify the + min/max calculation (iris.coords.POINT_MODE or iris.coords.BOUND_MODE). + + * projection - Calculate the xy range in an alternative projection. """ # Helpful error if we have an inappropriate CoordSystem @@ -114,73 +123,79 @@ def lat_lon_range(cube, mode=None): if cs is not None and not isinstance(cs, (iris.coord_systems.GeogCS, iris.coord_systems.RotatedGeogCS)): raise ValueError("Latlon coords cannot be found with {0}.".format(type(cs))) - # get the lat and lon coords (might have "grid_" at the start of the name, if rotated). - lat_coord, lon_coord = _get_lat_lon_coords(cube) + x_coord, y_coord = cube.coord(axis="X"), cube.coord(axis="Y") cs = cube.coord_system('CoordSystem') - if lon_coord.has_bounds() != lat_coord.has_bounds(): - raise ValueError('Cannot get the range of the latitude and longitude coordinates if they do ' + if x_coord.has_bounds() != x_coord.has_bounds(): + raise ValueError('Cannot get the range of the x and y coordinates if they do ' 'not have the same presence of bounds.') - if lon_coord.has_bounds(): + if x_coord.has_bounds(): if mode not in [iris.coords.POINT_MODE, iris.coords.BOUND_MODE]: raise ValueError('When the coordinate has bounds, please specify "mode".') _mode = mode else: _mode = iris.coords.POINT_MODE + # Get the x and y grids if isinstance(cs, iris.coord_systems.RotatedGeogCS): if _mode == iris.coords.POINT_MODE: - lats, lons = get_lat_lon_grids(cube) + x, y = get_xy_grids(cube) else: - lats, lons = get_lat_lon_contiguous_bounded_grids(cube) + x, y = get_xy_contiguous_bounded_grids(cube) else: if _mode == iris.coords.POINT_MODE: - lons = lon_coord.points - lats = lat_coord.points + x = x_coord.points + y = y_coord.points else: - lons = lon_coord.bounds - lats = lat_coord.bounds + x = x_coord.bounds + y = y_coord.bounds + + if projection: + # source projection + source_cs = cube.coord_system("CoordSystem") + if source_cs is not None: + source_proj = source_cs.as_cartopy_projection() + else: + #source_proj = cartopy.crs.PlateCarree() + raise Exception('Unknown source coordinate system') + + if source_proj != projection: + # TODO: Ensure there is a test for this + x, y = projection.transform_points(x=x, y=y, src_crs=source_proj) - if getattr(lon_coord, 'circular', False): - lon_range = (numpy.min(lons), numpy.min(lons) + lon_coord.units.modulus) + # Get the x and y range + if getattr(x_coord, 'circular', False): + x_range = (numpy.min(x), numpy.min(x) + x_coord.units.modulus) else: - lon_range = (numpy.min(lons), numpy.max(lons)) - - return ( (numpy.min(lats), numpy.max(lats)), lon_range ) + x_range = (numpy.min(x), numpy.max(x)) + + y_range = (numpy.min(y), numpy.max(y)) + return (x_range, y_range) -def get_lat_lon_grids(cube): + +def get_xy_grids(cube): """ - Return 2d lat and lon points in the requested coordinate system. + Return 2d x and y points in the native coordinate system. :: - lats, lons = get_lat_lon_grids(cube) + x, y = get_xy_grids(cube) """ - # get the lat and lon coords (might have "grid_" at the start of the name, if rotated). - lat_coord, lon_coord = _get_lat_lon_coords(cube) + x_coord, y_coord = cube.coord(axis="X"), cube.coord(axis="Y") cs = cube.coord_system('CoordSystem') - if lon_coord.units != 'degrees': - lon_coord = lon_coord.unit_converted('degrees') - if lat_coord.units != 'degrees': - lat_coord = lat_coord.unit_converted('degrees') - - lons = lon_coord.points - lats = lat_coord.points + x = x_coord.points + y = y_coord.points # Convert to 2 x 2d grid of data - lons, lats = numpy.meshgrid(lons, lats) - - # if the pole was rotated, then un-rotate it - if isinstance(cs, iris.coord_systems.RotatedGeogCS): - lons, lats = unrotate_pole(lons, lats, cs.grid_north_pole_longitude, cs.grid_north_pole_latitude) - - return (lats, lons) + x, y = numpy.meshgrid(x, y) + return (x, y) -def get_lat_lon_contiguous_bounded_grids(cube): + +def get_xy_contiguous_bounded_grids(cube): """ Return 2d lat and lon bounds. @@ -190,21 +205,14 @@ def get_lat_lon_contiguous_bounded_grids(cube): lats, lons = cs.get_lat_lon_bounded_grids() """ - # get the lat and lon coords (might have "grid_" at the start of the name, if rotated). - lat_coord, lon_coord = _get_lat_lon_coords(cube) + x_coord, y_coord = cube.coord(axis="X"), cube.coord(axis="Y") cs = cube.coord_system('CoordSystem') - if lon_coord.units != 'degrees': - lon_coord = lon_coord.unit_converted('degrees') - if lat_coord.units != 'degrees': - lat_coord = lat_coord.unit_converted('degrees') - - lons = lon_coord.contiguous_bounds() - lats = lat_coord.contiguous_bounds() - lons, lats = numpy.meshgrid(lons, lats) - if isinstance(cs, iris.coord_systems.RotatedGeogCS): - lons, lats = iris.analysis.cartography.unrotate_pole(lons, lats, cs.grid_north_pole_longitude, cs.grid_north_pole_latitude) - return (lats, lons) + x = x_coord.contiguous_bounds() + y = y_coord.contiguous_bounds() + x, y = numpy.meshgrid(x, y) + + return (x, y) def _quadrant_area(radian_colat_bounds, radian_lon_bounds, radius_of_earth): diff --git a/lib/iris/etc/grib_rules.txt b/lib/iris/etc/grib_rules.txt index c5946bc488..ec718a2c3b 100644 --- a/lib/iris/etc/grib_rules.txt +++ b/lib/iris/etc/grib_rules.txt @@ -19,34 +19,33 @@ ### Edition independent metadata ### #################################### - IF grib.gridType=="regular_ll" grib.jPointsAreConsecutive == 0 THEN -CoordAndDims(DimCoord(numpy.arange(grib.Nj, dtype=numpy.float64) * grib.jDirectionIncrementInDegrees * (grib.jScansPositively*2-1) + grib.latitudeOfFirstGridPointInDegrees, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0) -CoordAndDims(DimCoord(numpy.arange(grib.Ni) * grib.iDirectionIncrementInDegrees * (grib.iScansNegatively*(-2)+1) + grib.longitudeOfFirstGridPointInDegrees, grib._x_coord_name, units='degrees', coord_system=grib._coord_system), 1) +CoordAndDims(DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0) +CoordAndDims(DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1) IF grib.gridType=="regular_ll" grib.jPointsAreConsecutive == 1 THEN -CoordAndDims(DimCoord(numpy.arange(grib.Nj, dtype=numpy.float64) * grib.jDirectionIncrementInDegrees * (grib.jScansPositively*2-1) + grib.latitudeOfFirstGridPointInDegrees, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1) -CoordAndDims(DimCoord(numpy.arange(grib.Ni, dtype=numpy.float64) * grib.iDirectionIncrementInDegrees * (grib.iScansNegatively*(-2)+1) + grib.longitudeOfFirstGridPointInDegrees, grib._x_coord_name, units='degrees', coord_system=grib._coord_system), 0) +CoordAndDims(DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1) +CoordAndDims(DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0) IF grib.gridType=="rotated_ll" grib.jPointsAreConsecutive == 0 THEN -CoordAndDims(DimCoord(numpy.arange(grib.Nj, dtype=numpy.float64) * grib.jDirectionIncrementInDegrees * (grib.jScansPositively*2-1) + grib.latitudeOfFirstGridPointInDegrees, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0) -CoordAndDims(DimCoord(numpy.arange(grib.Ni, dtype=numpy.float64) * grib.iDirectionIncrementInDegrees * (grib.iScansNegatively*(-2)+1) + grib.longitudeOfFirstGridPointInDegrees, grib._x_coord_name, units='degrees', coord_system=grib._coord_system), 1) +CoordAndDims(DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0) +CoordAndDims(DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1) IF grib.gridType=="rotated_ll" grib.jPointsAreConsecutive == 1 THEN -CoordAndDims(DimCoord(numpy.arange(grib.Nj, dtype=numpy.float64) * grib.jDirectionIncrementInDegrees * (grib.jScansPositively*2-1) + grib.latitudeOfFirstGridPointInDegrees, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1) -CoordAndDims(DimCoord(numpy.arange(grib.Ni, dtype=numpy.float64) * grib.iDirectionIncrementInDegrees * (grib.iScansNegatively*(-2)+1) + grib.longitudeOfFirstGridPointInDegrees, grib._x_coord_name, units='degrees', coord_system=grib._coord_system), 0) +CoordAndDims(DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1) +CoordAndDims(DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0) diff --git a/lib/iris/fileformats/grib.py b/lib/iris/fileformats/grib.py index 7f124139db..b71c2980d4 100644 --- a/lib/iris/fileformats/grib.py +++ b/lib/iris/fileformats/grib.py @@ -196,7 +196,8 @@ def _compute_extra_keys(self): # Warn if we detect 'bad' (2's compliment) forecastTime. # Don't fix it, we're not doing that at present. It's not grib compliant. if abs(forecastTime) > 2**24: - warnings.warn("Bad forecastTime detected! Please contact the Iris team with the file you tried to load.") + warnings.warn("Bad forecastTime detected! " + "Please contact the Iris team with the file you tried to load.") else: forecastTime = self.stepRange @@ -219,11 +220,16 @@ def _compute_extra_keys(self): '_firstLevelTypeUnits':unknown_string, '_firstLevel':-1.0, '_secondLevelTypeName':unknown_string, '_secondLevel':-1.0, '_originatingCentre':unknown_string, '_forecastTimeUnit':unknown_string, - '_coord_system':None, - '_x_coord_name':unknown_string, '_y_coord_name':unknown_string} + '_coord_system':None, '_x_circular':False, + '_x_coord_name':unknown_string, '_y_coord_name':unknown_string, + # These are here to avoid repetition in the rules files, + # and reduce the very long line lengths. + '_x_points':None, '_y_points':None} #reference date - self.extra_keys['_referenceDateTime'] = datetime.datetime(int(self.year), int(self.month), int(self.day), int(self.hour), int(self.minute)) + self.extra_keys['_referenceDateTime'] = \ + datetime.datetime(int(self.year), int(self.month), int(self.day), + int(self.hour), int(self.minute)) #verification date processingDone = self._get_processing_done() @@ -236,9 +242,10 @@ def _compute_extra_keys(self): endMinute = self.minuteOfEndOfOverallTimeInterval # fixed forecastTime in hours - self.extra_keys['_periodStartDateTime'] = self.extra_keys['_referenceDateTime'] + \ - datetime.timedelta(0, 0, 0, 0, 0, int(forecastTime)) - self.extra_keys['_periodEndDateTime'] = datetime.datetime(endYear, endMonth, endDay, endHour, endMinute) + self.extra_keys['_periodStartDateTime'] = \ + self.extra_keys['_referenceDateTime'] + datetime.timedelta(0, 0, 0, 0, 0, int(forecastTime)) + self.extra_keys['_periodEndDateTime'] = \ + datetime.datetime(endYear, endMonth, endDay, endHour, endMinute) else: self.extra_keys['_phenomenonDateTime'] = self._get_verification_date() @@ -343,6 +350,32 @@ def _compute_extra_keys(self): else: self.extra_keys['_x_coord_name'] = "grid_longitude" self.extra_keys['_y_coord_name'] = "grid_latitude" + + i_step = self.iDirectionIncrementInDegrees + j_step = self.jDirectionIncrementInDegrees + if self.iScansNegatively: + i_step = -i_step + if not self.jScansPositively: + j_step = -j_step + self._x_points = (numpy.arange(self.Ni, dtype=numpy.float64) * i_step + + self.longitudeOfFirstGridPointInDegrees) + self._y_points = (numpy.arange(self.Nj, dtype=numpy.float64) * j_step + + self.latitudeOfFirstGridPointInDegrees) + + # circular x coord? + if "longitude" in self.extra_keys['_x_coord_name'] and self.Ni > 1: + # Is the gap from end to start smaller or about equal to the max step? + points = self._x_points + gap = 360.0 - abs(points[-1] - points[0]) + max_step = abs(numpy.diff(points)).max() + if gap <= max_step: + self.extra_keys['_x_circular'] = True + else: + try: + numpy.testing.assert_almost_equal(gap / max_step, 1.0, decimal=3) + self.extra_keys['_x_circular'] = True + except: + pass def _get_processing_done(self): """Determine the type of processing that was done on the data.""" @@ -353,7 +386,8 @@ def _get_processing_done(self): #grib1 if edition == 1: timeRangeIndicator = self.timeRangeIndicator - processingDone = TIME_RANGE_INDICATORS.get(timeRangeIndicator, 'time _grib1_process_unknown_%i' % timeRangeIndicator) + processingDone = TIME_RANGE_INDICATORS.get(timeRangeIndicator, + 'time _grib1_process_unknown_%i' % timeRangeIndicator) #grib2 else: @@ -367,8 +401,8 @@ def _get_processing_done(self): #pdt 4.8? (time-processed) elif pdt == 8: typeOfStatisticalProcessing = self.typeOfStatisticalProcessing - processingDone = PROCESSING_TYPES.get(typeOfStatisticalProcessing, 'time _grib2_process_unknown_%i' % \ - typeOfStatisticalProcessing) + processingDone = PROCESSING_TYPES.get(typeOfStatisticalProcessing, + 'time _grib2_process_unknown_%i' % typeOfStatisticalProcessing) return processingDone @@ -413,10 +447,14 @@ def _get_verification_date(self): time_diff = int(self.stepRange) # gribapi gives us a string! forecast_time_unit = self.indicatorOfUnitOfTimeRange # P1 and P2 units - if forecast_time_unit == 0: verification_date = reference_date_time + datetime.timedelta(0, 0, 0, 0, int(time_diff)) # minutes - elif forecast_time_unit == 1: verification_date = reference_date_time + datetime.timedelta(0, 0, 0, 0, 0, int(time_diff)) # hours - elif forecast_time_unit == 2: verification_date = reference_date_time + datetime.timedelta(int(time_diff)) # days - elif forecast_time_unit == 13: verification_date = reference_date_time + datetime.timedelta(0, int(time_diff)) # seconds + if forecast_time_unit == 0: + verification_date = reference_date_time + datetime.timedelta(0, 0, 0, 0, int(time_diff)) # minutes + elif forecast_time_unit == 1: + verification_date = reference_date_time + datetime.timedelta(0, 0, 0, 0, 0, int(time_diff)) # hours + elif forecast_time_unit == 2: + verification_date = reference_date_time + datetime.timedelta(int(time_diff)) # days + elif forecast_time_unit == 13: + verification_date = reference_date_time + datetime.timedelta(0, int(time_diff)) # seconds else: raise iris.exceptions.TranslationError("Unhandled grib2 unitOfTime = %i" % forecast_time_unit) diff --git a/lib/iris/fileformats/netcdf.py b/lib/iris/fileformats/netcdf.py index 8bb874b151..6dd371fbd0 100644 --- a/lib/iris/fileformats/netcdf.py +++ b/lib/iris/fileformats/netcdf.py @@ -562,6 +562,10 @@ def _create_cf_grid_mapping(dataset, cube, cf_var): # tmerc elif isinstance(cs, iris.coord_systems.TransverseMercator): warnings.warn('TransverseMercator coordinate system not yet handled') + + # osgb (a specific tmerc) + elif isinstance(cs, iris.coord_systems.OSGB): + warnings.warn('OSGB coordinate system not yet handled') # other else: diff --git a/lib/iris/palette.py b/lib/iris/palette.py index a9bfcc3f03..973cfa3912 100644 --- a/lib/iris/palette.py +++ b/lib/iris/palette.py @@ -174,7 +174,7 @@ def __init__(self, pivot, *args, **kwargs): def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self.pivot) - + def _update(self, val, update_min=True, update_max=True): # Update both _vmin and _vmax from given value. val_diff = numpy.abs(val - self.pivot) diff --git a/lib/iris/plot.py b/lib/iris/plot.py index 6023aa1740..255e84884e 100644 --- a/lib/iris/plot.py +++ b/lib/iris/plot.py @@ -18,7 +18,7 @@ Iris-specific extensions to matplotlib, mimicking the :mod:`matplotlib.pyplot` interface. -See also: :ref:`matplotlib `, :ref:`Basemap `. +See also: :ref:`matplotlib `. """ @@ -26,13 +26,17 @@ import datetime import warnings +import matplotlib.axes import matplotlib.collections as mpl_collections import matplotlib.dates as mpl_dates import matplotlib.transforms as mpl_transforms import matplotlib.pyplot as plt -import mpl_toolkits.basemap as basemap from mpl_toolkits.axes_grid.anchored_artists import AnchoredText import numpy +import numpy.ma +import cartopy.crs +import cartopy.mpl_integration.geoaxes + import iris.cube import iris.coord_systems @@ -42,9 +46,6 @@ import iris.unit -# Used to provide a "current" Basemap instance, in the style of pyplot.gcf() and pyplot.gca() -_CURRENT_MAP = None - # Cynthia Brewer citation text. _BREWER = 'Colours based on ColorBrewer.org' @@ -339,6 +340,32 @@ def _draw_1d_from_points(draw_method_name, arg_func, cube, *args, **kwargs): return result +def _get_cartopy_axes(cartopy_proj): + # Replace non-cartopy subplot/axes with a cartopy alternative. + # XXX original subplot properties will be lost... + # XXX consider allowing the axes to be passed through + ax = plt.gca() + if not isinstance(ax, + cartopy.mpl_integration.geoaxes.GenericProjectionAxes): + fig = plt.gcf() + if isinstance(ax, matplotlib.axes.SubplotBase): + new_ax = fig.add_subplot(ax.get_subplotspec(), + projection=cartopy_proj, + title=ax.get_title(), + xlabel=ax.get_xlabel(), + ylabel=ax.get_ylabel()) + else: + new_ax = fig.add_axes(projection=cartopy_proj, + title=ax.get_title(), + xlabel=ax.get_xlabel(), + ylabel=ax.get_ylabel()) + + # delete the axes which didn't have a cartopy projection + fig.delaxes(ax) + ax = new_ax + return ax + + def _map_common(draw_method_name, arg_func, mode, cube, data, *args, **kwargs): """ Draw the given cube on a map using its points or bounds. @@ -346,77 +373,45 @@ def _map_common(draw_method_name, arg_func, mode, cube, data, *args, **kwargs): "Mode" parameter will switch functionality between POINT or BOUND plotting. """ - # get the 2d lons and 2d lats from the CS + # get the 2d x and 2d y from the CS if mode == iris.coords.POINT_MODE: - lats, lons = iris.analysis.cartography.get_lat_lon_grids(cube) + x, y = iris.analysis.cartography.get_xy_grids(cube) else: - lats, lons = iris.analysis.cartography.get_lat_lon_contiguous_bounded_grids(cube) + x, y = iris.analysis.cartography.get_xy_contiguous_bounded_grids(cube) # take a copy of the data so that we can make modifications to it data = data.copy() - # if we are global, then append the first column of data the array to the last (and add 360 degrees) + # If we are global, then append the first column of data the array to the last (and add 360 degrees) # NOTE: if it is found that this block of code is useful in anywhere other than this plotting routine, it # may be better placed in the CS. - lon_coord = filter(lambda coord: coord.standard_name in ["longitude", "grid_longitude"], cube.coords())[0] - if getattr(lon_coord, 'circular', False): - lats = numpy.append(lats, lats[:, 0:1], axis=1) - lons = numpy.append(lons, lons[:, 0:1] + 360, axis=1) + x_coord = cube.coord(axis="X") + if getattr(x_coord, 'circular', False): + _, direction = iris.util.monotonic(x_coord.points, return_direction=True) + y = numpy.append(y, y[:, 0:1], axis=1) + x = numpy.append(x, x[:, 0:1] + 360 * direction, axis=1) data = numpy.ma.concatenate([data, data[:, 0:1]], axis=1) - # Do we need to flip the longitude to avoid basemap's "non positive monotonic" warning? - # Assume we have a non-scalar longitude coord describing a data dimension. - mono, direction = iris.util.monotonic(lons[0, :], return_direction=True) - if mono and direction == -1: - data = data[:, ::-1] - lons = lons[:, ::-1] - lats = lats[:, ::-1] - - # Attempt to mimic the pyplot stateful interface with basemap. - # If the current Basemap instance hasn't been registered on the current axes then - # we assume we've moved to a new axes and create a new map. - bm = _CURRENT_MAP - if bm is None or hash(plt.gca()) not in bm._initialized_axes: - # Provide lat & lon ranges as we have already calculated our lats and lons. - bm = map_setup(cube=cube, lon_range=(numpy.min(lons), numpy.max(lons)), - lat_range=(numpy.min(lats), numpy.max(lats)), ) - - # Convert the lons and lats into the plot coordinates - px, py = bm(lons, lats) + # Replace non-cartopy subplot/axes with a cartopy alternative. + cs = cube.coord_system('CoordSystem') + cartopy_proj = cs.as_cartopy_projection() # E.g. PlateCarree + ax = _get_cartopy_axes(cartopy_proj) - if mode == iris.coords.POINT_MODE: - # TODO #480 Include mdi in this index when it is available - invalid_points = numpy.where((px == 1e+30) | (py == 1e+30) | (numpy.isnan(data))) - data[invalid_points] = numpy.nan - else: - # TODO #480 Include mdi in this index - invalid_points = numpy.where( (px == 1e+30) | (py == 1e+30) ) - - px[invalid_points] = numpy.nan - py[invalid_points] = numpy.nan + draw_method = getattr(ax, draw_method_name) - # Draw the contour lines/filled contours - draw_method = getattr(bm, draw_method_name) + # Set the "from transform" keyword. + # NB. While cartopy doesn't support spherical contours, just use the + # projection as the source CRS. + assert 'transform' not in kwargs, 'Transform keyword is not allowed.' + kwargs['transform'] = cartopy_proj if arg_func is not None: - new_args, kwargs = arg_func(px, py, data, *args, **kwargs) + new_args, kwargs = arg_func(x, y, data, *args, **kwargs) else: - new_args = (px, py, data) + args - - drawn_object = draw_method(*new_args, **kwargs) + new_args = (x, y, data) + args - # if the range of the data is outside the range of the map, then bring the data back 360 degrees and re-plot - if numpy.max(lons) > bm.urcrnrlon: - px, py = bm(lons-360, lats) - if hasattr(drawn_object, 'levels'): - if arg_func is not None: - new_args, kwargs = arg_func(px, py, data, drawn_object.levels, *args, **kwargs) - else: - new_args = (px, py, data, drawn_object.levels) + args - - drawn_object = draw_method(*new_args, **kwargs) - - return drawn_object + # Draw the contour lines/filled contours. + return draw_method(*new_args, **kwargs) @iris.palette.auto_palette @@ -494,104 +489,90 @@ def contourf(cube, *args, **kwargs): return result -def gcm(cube=None): - """Returns the current :class:`mpl_toolkits.basemap.Basemap`, creating a new instance if necessary.""" - if _CURRENT_MAP is None: - map_setup(cube=cube) - return _CURRENT_MAP - - -def map_setup(cube=None, mode=None, lon_range=None, lat_range=None, **kwargs): +def map_setup(projection=None, xlim=None, ylim=None, cube=None, mode=None): """ - Defines the map for the current plot. - - Kwargs: - - * cube: - A cube whose native projection will be used to define the map projection. - - * projection: - Name of the projection to use. Currently only 'cyl', Cylindrical Equidistant, is supported. - - * lon_range: - Longitude range of the map, e.g [lon_min, lon_max]. - - * lat_range: - Latitude range of the map, e.g [lat_min, lat_max]. + Setup matplotlib for cartographic plotting. - * mode: - If *cube* is given, and *lon_range* or *lat_range* are not provided they will be calculated automatically - by looking at the appropriate points/bounds range of the lat/lon coordinates. If latitude or longitude - coordinates have bounds then provide the *mode* keyword to determine whether to use - bounds or points to calculate the latitude/longitude range. - Valid values are iris.coords.POINT_MODE or iris.coords.BOUND_MODE. + The projection is taken from the projection keyword, if present, + otherwise it is taken from the cube, if present, + otherwise it defaults to a PlateCarree projection. - Returns: - Returns a new :class:`mpl_toolkits.basemap.Basemap`. - - """ - global _CURRENT_MAP + The xy limits are taken from the xlim and ylim keywords, if present, + otherwise they are taken from the cube, if present, + otherwise it is left for matplotlib to set limit during the first plot. - # support basemap's keywords urcrnrlat, llcrnrlat, llcrnrlat & llcrnrlat - # but also provide an improved interface using lon_range, lat_range - if (kwargs.has_key('urcrnrlat') or kwargs.has_key('llcrnrlat')) and lat_range is not None: - raise ValueError('Do not specify lat_range when "llcrnrlat" or "urcrnrlat" are set.') + Kwargs: - if (kwargs.has_key('urcrnrlon') or kwargs.has_key('llcrnrlon')) and lon_range is not None: - raise ValueError('Do not specify lon_range when "llcrnrlon" or "urcrnrlon" are set.') + * projection - The projection to use for plotting. + * xlim - x limits + * ylim - y limits + * cube - A cube which can be used for projection and limits. + * mode - Controls min/max calulation for bounded coordinates + (Passed through to :func:`~iris.analysis.cartography.xy_range`). + Set to iris.coords.POINT_MODE or iris.coords.BOUND_MODE. + Default is iris.coords.BOUND_MODE. + + Note: + + There is no need to setup a map in many cases, + as this is done for you by Iris' plotting routines. + + # Unnecessary map_setup + map_setup(cube) + contourf(cube) - # decompose lat_range & lon_range into lat/lon_min/max elements - if lat_range is not None: - lat_min, lat_max = lat_range - else: - lat_min, lat_max = kwargs.get('llcrnrlat'), kwargs.get('urcrnrlat') + Suggested uses of this function are as follows, :: + + # Alternative projection, automatic limits + map_setup(projection) + contourf(cube) - if lon_range is not None: - lon_min, lon_max = lon_range - else: - lon_min, lon_max = kwargs.get('llcrnrlon'), kwargs.get('urcrnrlon') - + # Alternative projection, custom limits + map_setup(projection, xlim, ylim) + contourf(cube) + + # Native projection, custom limits + map_setup(cube, xlim, ylim) + contourf(cube) + + The following snippet is inefficient. + Coordinate transformation is used twice, which is not necessary. :: - if cube is not None: - projection = kwargs.pop('projection', None) - - if len(kwargs) > 0: - raise TypeError('Unsupported keywords to map when cube is provided were given (%s).' % ', '.join(kwargs)) - - # TODO #581 Get the projection from the CS - if projection is None: - projection = 'cyl' + # Transforms to calulate projected extents + map_setup(cube, other_projection) + # Transforms again, for plotting + contourf(cube) - kwargs['projection'] = projection - - if lat_range is None or lon_range is None: - _lat_range, _lon_range = iris.analysis.cartography.lat_lon_range(cube, mode) - - # If the lon/lat_min/max is not none, keep it, otherwise put in the newly calculated range - if lat_min is None: lat_min = _lat_range[0] - if lat_max is None: lat_max = _lat_range[1] - if lon_min is None: lon_min = _lon_range[0] - if lon_max is None: lon_max = _lon_range[1] - - if lon_min is not None: - kwargs['llcrnrlon'] = lon_min - if lon_max is not None: - kwargs['urcrnrlon'] = lon_max + Instead, let the limits be calulated automatically, + as in the suggested usage, above. - # cap the maximum latitude range to -90, +90 - if lat_min is not None: - kwargs['llcrnrlat'] = numpy.max([-90, lat_min]) - if lat_max is not None: - kwargs['urcrnrlat'] = numpy.min([ lat_max, 90]) + """ + # Which projection? + if projection is None and cube is not None: + cs = cube.coord_system("CoordSystem") + projection = cs.as_cartopy_projection() if cs else None + if projection is None: + projection = cartopy.crs.PlateCarree() + + lim_crs = projection - _CURRENT_MAP = basemap.Basemap(**kwargs) + # Which extents? + if (xlim is None or ylim is None) and cube is not None: + mode = mode or iris.coords.BOUND_MODE + extents = iris.analysis.cartography.xy_range(cube, mode, projection) + xlim = extents[0] + ylim = extents[1] + lim_crs = cs.as_cartopy_projection() if cs else None - # Ensure this Basemap instance has registered itself on the current axes. - # This allows routines like iplt.contour to avoid creating a new Basemap instance when - # one has explicitly been created with this routine. - _CURRENT_MAP.set_axes_limits() + ax = _get_cartopy_axes(projection) - return _CURRENT_MAP + if (xlim is not None) != (ylim is not None): + warnings.warn('Both xlim and ylim must currently be set.') + + if xlim is not None: + ax.set_extent(tuple(xlim) + tuple(ylim), lim_crs) + + return ax def _fill_orography(cube, coords, mode, vert_plot, horiz_plot, style_args): @@ -849,7 +830,3 @@ def citation(text, figure=None): anchor.patch.set_boxstyle('round, pad=0, rounding_size=0.2') figure.gca().add_artist(anchor) - - - - diff --git a/lib/iris/quickplot.py b/lib/iris/quickplot.py index f8c848b9f8..b23da7bd9c 100644 --- a/lib/iris/quickplot.py +++ b/lib/iris/quickplot.py @@ -20,7 +20,7 @@ These routines work much like their :mod:`iris.plot` counterparts, but they automatically add a plot title, axis titles, and a colour bar when appropriate. -See also: :ref:`matplotlib `, :ref:`Basemap `. +See also: :ref:`matplotlib `. """ diff --git a/lib/iris/tests/results/visual_tests/test_COP_maps.TestCOPMaps.test_cop_maps.0.png b/lib/iris/tests/results/visual_tests/test_COP_maps.TestCOPMaps.test_cop_maps.0.png index 2443c4a1e1..99ecdaf431 100644 Binary files a/lib/iris/tests/results/visual_tests/test_COP_maps.TestCOPMaps.test_cop_maps.0.png and b/lib/iris/tests/results/visual_tests/test_COP_maps.TestCOPMaps.test_cop_maps.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_TEC.TestTEC.test_TEC.0.png b/lib/iris/tests/results/visual_tests/test_TEC.TestTEC.test_TEC.0.png index 931835c5d6..999d656d08 100644 Binary files a/lib/iris/tests/results/visual_tests/test_TEC.TestTEC.test_TEC.0.png and b/lib/iris/tests/results/visual_tests/test_TEC.TestTEC.test_TEC.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_analysis.TestRotatedPole.test_all.1.png b/lib/iris/tests/results/visual_tests/test_analysis.TestRotatedPole.test_all.1.png index 96e172ca56..4264e76f12 100644 Binary files a/lib/iris/tests/results/visual_tests/test_analysis.TestRotatedPole.test_all.1.png and b/lib/iris/tests/results/visual_tests/test_analysis.TestRotatedPole.test_all.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_analysis.TestRotatedPole.test_all.3.png b/lib/iris/tests/results/visual_tests/test_analysis.TestRotatedPole.test_all.3.png index a7209dc262..b2cc5b6e84 100644 Binary files a/lib/iris/tests/results/visual_tests/test_analysis.TestRotatedPole.test_all.3.png and b/lib/iris/tests/results/visual_tests/test_analysis.TestRotatedPole.test_all.3.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_auto.0.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_auto.0.png index d34d4d6c7f..8263f7e4ee 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_auto.0.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_auto.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_default.0.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_default.0.png index 0f1e84a74c..67a8771765 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_default.0.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_default.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.0.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.0.png index 1d56e600cb..97ef86f6e7 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.0.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.1.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.1.png index b6ae6a2383..3395117ce0 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.1.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.2.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.2.png index eaca968b72..bc6def721d 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.2.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.2.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.3.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.3.png index b00c6fc13e..2ced501ee6 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.3.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_cmap_override.3.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_auto.0.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_auto.0.png index c41b5ae134..11ed9c8e65 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_auto.0.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_auto.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_default.0.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_default.0.png index 1a21897b61..da333c3ca4 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_default.0.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_default.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_override.0.png b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_override.0.png index 74555384e3..1e6058f625 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_override.0.png and b/lib/iris/tests/results/visual_tests/test_cmap_norm.TestCmapNorm.test_norm_override.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_cross_section.TestCrossSection.test_cross_section.1.png b/lib/iris/tests/results/visual_tests/test_cross_section.TestCrossSection.test_cross_section.1.png index f68213d35a..52704882bc 100644 Binary files a/lib/iris/tests/results/visual_tests/test_cross_section.TestCrossSection.test_cross_section.1.png and b/lib/iris/tests/results/visual_tests/test_cross_section.TestCrossSection.test_cross_section.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_custom_file_loading.TestCustomFileLoading.test_global_map.0.png b/lib/iris/tests/results/visual_tests/test_custom_file_loading.TestCustomFileLoading.test_global_map.0.png index c630ea258a..82cfe09a51 100644 Binary files a/lib/iris/tests/results/visual_tests/test_custom_file_loading.TestCustomFileLoading.test_global_map.0.png and b/lib/iris/tests/results/visual_tests/test_custom_file_loading.TestCustomFileLoading.test_global_map.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_deriving_phenomena.TestDerivingPhenomena.test_deriving_phenomena.0.png b/lib/iris/tests/results/visual_tests/test_deriving_phenomena.TestDerivingPhenomena.test_deriving_phenomena.0.png index 3ae8f4d596..391dddeaf7 100644 Binary files a/lib/iris/tests/results/visual_tests/test_deriving_phenomena.TestDerivingPhenomena.test_deriving_phenomena.0.png and b/lib/iris/tests/results/visual_tests/test_deriving_phenomena.TestDerivingPhenomena.test_deriving_phenomena.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_global_map.TestGlobalMap.test_global_map.0.png b/lib/iris/tests/results/visual_tests/test_global_map.TestGlobalMap.test_global_map.0.png index b6c3668a6e..38ec8387ba 100644 Binary files a/lib/iris/tests/results/visual_tests/test_global_map.TestGlobalMap.test_global_map.0.png and b/lib/iris/tests/results/visual_tests/test_global_map.TestGlobalMap.test_global_map.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.0.png b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.0.png index 4f9cf1635d..e6b6f24ca2 100644 Binary files a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.0.png and b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.1.png b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.1.png index d0fd8645e3..869a89028d 100644 Binary files a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.1.png and b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.2.png b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.2.png index ae76b194e6..d10d7117d0 100644 Binary files a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.2.png and b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.2.png differ diff --git a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.3.png b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.3.png index a18c2b39dd..e960864ded 100644 Binary files a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.3.png and b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_ij_directions.3.png differ diff --git a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_y_fastest.0.png b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_y_fastest.0.png index 684bcb03ce..4f2e120690 100644 Binary files a/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_y_fastest.0.png and b/lib/iris/tests/results/visual_tests/test_grib_load.TestGribLoad.test_y_fastest.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_lagged_ensemble.TestLaggedEnsemble.test_lagged_ensemble.0.png b/lib/iris/tests/results/visual_tests/test_lagged_ensemble.TestLaggedEnsemble.test_lagged_ensemble.0.png index a10fa34f21..53bbff7005 100644 Binary files a/lib/iris/tests/results/visual_tests/test_lagged_ensemble.TestLaggedEnsemble.test_lagged_ensemble.0.png and b/lib/iris/tests/results/visual_tests/test_lagged_ensemble.TestLaggedEnsemble.test_lagged_ensemble.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_lagged_ensemble.TestLaggedEnsemble.test_lagged_ensemble.1.png b/lib/iris/tests/results/visual_tests/test_lagged_ensemble.TestLaggedEnsemble.test_lagged_ensemble.1.png index 2a1761355b..a1d74d11ca 100644 Binary files a/lib/iris/tests/results/visual_tests/test_lagged_ensemble.TestLaggedEnsemble.test_lagged_ensemble.1.png and b/lib/iris/tests/results/visual_tests/test_lagged_ensemble.TestLaggedEnsemble.test_lagged_ensemble.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestBasic.test_contourf.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestBasic.test_contourf.0.png index b0e054f87e..5f4a5926de 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestBasic.test_contourf.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestBasic.test_contourf.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestBasic.test_pcolor.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestBasic.test_pcolor.0.png index 08d0708393..10b7802dca 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestBasic.test_pcolor.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestBasic.test_pcolor.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestBoundedCube.test_grid.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestBoundedCube.test_grid.0.png index 48fa896410..78a6a91496 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestBoundedCube.test_grid.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestBoundedCube.test_grid.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestBoundedCube.test_pcolormesh.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestBoundedCube.test_pcolormesh.0.png index 1218fe652e..28d97f3018 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestBoundedCube.test_pcolormesh.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestBoundedCube.test_pcolormesh.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_grid.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_grid.0.png index d9768f8551..592e46e09f 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_grid.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_grid.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_outline.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_outline.0.png index 1c980f7c53..c85122436e 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_outline.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_outline.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_pcolormesh.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_pcolormesh.0.png index c6fef18ad7..113987e556 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_pcolormesh.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_pcolormesh.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_scatter.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_scatter.0.png index ff5d5ec4d8..9cec013fbb 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_scatter.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLimitedAreaCube.test_scatter.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_keywords.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_keywords.0.png index 75602c337a..cd3d849373 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_keywords.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_keywords.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_keywords.1.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_keywords.1.png index cc1aa407e0..e983b86a2d 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_keywords.1.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_keywords.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.0.png index 33551a57d7..808b8dc453 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.1.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.1.png index 75602c337a..cd3d849373 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.1.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.2.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.2.png index 674664e239..f20339f772 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.2.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_params.2.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_simple.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_simple.0.png index fc70b38d6d..a44e5cbbb4 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_simple.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestLowLevel.test_simple.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_mapping.TestMappingSubRegion.test_simple.0.png b/lib/iris/tests/results/visual_tests/test_mapping.TestMappingSubRegion.test_simple.0.png index fed5179af0..4d146a943d 100644 Binary files a/lib/iris/tests/results/visual_tests/test_mapping.TestMappingSubRegion.test_simple.0.png and b/lib/iris/tests/results/visual_tests/test_mapping.TestMappingSubRegion.test_simple.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_plot.TestContour.test_yx.0.png b/lib/iris/tests/results/visual_tests/test_plot.TestContour.test_yx.0.png index fe8bef6d9d..2b80c23c39 100644 Binary files a/lib/iris/tests/results/visual_tests/test_plot.TestContour.test_yx.0.png and b/lib/iris/tests/results/visual_tests/test_plot.TestContour.test_yx.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_plot.TestContourf.test_yx.0.png b/lib/iris/tests/results/visual_tests/test_plot.TestContourf.test_yx.0.png index 2c8370f0b2..9875a5d42a 100644 Binary files a/lib/iris/tests/results/visual_tests/test_plot.TestContourf.test_yx.0.png and b/lib/iris/tests/results/visual_tests/test_plot.TestContourf.test_yx.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_plot.TestPcolor.test_yx.0.png b/lib/iris/tests/results/visual_tests/test_plot.TestPcolor.test_yx.0.png index 6455fa6124..b49516c986 100644 Binary files a/lib/iris/tests/results/visual_tests/test_plot.TestPcolor.test_yx.0.png and b/lib/iris/tests/results/visual_tests/test_plot.TestPcolor.test_yx.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_plot.TestPcolormesh.test_yx.0.png b/lib/iris/tests/results/visual_tests/test_plot.TestPcolormesh.test_yx.0.png index ffeaca6304..9681c897f9 100644 Binary files a/lib/iris/tests/results/visual_tests/test_plot.TestPcolormesh.test_yx.0.png and b/lib/iris/tests/results/visual_tests/test_plot.TestPcolormesh.test_yx.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.1.png b/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.1.png index b0e054f87e..5f4a5926de 100644 Binary files a/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.1.png and b/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.3.png b/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.3.png index 1422bb5525..fc0779aad4 100644 Binary files a/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.3.png and b/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.3.png differ diff --git a/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.5.png b/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.5.png index fddaf94793..5a22f9558f 100644 Binary files a/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.5.png and b/lib/iris/tests/results/visual_tests/test_plot.TestPlotCoordinatesGiven.test_yx.5.png differ diff --git a/lib/iris/tests/results/visual_tests/test_quickplot.TestLabels.test_map.0.png b/lib/iris/tests/results/visual_tests/test_quickplot.TestLabels.test_map.0.png index ceb40f5a24..5c43fa264b 100644 Binary files a/lib/iris/tests/results/visual_tests/test_quickplot.TestLabels.test_map.0.png and b/lib/iris/tests/results/visual_tests/test_quickplot.TestLabels.test_map.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_quickplot.TestLabels.test_map.1.png b/lib/iris/tests/results/visual_tests/test_quickplot.TestLabels.test_map.1.png index 7df34dfcc0..a0b75dc686 100644 Binary files a/lib/iris/tests/results/visual_tests/test_quickplot.TestLabels.test_map.1.png and b/lib/iris/tests/results/visual_tests/test_quickplot.TestLabels.test_map.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.1.png b/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.1.png index 028f308c6b..7d3138cdb9 100644 Binary files a/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.1.png and b/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.3.png b/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.3.png index a4f5d2d097..a0b75dc686 100644 Binary files a/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.3.png and b/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.3.png differ diff --git a/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.5.png b/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.5.png index 5d58d56377..909b3a35e7 100644 Binary files a/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.5.png and b/lib/iris/tests/results/visual_tests/test_quickplot.TestQuickplotCoordinatesGiven.test_yx.5.png differ diff --git a/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.0.png b/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.0.png index 2f6b2a5609..2b47db68df 100644 Binary files a/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.0.png and b/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.0.png differ diff --git a/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.1.png b/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.1.png index 214097e317..11f6db3f16 100644 Binary files a/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.1.png and b/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.1.png differ diff --git a/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.2.png b/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.2.png index ab95e5c82f..70da4e3a01 100644 Binary files a/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.2.png and b/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.2.png differ diff --git a/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.3.png b/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.3.png index b1a426f196..047fa87633 100644 Binary files a/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.3.png and b/lib/iris/tests/results/visual_tests/test_rotated_pole_mapping.TestRotatedPoleMapping.test_rotated_pole_mapping.3.png differ diff --git a/lib/iris/tests/test_analysis.py b/lib/iris/tests/test_analysis.py index 5bf74bc81a..14c4ac0283 100644 --- a/lib/iris/tests/test_analysis.py +++ b/lib/iris/tests/test_analysis.py @@ -239,19 +239,26 @@ def test_min(self): def test_duplicate_coords(self): self.assertRaises(ValueError, tests.stock.track_1d, duplicate_x=True) - def test_lat_lon_range(self): - # Test with non-circular longitude - result_non_circ = iris.analysis.cartography.lat_lon_range(self.cube) - numpy.testing.assert_array_almost_equal(result_non_circ, ((15, 77), (-88, 72)), decimal=0) - - # Set longitude to be circular - self.cube.coord('grid_longitude').circular = True - result_circ = iris.analysis.cartography.lat_lon_range(self.cube) - - # lon range of circular coord grid_longitude will be approx -88 + 360 = 272 - numpy.testing.assert_array_almost_equal(result_circ, ((15, 77), (-88, 272)), decimal=0) - - # Test with non geodetic coords + def test_xy_range(self): + result_non_circ = iris.analysis.cartography.xy_range(self.cube) + self.assertEqual(self.cube.coord('grid_longitude').circular, False) + numpy.testing.assert_array_almost_equal( + result_non_circ, ((313.02, 392.11), (-22.49, 24.92)), decimal=0) + + def test_xy_range_geog_cs(self): + cube = iris.tests.stock.global_pp() + self.assertTrue(cube.coord('longitude').circular) + result = iris.analysis.cartography.xy_range(cube) + numpy.testing.assert_array_almost_equal( + result, ((0, 360), (-90, 90)), decimal=0) + + def test_xy_range_geog_cs_regional(self): + cube = iris.tests.stock.global_pp() + cube = cube[10:20, 20:30] + self.assertFalse(cube.coord('longitude').circular) + result = iris.analysis.cartography.xy_range(cube) + numpy.testing.assert_array_almost_equal( + result, ((75, 108.75), (42.5, 65)), decimal=0) class TestMissingData(tests.IrisTest): @@ -370,13 +377,14 @@ def test_count_2d(self): @iris.tests.skip_data class TestRotatedPole(tests.IrisTest): def _check_both_conversions(self, cube): - lats, lons = iris.analysis.cartography.get_lat_lon_grids(cube) - plt.scatter(lons, lats) + rlons, rlats = iris.analysis.cartography.get_xy_grids(cube) + rcs = cube.coord_system('RotatedGeogCS') + x, y = iris.analysis.cartography.unrotate_pole(rlons, rlats, + rcs.grid_north_pole_longitude, + rcs.grid_north_pole_latitude) + plt.scatter(x, y) self.check_graphic() - grid_north_pole_latitude = cube.coord_system('RotatedGeogCS').grid_north_pole_latitude - grid_north_pole_longitude = cube.coord_system('RotatedGeogCS').grid_north_pole_longitude - rlons, rlats = iris.analysis.cartography.rotate_pole(lons, lats, grid_north_pole_longitude, grid_north_pole_latitude) plt.scatter(rlons, rlats) self.check_graphic() diff --git a/lib/iris/tests/test_cmap_norm.py b/lib/iris/tests/test_cmap_norm.py index a53d30c117..73b4381600 100644 --- a/lib/iris/tests/test_cmap_norm.py +++ b/lib/iris/tests/test_cmap_norm.py @@ -67,6 +67,7 @@ def test_norm_default(self): def test_norm_override(self): self.cube.standard_name += '_anomaly' + # The data range is 245 to 305 norm = iris.palette.SymmetricNormalize(pivot=200) iplt.contourf(self.cube, norm=norm) self.check_graphic() diff --git a/lib/iris/tests/test_grib_load.py b/lib/iris/tests/test_grib_load.py index f365591cb0..aa8bc09057 100644 --- a/lib/iris/tests/test_grib_load.py +++ b/lib/iris/tests/test_grib_load.py @@ -50,7 +50,7 @@ def test_y_fastest(self): cubes = iris.load(tests.get_data_path(("GRIB", "y_fastest", "y_fast.grib2"))) self.assertCML(cubes, ("grib_load", "y_fastest.cml")) iplt.contourf(cubes[0]) - iplt.gcm(cubes[0]).drawcoastlines() + plt.gca().coastlines() plt.title("y changes fastest") self.check_graphic() @@ -63,28 +63,28 @@ def old_compat_load(name): cubes = old_compat_load("ipos_jpos.grib2") self.assertCML(cubes, ("grib_load", "ipos_jpos.cml")) iplt.contourf(cubes[0]) - iplt.gcm(cubes[0]).drawcoastlines() + plt.gca().coastlines() plt.title("ipos_jpos cube") self.check_graphic() cubes = old_compat_load("ipos_jneg.grib2") self.assertCML(cubes, ("grib_load", "ipos_jneg.cml")) iplt.contourf(cubes[0]) - iplt.gcm(cubes[0]).drawcoastlines() + plt.gca().coastlines() plt.title("ipos_jneg cube") self.check_graphic() cubes = old_compat_load("ineg_jneg.grib2") self.assertCML(cubes, ("grib_load", "ineg_jneg.cml")) iplt.contourf(cubes[0]) - iplt.gcm(cubes[0]).drawcoastlines() + plt.gca().coastlines() plt.title("ineg_jneg cube") self.check_graphic() cubes = old_compat_load("ineg_jpos.grib2") self.assertCML(cubes, ("grib_load", "ineg_jpos.cml")) iplt.contourf(cubes[0]) - iplt.gcm(cubes[0]).drawcoastlines() + plt.gca().coastlines() plt.title("ineg_jpos cube") self.check_graphic() diff --git a/lib/iris/tests/test_mapping.py b/lib/iris/tests/test_mapping.py index 926316812c..2261951219 100644 --- a/lib/iris/tests/test_mapping.py +++ b/lib/iris/tests/test_mapping.py @@ -24,6 +24,7 @@ import matplotlib.pyplot as plt import numpy +import cartopy.crs as ccrs import iris import iris.coord_systems @@ -69,8 +70,9 @@ def setUp(self): def test_simple(self): iplt.contourf(self.cube) self.check_graphic() - + +# TODO: Remove def _pretend_unrotated(cube): lat = cube.coord('grid_latitude') lon = cube.coord('grid_longitude') @@ -91,52 +93,36 @@ class TestMappingSubRegion(tests.IrisTest): def setUp(self): cube_path = tests.get_data_path(('PP', 'aPProt1', 'rotatedMHtimecube.pp')) cube = iris.load_strict(cube_path)[0] - - # Until there is better mapping support for rotated-pole, pretend this isn't rotated. - # ie. Move the pole from (37.5, 177.5) to (90, 0) and bodge the coordinates. - _pretend_unrotated(cube) - - self.cube = cube + # make the data slighly smaller to speed things up... + self.cube = cube[::10, ::10] def test_simple(self): # First sub-plot plt.subplot(221) plt.title('Default') - iplt.contourf(self.cube) - - map = iplt.gcm() - map.drawcoastlines() + plt.gca().coastlines() # Second sub-plot plt.subplot(222) plt.title('Molleweide') - - iplt.map_setup(projection='moll', lon_0=120) + iplt.map_setup(projection=ccrs.Mollweide(central_longitude=120)) iplt.contourf(self.cube) - - map = iplt.gcm() - map.drawcoastlines() + plt.gca().coastlines() # Third sub-plot plt.subplot(223) plt.title('Native') - - iplt.map_setup(cube=self.cube) - iplt.contourf(self.cube) - - map = iplt.gcm() - map.drawcoastlines() - + ax = iplt.map_setup(cube=self.cube) + iplt.contour(self.cube) + ax.coastlines() + # Fourth sub-plot plt.subplot(224) - plt.title('Three/six level') - - iplt.contourf(self.cube, 3) - iplt.contour(self.cube, 6) - - map = iplt.gcm() - map.drawcoastlines() + plt.title('PlateCarree') + ax = plt.subplot(2, 2, 4, projection=ccrs.PlateCarree()) + iplt.contourf(self.cube) + ax.coastlines() self.check_graphic() @@ -154,7 +140,7 @@ def test_simple(self): self.check_graphic() def test_params(self): - c = iplt.contourf(self.cube, self.few) + iplt.contourf(self.cube, self.few) self.check_graphic() iplt.contourf(self.cube, self.few_levels) @@ -181,6 +167,8 @@ def setUp(self): self.cube.coord('longitude').guess_bounds() def test_pcolormesh(self): + # pcolormesh can only be drawn in native coordinates (or more specifically, in coordinates that don't wrap). + plt.axes(projection=ccrs.PlateCarree(central_longitude=180)) iplt.pcolormesh(self.cube) self.check_graphic() @@ -212,9 +200,8 @@ def test_outline(self): self.check_graphic() def test_scatter(self): - iplt.points(self.cube) - map = iplt.gcm() - map.drawcoastlines() + scatter = iplt.points(self.cube) + plt.gca().coastlines() self.check_graphic() diff --git a/lib/iris/tests/test_plot.py b/lib/iris/tests/test_plot.py index 5f0b8ed26d..64eeabb234 100644 --- a/lib/iris/tests/test_plot.py +++ b/lib/iris/tests/test_plot.py @@ -19,6 +19,8 @@ # import iris tests first so that some things can be initialised before importing anything else import iris.tests as tests +import warnings + import matplotlib.pyplot as plt import numpy @@ -175,7 +177,6 @@ class SliceMixin(object): def test_yx(self): cube = self.wind[0, 0, :, :] - iplt.map_setup(cube=cube, mode=coords.POINT_MODE) self.draw_method(cube) self.check_graphic() @@ -288,35 +289,6 @@ def setUp(self): self.draw_method = qplt.plot -@iris.tests.skip_data -class TestFillContinents(tests.GraphicsTest): - def setUp(self): - datafile = tests.get_data_path(('PP', 'itam', 'WO0000000000934', 'NAE.20100908_00_an.pp')) - self.cube = iris.load(datafile)[0] - # scale down the data by 100 - self.cube.data = self.cube.data/100.0 - - def test_fillcontinents_underneath(self): - - # setup the map and plot output - current_map = iris.plot.map_setup(resolution='i', lon_range=[-70, 70], lat_range=[25, 75], projection='merc') - current_map.drawcoastlines() - current_map.fillcontinents(color='green', lake_color='aqua', zorder=0) - iris.plot.contourf(self.cube) - - self.check_graphic() - - def test_fillcontinents_ontop(self): - - # setup the map and plot output - current_map = iris.plot.map_setup(resolution='i', lon_range=[-70, 70], lat_range=[25, 75], projection='merc') - current_map.drawcoastlines() - current_map.fillcontinents(color='green', lake_color='aqua', zorder=3) - iris.plot.contourf(self.cube) - - self.check_graphic() - - _load_strict_once_cache = {}