Esempio n. 1
0
def make_polygon(lons, lats, name, author, tags):
    fc = FeatureCollection()

    coords = list()
    for index in range(len(lons)):
        coords.append([lons[index], lats[index]])
    coords.append([lons[0], lats[0]])

    fc.add_feature({
        "type": "Feature",
        "properties": {
            "name": name,
            "author": author,
            "object": 'region',
            "component": 'ocean',
            "tags": tags,
            "zmin": -1500.,
            "zmax": -200.
        },
        "geometry": {
            "type": "Polygon",
            "coordinates": [coords]
        }
    })
    return fc
Esempio n. 2
0
def get_longest_contour(contourValue, author):
    def stereo_to_lon_lat(x, y):
        return pyproj.transform(inProj, outProj, x, y)

    ds = xarray.open_dataset('bedmap2.nc')

    # plot contours
    plt.figure()
    cs = plt.contour(ds.x.values, ds.y.values, ds.bed, (contourValue, ))
    paths = cs.collections[0].get_paths()

    pathLengths = [len(paths[i]) for i in range(len(paths))]
    iLongest = numpy.argmax(pathLengths)

    p = paths[iLongest]
    v = p.vertices
    x = v[:, 0]
    y = v[:, 1]

    # Antarctic stereographic
    inProj = pyproj.Proj(init='epsg:3031')
    # lon/lat
    outProj = pyproj.Proj(init='epsg:4326')
    lon, lat = pyproj.transform(inProj, outProj, x, y)

    poly = shapely.geometry.Polygon([(i[0], i[1]) for i in zip(x, y)])

    epsilon = 1e-14
    minY = numpy.amin(y)
    wedge = shapely.geometry.Polygon([(epsilon, minY), (epsilon**2, -epsilon),
                                      (0, epsilon), (-epsilon**2, -epsilon),
                                      (-epsilon, minY), (epsilon, minY)])

    difference = poly.difference(wedge)

    difference = shapely.ops.transform(stereo_to_lon_lat, difference)

    x, y = difference.exterior.xy

    plt.figure()
    plt.plot(x, y)

    fc = FeatureCollection()

    geometry = shapely.geometry.mapping(difference)
    # get rid of the wedge again by rounding the coordinates
    geometry['coordinates'] = _round_coords(geometry['coordinates'])

    fc.add_feature({
        "type": "Feature",
        "properties": {
            "name": "Contour {}".format(contourValue),
            "author": author,
            "object": 'region',
            "component": 'ocean'
        },
        "geometry": geometry
    })

    return fc
Esempio n. 3
0
def remove_small_polygons(fc, minArea):
    '''
    A helper function to remove small polygons from a feature collection

    Parameters
    ----------
    fc : ``FeatureCollection``
        The feature collection to remove polygons from

    minArea : float
        The minimum area (in square degrees) below which polygons should be
        removed

    Returns
    -------
    fcOut : ``FeatureCollection``
        The new feature collection with small polygons removed
    '''
    # Authors
    # -------
    # Xylar Asay-Davis

    fcOut = FeatureCollection()

    removedCount = 0
    for feature in fc.features:
        geom = feature['geometry']
        if geom['type'] not in ['Polygon', 'MultiPolygon']:
            # no area to check, so just add it
            fcOut.add_feature(copy.deepcopy(feature))
        else:
            add = False
            featureShape = shapely.geometry.shape(geom)
            if featureShape.type == 'Polygon':
                if featureShape.area > minArea:
                    add = True
                else:
                    removedCount += 1
            else:
                # a MultiPolygon
                outPolygons = []
                for polygon in featureShape:
                    if polygon.area > minArea:
                        outPolygons.append(polygon)
                    else:
                        removedCount += 1
                if len(outPolygons) > 0:
                    outShape = shapely.ops.cascaded_union(outPolygons)
                    feature['geometry'] = shapely.geometry.mapping(outShape)
                    add = True
        if add:
            fcOut.add_feature(copy.deepcopy(feature))
        else:
            print("{} has been removed.".format(
                feature['pproperties']['name']))

    print(' * Removed {} small polygons'.format(removedCount))

    return fcOut
Esempio n. 4
0
def make_rectangle(lon0, lon1, lat0, lat1, name, author, tags):
    fc = FeatureCollection()

    fc.add_feature(
        {"type": "Feature",
         "properties": {"name": name,
                        "author": author,
                        "object": 'region',
                        "component": 'ocean',
                        "tags": tags},
         "geometry": {
             "type": "Polygon",
             "coordinates": [[[lon0, lat0],
                              [lon1, lat0],
                              [lon1, lat1],
                              [lon0, lat1],
                              [lon0, lat0]]]}})
    return fc
    def run_task(self):  # {{{
        """
        Plots time-series output of properties in an ocean region.
        """
        # Authors
        # -------
        # Xylar Asay-Davis

        self.logger.info("\nPlotting TS diagram for {}"
                         "...".format(self.regionName))

        register_custom_colormaps()

        config = self.config
        sectionName = self.sectionName

        startYear = self.mpasClimatologyTask.startYear
        endYear = self.mpasClimatologyTask.endYear

        regionMaskSuffix = config.getExpression(sectionName,
                                                'regionMaskSuffix')

        regionMaskFile = get_region_mask(config,
                                         '{}.geojson'.format(regionMaskSuffix))

        fcAll = read_feature_collection(regionMaskFile)

        fc = FeatureCollection()
        for feature in fcAll.features:
            if feature['properties']['name'] == self.regionName:
                fc.add_feature(feature)
                break

        self.logger.info('  Make plots...')

        groupLink = 'tsDiag' + self.regionGroup[0].lower() + \
            self.regionGroup[1:].replace(' ', '')

        nSubplots = 1 + len(self.obsDicts)
        if self.controlConfig is not None:
            nSubplots += 1

        if nSubplots == 4:
            nCols = 2
            nRows = 2
        else:
            nCols = min(nSubplots, 3)
            nRows = (nSubplots - 1) // 3 + 1

        axisIndices = numpy.reshape(numpy.arange(nRows * nCols),
                                    (nRows, nCols))[::-1, :].ravel()

        titleFontSize = config.get('plot', 'titleFontSize')
        axis_font = {'size': config.get('plot', 'axisFontSize')}
        title_font = {
            'size': titleFontSize,
            'color': config.get('plot', 'titleFontColor'),
            'weight': config.get('plot', 'titleFontWeight')
        }

        width = 3 + 4.5 * nCols
        height = 2 + 4 * nRows

        # noinspection PyTypeChecker
        fig, axarray = plt.subplots(nrows=nRows,
                                    ncols=nCols,
                                    sharey=True,
                                    figsize=(width, height))

        if nSubplots == 1:
            axarray = numpy.array(axarray)

        if nRows == 1:
            axarray = axarray.reshape((nRows, nCols))

        T, S, zMid, volume, zmin, zmax = self._get_mpas_t_s(self.config)
        mainRunName = config.get('runs', 'mainRunName')
        plotFields = [{
            'S': S,
            'T': T,
            'z': zMid,
            'vol': volume,
            'title': mainRunName
        }]

        if self.controlConfig is not None:
            T, S, zMid, volume, _, _ = self._get_mpas_t_s(self.controlConfig)
            controlRunName = self.controlConfig.get('runs', 'mainRunName')
            plotFields.append({
                'S': S,
                'T': T,
                'z': zMid,
                'vol': volume,
                'title': 'Control: {}'.format(controlRunName)
            })

        for obsName in self.obsDicts:
            obsT, obsS, obsZ, obsVol = self._get_obs_t_s(
                self.obsDicts[obsName])
            plotFields.append({
                'S': obsS,
                'T': obsT,
                'z': obsZ,
                'vol': obsVol,
                'title': obsName
            })

        Tbins = config.getExpression(sectionName, 'Tbins', usenumpyfunc=True)
        Sbins = config.getExpression(sectionName, 'Sbins', usenumpyfunc=True)

        normType = config.get(sectionName, 'normType')

        PT, SP = numpy.meshgrid(Tbins, Sbins)
        SA = gsw.SA_from_SP(SP, p=0., lon=0., lat=-75.)
        CT = gsw.CT_from_t(SA, PT, p=0.)

        neutralDensity = sigma0(SA, CT)
        rhoInterval = config.getfloat(sectionName, 'rhoInterval')
        contours = numpy.arange(24., 29. + rhoInterval, rhoInterval)

        diagramType = config.get(sectionName, 'diagramType')
        if diagramType not in ['volumetric', 'scatter']:
            raise ValueError('Unexpected diagramType {}'.format(diagramType))

        lastPanel = None
        volMinMpas = None
        volMaxMpas = None
        for index in range(len(axisIndices)):
            panelIndex = axisIndices[index]

            row = nRows - 1 - index // nCols
            col = numpy.mod(index, nCols)

            if panelIndex >= nSubplots:
                plt.delaxes(axarray[row, col])
                continue

            plt.sca(axarray[row, col])
            T = plotFields[index]['T']
            S = plotFields[index]['S']
            z = plotFields[index]['z']
            volume = plotFields[index]['vol']
            title = plotFields[index]['title']

            CS = plt.contour(SP,
                             PT,
                             neutralDensity,
                             contours,
                             linewidths=1.,
                             colors='k',
                             zorder=2)
            plt.clabel(CS, fontsize=12, inline=1, fmt='%4.2f')

            if diagramType == 'volumetric':
                lastPanel, volMin, volMax = \
                    self._plot_volumetric_panel(T, S, volume)

                if index == 0:
                    volMinMpas = volMin
                    volMaxMpas = volMax
                if normType == 'linear':
                    norm = colors.Normalize(vmin=0., vmax=volMaxMpas)
                elif normType == 'log':
                    if volMinMpas is None or volMaxMpas is None:
                        norm = None
                    else:
                        norm = colors.LogNorm(vmin=volMinMpas, vmax=volMaxMpas)
                else:
                    raise ValueError(
                        'Unsupported normType {}'.format(normType))
                if norm is not None:
                    lastPanel.set_norm(norm)
            else:
                lastPanel = self._plot_scatter_panel(T, S, z, zmin, zmax)

            CTFreezing = freezing.CT_freezing(Sbins, 0, 1)
            PTFreezing = gsw.t_from_CT(gsw.SA_from_SP(Sbins,
                                                      p=0.,
                                                      lon=0.,
                                                      lat=-75.),
                                       CTFreezing,
                                       p=0.)
            plt.plot(Sbins,
                     PTFreezing,
                     linestyle='--',
                     linewidth=1.,
                     color='k')

            plt.ylim([Tbins[0], Tbins[-1]])
            plt.xlim([Sbins[0], Sbins[-1]])

            plt.xlabel('Salinity (PSU)', **axis_font)
            if col == 0:
                plt.ylabel(r'Potential temperature ($^\circ$C)', **axis_font)
            plt.title(title)

        # do this before the inset because otherwise it moves the inset
        # and cartopy doesn't play too well with tight_layout anyway
        plt.tight_layout()

        fig.subplots_adjust(right=0.91)
        if nRows == 1:
            fig.subplots_adjust(top=0.85)
        else:
            fig.subplots_adjust(top=0.88)

        suptitle = 'T-S diagram for {} ({}, {:04d}-{:04d})\n' \
                   ' {} m < z < {} m'.format(self.regionName, self.season,
                                             startYear, endYear, zmin, zmax)
        fig.text(0.5,
                 0.9,
                 suptitle,
                 horizontalalignment='center',
                 **title_font)

        inset = add_inset(fig, fc, width=1.5, height=1.5)

        # move the color bar down a little ot avoid the inset
        pos0 = inset.get_position()
        pos1 = axarray[-1, -1].get_position()
        pad = 0.04
        top = pos0.y0 - pad
        height = top - pos1.y0
        cbar_ax = fig.add_axes([0.92, pos1.y0, 0.02, height])
        cbar = fig.colorbar(lastPanel, cax=cbar_ax)

        if diagramType == 'volumetric':
            cbar.ax.get_yaxis().labelpad = 15
            cbar.ax.set_ylabel(r'volume (m$^3$)', rotation=270)
        else:
            cbar.ax.set_ylabel('depth (m)', rotation=270)

        outFileName = '{}/TS_diagram_{}_{}.png'.format(self.plotsDirectory,
                                                       self.prefix,
                                                       self.season)
        savefig(outFileName, tight=False)

        caption = 'Regional mean of {}'.format(suptitle)
        write_image_xml(config=config,
                        filePrefix='TS_diagram_{}_{}'.format(
                            self.prefix, self.season),
                        componentName='Ocean',
                        componentSubdirectory='ocean',
                        galleryGroup='T-S Diagrams',
                        groupLink=groupLink,
                        gallery=self.regionGroup,
                        thumbnailDescription=self.regionName,
                        imageDescription=caption,
                        imageCaption=caption)
    def run_task(self):  # {{{
        """
        Plots time-series output of properties in an ocean region.
        """
        # Authors
        # -------
        # Xylar Asay-Davis

        self.logger.info("\nPlotting time series of ocean properties of {}"
                         "...".format(self.regionName))

        self.logger.info('  Load time series...')

        config = self.config
        calendar = self.calendar

        regionMaskSuffix = config.getExpression(self.sectionName,
                                                'regionMaskSuffix')

        regionMaskFile = get_region_mask(config,
                                         '{}.geojson'.format(regionMaskSuffix))

        fcAll = read_feature_collection(regionMaskFile)

        fc = FeatureCollection()
        for feature in fcAll.features:
            if feature['properties']['name'] == self.regionName:
                fc.add_feature(feature)
                break

        baseDirectory = build_config_full_path(config, 'output',
                                               'timeSeriesSubdirectory')

        startYear = config.getint('timeSeries', 'startYear')
        endYear = config.getint('timeSeries', 'endYear')
        regionGroup = self.regionGroup
        timeSeriesName = regionGroup[0].lower() + \
            regionGroup[1:].replace(' ', '')

        inFileName = '{}/{}/{}_{:04d}-{:04d}.nc'.format(
            baseDirectory, timeSeriesName, timeSeriesName, startYear, endYear)

        dsIn = xarray.open_dataset(inFileName).isel(nRegions=self.regionIndex)

        zbounds = dsIn.zbounds.values

        controlConfig = self.controlConfig
        plotControl = controlConfig is not None
        if plotControl:
            controlRunName = controlConfig.get('runs', 'mainRunName')
            baseDirectory = build_config_full_path(controlConfig, 'output',
                                                   'timeSeriesSubdirectory')

            startYear = controlConfig.getint('timeSeries', 'startYear')
            endYear = controlConfig.getint('timeSeries', 'endYear')

            inFileName = '{}/{}/{}_{:04d}-{:04d}.nc'.format(
                baseDirectory, timeSeriesName, timeSeriesName, startYear,
                endYear)
            dsRef = xarray.open_dataset(inFileName).isel(
                nRegions=self.regionIndex)

            zboundsRef = dsRef.zbounds.values

        mainRunName = config.get('runs', 'mainRunName')
        movingAverageMonths = 1

        self.logger.info('  Make plots...')

        groupLink = self.regionGroup[0].lower() + \
            self.regionGroup[1:].replace(' ', '')

        for var in self.variables:
            varName = var['name']
            mainArray = dsIn[varName]
            is3d = mainArray.attrs['is3d'] == 'True'
            if is3d:
                title = 'Volume-Mean {} in {}'.format(var['title'],
                                                      self.regionName)
            else:
                title = 'Area-Mean {} in {}'.format(var['title'],
                                                    self.regionName)

            if plotControl:
                refArray = dsRef[varName]
            xLabel = 'Time (yr)'
            yLabel = '{} ({})'.format(var['title'], var['units'])

            filePrefix = '{}_{}'.format(self.prefix, varName)
            outFileName = '{}/{}.png'.format(self.plotsDirectory, filePrefix)

            fields = [mainArray]
            lineColors = ['k']
            lineWidths = [2.5]
            legendText = [mainRunName]
            if plotControl:
                fields.append(refArray)
                lineColors.append('r')
                lineWidths.append(1.2)
                legendText.append(controlRunName)

            if is3d:
                if not plotControl or numpy.all(zbounds == zboundsRef):
                    title = '{} ({} < z < {} m)'.format(
                        title, zbounds[0], zbounds[1])
                else:
                    legendText[0] = '{} ({} < z < {} m)'.format(
                        legendText[0], zbounds[0], zbounds[1])
                    legendText[1] = '{} ({} < z < {} m)'.format(
                        legendText[1], zboundsRef[0], zboundsRef[1])

            fig = timeseries_analysis_plot(
                config,
                fields,
                calendar=calendar,
                title=title,
                xlabel=xLabel,
                ylabel=yLabel,
                movingAveragePoints=movingAverageMonths,
                lineColors=lineColors,
                lineWidths=lineWidths,
                legendText=legendText)

            # do this before the inset because otherwise it moves the inset
            # and cartopy doesn't play too well with tight_layout anyway
            plt.tight_layout()

            add_inset(fig, fc, width=2.0, height=2.0)

            savefig(outFileName, tight=False)

            caption = 'Regional mean of {}'.format(title)
            write_image_xml(config=config,
                            filePrefix=filePrefix,
                            componentName='Ocean',
                            componentSubdirectory='ocean',
                            galleryGroup='{} Time Series'.format(
                                self.regionGroup),
                            groupLink=groupLink,
                            gallery=var['title'],
                            thumbnailDescription=self.regionName,
                            imageDescription=caption,
                            imageCaption=caption)
Esempio n. 7
0
    def run_task(self):  # {{{
        """
        Plot a depth profile with variability
        """
        # Authors
        # -------
        # Xylar Asay-Davis

        config = self.config
        startYear = self.startYear
        endYear = self.endYear

        regionMaskFile = self.masksSubtask.geojsonFileName

        fcAll = read_feature_collection(regionMaskFile)

        fc = FeatureCollection()
        for feature in fcAll.features:
            if feature['properties']['name'] == self.regionName:
                fc.add_feature(feature)
                break

        inDirectory = build_config_full_path(config, 'output',
                                             'profilesSubdirectory')
        timeSeriesName = self.timeSeriesName
        inFileName = '{}/{}_{}_{:04d}-{:04d}.nc'.format(
            inDirectory, timeSeriesName, self.season,
            self.startYear, self.endYear)

        regionGroup = self.masksSubtask.regionGroup
        regionGroupSection = 'profiles{}'.format(
            regionGroup.replace(' ', ''))

        ds = xr.open_dataset(inFileName)
        allRegionNames = decode_strings(ds.regionNames)

        regionIndex = allRegionNames.index(self.regionName)
        ds = ds.isel(nRegions=regionIndex)
        meanFieldName = '{}_mean'.format(self.field['prefix'])
        stdFieldName = '{}_std'.format(self.field['prefix'])

        mainRunName = config.get('runs', 'mainRunName')
        profileGalleryGroup = config.get(regionGroupSection,
                                         'profileGalleryGroup')

        titleFieldName = self.field['titleName']
        regionName = self.regionName.replace('_', ' ')

        xLabel = '{} ({})'.format(titleFieldName, self.field['units'])
        yLabel = 'depth (m)'
        outFileName = '{}/{}.png'.format(self.plotsDirectory, self.filePrefix)
        lineColors = ['k']
        lineWidths = [1.6]
        zArrays = [ds.z.values]
        fieldArrays = [ds[meanFieldName].values]
        errArrays = [ds[stdFieldName].values]
        if self.controlConfig is None:
            title = '{} {}, years {:04d}-{:04d}\n{}'.format(
                regionName, self.season, startYear, endYear, mainRunName)
            legendText = [None]
        else:
            controlStartYear = self.controlConfig.getint('climatology',
                                                         'startYear')
            controlEndYear = self.controlConfig.getint('climatology',
                                                       'endYear')
            controlRunName = self.controlConfig.get('runs', 'mainRunName')

            if controlStartYear == startYear and controlEndYear == endYear:
                title = '{} {}, years {:04d}-{:04d}'.format(
                    regionName, self.season, startYear, endYear)
                legendText = [mainRunName, controlRunName]
            elif mainRunName == controlRunName:
                title = '{} {}\n{}'.format(
                    regionName, self.season, mainRunName)
                legendText = ['{:04d}-{:04d}'.format(startYear, endYear),
                              '{:04d}-{:04d}'.format(controlStartYear,
                                                     controlEndYear)]
            else:
                title = '{} {}   '.format(regionName, self.season)
                legendText = ['{} {:04d}-{:04d}'.format(mainRunName, startYear,
                                                        endYear),
                              '{} {:04d}-{:04d}'.format(controlRunName,
                                                        controlStartYear,
                                                        controlEndYear)]

            controlDirectory = build_config_full_path(
                self.controlConfig, 'output',
                'profilesSubdirectory')

            controlFileName = \
                '{}/{}_{}_{:04d}-{:04d}.nc'.format(
                    controlDirectory, timeSeriesName, self.season,
                    controlStartYear, controlEndYear)

            dsControl = xr.open_dataset(controlFileName)
            allRegionNames = decode_strings(dsControl.regionNames)
            regionIndex = allRegionNames.index(self.regionName)
            dsControl = dsControl.isel(nRegions=regionIndex)

            lineColors.append('r')
            lineWidths.append(1.2)
            zArrays.append(dsControl.z.values)
            fieldArrays.append(dsControl[meanFieldName].values)
            errArrays.append(dsControl[stdFieldName].values)

        depthRange = config.getExpression(regionGroupSection, 'depthRange')
        if len(depthRange) == 0:
            depthRange = None

        fig = self.plot(zArrays, fieldArrays, errArrays,
                        lineColors=lineColors, lineWidths=lineWidths,
                        legendText=legendText, title=title, xLabel=xLabel,
                        yLabel=yLabel, yLim=depthRange)

        # do this before the inset because otherwise it moves the inset
        # and cartopy doesn't play too well with tight_layout anyway
        plt.tight_layout()

        add_inset(fig, fc, width=1.0, height=1.0)

        savefig(outFileName, tight=False)

        caption = '{} {} vs depth'.format(regionName, titleFieldName)
        write_image_xml(
            config=config,
            filePrefix=self.filePrefix,
            componentName='Ocean',
            componentSubdirectory='ocean',
            galleryGroup=profileGalleryGroup,
            groupLink='ocnregprofs',
            imageDescription=caption,
            imageCaption=caption,
            gallery=titleFieldName,
            thumbnailDescription='{} {}'.format(regionName, self.season))
    iceMask = numpy.logical_or(iceMask, bedMask)
    groundedMask = numpy.logical_or(groundedMask, bedMask)

    masks = dict()
    masks['AntarcticIceCoverage'] = iceMask
    masks['AntarcticGroundedIceCoverage'] = groundedMask
    fc = FeatureCollection()
    for name in masks:

        properties = dict()
        properties['name'] = name
        properties['component'] = 'bedmachine'
        properties['author'] = \
            'Morlighem et al. (2019) doi:10.1038/s41561-019-0510-8'
        properties['object'] = 'region'
        properties['tags'] = ''
        feature = dict()
        feature['properties'] = properties
        feature['geometry'] = extract_geometry(masks[name])
        fc.add_feature(feature)

    fc.to_geojson(out_file_name)

gf = GeometricFeatures(cacheLocation='./geometric_data')
gf.split(fc)
write_feature_names_and_tags(gf.cacheLocation)

os.rename('features_and_tags.json',
          'geometric_features/features_and_tags.json')
Esempio n. 9
0
    def run_task(self):  # {{{
        """
        Plots time-series output of Antarctic sub-ice-shelf melt rates.
        """
        # Authors
        # -------
        # Xylar Asay-Davis, Stephen Price

        self.logger.info("\nPlotting Antarctic melt rate time series for "
                         "{}...".format(self.iceShelf))

        self.logger.info('  Load melt rate data...')

        config = self.config
        calendar = self.calendar

        iceShelfMasksFile = self.iceShelfMasksFile

        fcAll = read_feature_collection(iceShelfMasksFile)

        fc = FeatureCollection()
        for feature in fcAll.features:
            if feature['properties']['name'] == self.iceShelf:
                fc.add_feature(feature)
                break

        totalMeltFlux, meltRates = self._load_ice_shelf_fluxes(config)

        plotControl = self.controlConfig is not None
        if plotControl:
            controlRunName = self.controlConfig.get('runs', 'mainRunName')

            refTotalMeltFlux, refMeltRates = \
                self._load_ice_shelf_fluxes(self.controlConfig)

        # Load observations from multiple files and put in dictionary based
        # on shelf keyname
        observationsDirectory = build_obs_path(config, 'ocean',
                                               'meltSubdirectory')
        obsFileNameDict = {'Rignot et al. (2013)':
                           'Rignot_2013_melt_rates_20200623.csv',
                           'Rignot et al. (2013) SS':
                           'Rignot_2013_melt_rates_SS_20200623.csv'}

        obsDict = {}  # dict for storing dict of obs data
        for obsName in obsFileNameDict:
            obsFileName = '{}/{}'.format(observationsDirectory,
                                         obsFileNameDict[obsName])
            obsDict[obsName] = {}
            obsFile = csv.reader(open(obsFileName, 'rU'))
            next(obsFile, None)  # skip the header line
            for line in obsFile:  # some later useful values commented out
                shelfName = line[0]
                if shelfName != self.iceShelf:
                    continue

                # surveyArea = line[1]
                meltFlux = float(line[2])
                meltFluxUncertainty = float(line[3])
                meltRate = float(line[4])
                meltRateUncertainty = float(line[5])
                # actualArea = float( line[6] )  # actual area here is in sq km

                # build dict of obs. keyed to filename description
                # (which will be used for plotting)
                obsDict[obsName] = {
                    'meltFlux': meltFlux,
                    'meltFluxUncertainty': meltFluxUncertainty,
                    'meltRate': meltRate,
                    'meltRateUncertainty': meltRateUncertainty}
                break

        # If areas from obs file used need to be converted from sq km to sq m

        mainRunName = config.get('runs', 'mainRunName')
        movingAverageMonths = config.getint('timeSeriesAntarcticMelt',
                                            'movingAverageMonths')

        outputDirectory = build_config_full_path(config, 'output',
                                                 'timeseriesSubdirectory')

        make_directories(outputDirectory)

        self.logger.info('  Make plots...')

        # get obs melt flux and unc. for shelf (similar for rates)
        obsMeltFlux = []
        obsMeltFluxUnc = []
        obsMeltRate = []
        obsMeltRateUnc = []
        for obsName in obsDict:
            if len(obsDict[obsName]) > 0:
                obsMeltFlux.append(
                    obsDict[obsName]['meltFlux'])
                obsMeltFluxUnc.append(
                    obsDict[obsName]['meltFluxUncertainty'])
                obsMeltRate.append(
                    obsDict[obsName]['meltRate'])
                obsMeltRateUnc.append(
                    obsDict[obsName]['meltRateUncertainty'])
            else:
                # append NaN so this particular obs won't plot
                self.logger.warning('{} observations not available for '
                                    '{}'.format(obsName, self.iceShelf))
                obsMeltFlux.append(None)
                obsMeltFluxUnc.append(None)
                obsMeltRate.append(None)
                obsMeltRateUnc.append(None)

        title = self.iceShelf.replace('_', ' ')

        xLabel = 'Time (yr)'
        yLabel = 'Melt Flux (GT/yr)'

        timeSeries = totalMeltFlux.isel(nRegions=self.regionIndex)

        filePrefix = 'melt_flux_{}'.format(self.iceShelf.replace(' ', '_'))
        outFileName = '{}/{}.png'.format(self.plotsDirectory, filePrefix)

        fields = [timeSeries]
        lineColors = ['k']
        lineWidths = [2.5]
        legendText = [mainRunName]
        if plotControl:
            fields.append(refTotalMeltFlux.isel(nRegions=self.regionIndex))
            lineColors.append('r')
            lineWidths.append(1.2)
            legendText.append(controlRunName)

        fig = timeseries_analysis_plot(config, fields, calendar=calendar,
                                       title=title, xlabel=xLabel,
                                       ylabel=yLabel,
                                       movingAveragePoints=movingAverageMonths,
                                       lineColors=lineColors,
                                       lineWidths=lineWidths,
                                       legendText=legendText,
                                       obsMean=obsMeltFlux,
                                       obsUncertainty=obsMeltFluxUnc,
                                       obsLegend=list(obsDict.keys()))

        # do this before the inset because otherwise it moves the inset
        # and cartopy doesn't play too well with tight_layout anyway
        plt.tight_layout()

        add_inset(fig, fc, width=2.0, height=2.0)

        savefig(outFileName)

        caption = 'Running Mean of Total Melt Flux  under Ice ' \
                  'Shelves in the {} Region'.format(title)
        write_image_xml(
            config=config,
            filePrefix=filePrefix,
            componentName='Ocean',
            componentSubdirectory='ocean',
            galleryGroup='Antarctic Melt Time Series',
            groupLink='antmelttime',
            gallery='Total Melt Flux',
            thumbnailDescription=title,
            imageDescription=caption,
            imageCaption=caption)

        xLabel = 'Time (yr)'
        yLabel = 'Melt Rate (m/yr)'

        timeSeries = meltRates.isel(nRegions=self.regionIndex)

        filePrefix = 'melt_rate_{}'.format(self.iceShelf.replace(' ', '_'))
        outFileName = '{}/{}.png'.format(self.plotsDirectory, filePrefix)

        fields = [timeSeries]
        lineColors = ['k']
        lineWidths = [2.5]
        legendText = [mainRunName]
        if plotControl:
            fields.append(refMeltRates.isel(nRegions=self.regionIndex))
            lineColors.append('r')
            lineWidths.append(1.2)
            legendText.append(controlRunName)

        if config.has_option(self.taskName, 'firstYearXTicks'):
            firstYearXTicks = config.getint(self.taskName,
                                            'firstYearXTicks')
        else:
            firstYearXTicks = None

        if config.has_option(self.taskName, 'yearStrideXTicks'):
            yearStrideXTicks = config.getint(self.taskName,
                                             'yearStrideXTicks')
        else:
            yearStrideXTicks = None

        fig = timeseries_analysis_plot(config, fields, calendar=calendar,
                                       title=title, xlabel=xLabel,
                                       ylabel=yLabel,
                                       movingAveragePoints=movingAverageMonths,
                                       lineColors=lineColors,
                                       lineWidths=lineWidths,
                                       legendText=legendText,
                                       firstYearXTicks=firstYearXTicks,
                                       yearStrideXTicks=yearStrideXTicks,
                                       obsMean=obsMeltRate,
                                       obsUncertainty=obsMeltRateUnc,
                                       obsLegend=list(obsDict.keys()))

        # do this before the inset because otherwise it moves the inset
        # and cartopy doesn't play too well with tight_layout anyway
        plt.tight_layout()

        add_inset(fig, fc, width=2.0, height=2.0)

        savefig(outFileName)

        caption = 'Running Mean of Area-averaged Melt Rate under Ice ' \
                  'Shelves in the {} Region'.format(title)
        write_image_xml(
            config=config,
            filePrefix=filePrefix,
            componentName='Ocean',
            componentSubdirectory='ocean',
            galleryGroup='Antarctic Melt Time Series',
            groupLink='antmelttime',
            gallery='Area-averaged Melt Rate',
            thumbnailDescription=title,
            imageDescription=caption,
            imageCaption=caption)
Esempio n. 10
0
    def run_task(self):  # {{{
        """
        Make the Hovmoller plot from the time series.
        """
        # Authors
        # -------
        # Xylar Asay-Davis, Milena Veneziani, Greg Streletz

        self.logger.info("\nPlotting {} time series vs. depth...".format(
            self.fieldNameInTitle))

        config = self.config

        mainRunName = config.get('runs', 'mainRunName')

        self.logger.info('  Load ocean data...')
        ds = xr.open_dataset(self.inFileName)

        if 'regionNames' in ds.coords:

            allRegionNames = decode_strings(ds.regionNames)
            regionIndex = allRegionNames.index(self.regionName)
            regionNameInTitle = self.regionName.replace('_', ' ')
            regionDim = ds.regionNames.dims[0]
        else:
            plotTitles = config.getExpression('regions', 'plotTitles')
            allRegionNames = config.getExpression('regions', 'regions')
            regionIndex = allRegionNames.index(self.regionName)
            regionNameInTitle = plotTitles[regionIndex]
            regionDim = 'nOceanRegionsTmp'

        ds = ds.isel(**{regionDim: regionIndex})

        # Note: restart file, not a mesh file because we need refBottomDepth,
        # not in a mesh file
        try:
            restartFile = self.runStreams.readpath('restart')[0]
        except ValueError:
            raise IOError('No MPAS-O restart file found: need at least one '
                          'restart file for plotting time series vs. depth')

        # Define/read in general variables
        self.logger.info('  Read in depth...')
        with xr.open_dataset(restartFile) as dsRestart:
            # reference depth [m]
            depths = dsRestart.refBottomDepth.values
            z = np.zeros(depths.shape)
            z[0] = -0.5 * depths[0]
            z[1:] = -0.5 * (depths[0:-1] + depths[1:])

        Time = ds.Time.values
        field = ds[self.mpasFieldName].values.transpose()

        xLabel = 'Time (years)'
        yLabel = 'Depth (m)'

        title = '{}, {}'.format(self.fieldNameInTitle, regionNameInTitle)

        outFileName = '{}/{}.png'.format(self.plotsDirectory, self.filePrefix)

        if config.has_option(self.sectionName, 'firstYearXTicks'):
            firstYearXTicks = config.getint(self.sectionName,
                                            'firstYearXTicks')
        else:
            firstYearXTicks = None

        if config.has_option(self.sectionName, 'yearStrideXTicks'):
            yearStrideXTicks = config.getint(self.sectionName,
                                             'yearStrideXTicks')
        else:
            yearStrideXTicks = None

        movingAverageMonths = config.getWithDefault(self.sectionName,
                                                    'movingAverageMonths', 1)

        if config.has_option(self.sectionName, 'yLim'):
            yLim = config.getExpression(self.sectionName, 'yLim')
        else:
            yLim = None

        if self.controlConfig is None:
            refField = None
            diff = None
            refTitle = None
            diffTitle = None
        else:
            controlConfig = self.controlConfig
            dsRef = xr.open_dataset(self.controlFileName)

            if 'regionNames' in dsRef.coords:
                allRegionNames = decode_strings(dsRef.regionNames)
                regionIndex = allRegionNames.index(self.regionName)
                regionNameInTitle = self.regionName.replace('_', ' ')
                regionDim = dsRef.regionNames.dims[0]
            else:
                plotTitles = controlConfig.getExpression(
                    'regions', 'plotTitles')
                allRegionNames = controlConfig.getExpression(
                    'regions', 'regions')
                regionIndex = allRegionNames.index(self.regionName)
                regionNameInTitle = plotTitles[regionIndex]
                regionDim = 'nOceanRegionsTmp'

            dsRef = dsRef.isel(**{regionDim: regionIndex})
            refField = dsRef[self.mpasFieldName].values.transpose()
            assert (field.shape == refField.shape)
            diff = field - refField
            refTitle = self.controlConfig.get('runs', 'mainRunName')
            diffTitle = 'Main - Control'

        fig, _, suptitle = plot_vertical_section_comparison(
            config,
            Time,
            z,
            field,
            refField,
            diff,
            self.sectionName,
            colorbarLabel=self.unitsLabel,
            title=title,
            modelTitle=mainRunName,
            refTitle=refTitle,
            diffTitle=diffTitle,
            xlabel=xLabel,
            ylabel=yLabel,
            lineWidth=1,
            xArrayIsTime=True,
            movingAveragePoints=movingAverageMonths,
            calendar=self.calendar,
            firstYearXTicks=firstYearXTicks,
            yearStrideXTicks=yearStrideXTicks,
            yLim=yLim,
            invertYAxis=False)

        if self.regionMaskFile is not None:

            # shift the super-title a little to the left to make room for the
            # inset
            pos = suptitle.get_position()
            suptitle.set_position((pos[0] - 0.05, pos[1]))

            fcAll = read_feature_collection(self.regionMaskFile)

            fc = FeatureCollection()
            for feature in fcAll.features:
                if feature['properties']['name'] == self.regionName:
                    fc.add_feature(feature)
                    break

            add_inset(fig, fc, width=1.0, height=1.0, xbuffer=0.1, ybuffer=0.1)

            savefig(outFileName, tight=False)

        else:
            savefig(outFileName)

        write_image_xml(config=config,
                        filePrefix=self.filePrefix,
                        componentName='Ocean',
                        componentSubdirectory='ocean',
                        galleryGroup=self.galleryGroup,
                        groupSubtitle=self.groupSubtitle,
                        groupLink=self.groupLink,
                        gallery=self.galleryName,
                        thumbnailDescription='{} {}'.format(
                            regionNameInTitle, self.thumbnailSuffix),
                        imageDescription=self.imageCaption,
                        imageCaption=self.imageCaption)
    def run_task(self):  # {{{
        """
        Plots time-series output of transport through transects.
        """
        # Authors
        # -------
        # Xylar Asay-Davis, Stephen Price

        self.logger.info("\nPlotting time series of transport through "
                         "{}...".format(self.transect))

        self.logger.info('  Load transport data...')

        obsDict = {
            'Drake Passage': [120, 175],
            'Tasmania-Ant': [147, 167],
            'Africa-Ant': None,
            'Antilles Inflow': [-23.1, -13.7],
            'Mona Passage': [-3.8, -1.4],
            'Windward Passage': [-7.2, -6.8],
            'Florida-Cuba': [30, 33],
            'Florida-Bahamas': [30, 33],
            'Indonesian Throughflow': [-21, -11],
            'Agulhas': [-90, -50],
            'Mozambique Channel': [-20, -8],
            'Bering Strait': [0.6, 1.0],
            'Lancaster Sound': [-1.0, -0.5],
            'Fram Strait': [-4.7, 0.7],
            'Davis Strait': [-1.6, -3.6],
            'Barents Sea Opening': [1.4, 2.6],
            'Nares Strait': [-1.8, 0.2]
        }

        config = self.config
        calendar = self.calendar

        fcAll = read_feature_collection(self.transportTransectFileName)

        fc = FeatureCollection()
        for feature in fcAll.features:
            if feature['properties']['name'] == self.transect:
                fc.add_feature(feature)
                break

        transport, trans_mean, trans_std = self._load_transport(config)

        if self.transect in obsDict:
            bounds = obsDict[self.transect]
        else:
            bounds = None

        plotControl = self.controlConfig is not None

        mainRunName = config.get('runs', 'mainRunName')
        movingAverageMonths = config.getint('timeSeriesTransport',
                                            'movingAverageMonths')

        self.logger.info('  Plotting...')

        transectName = self.transect.replace('_', ' ')
        title = transectName
        thumbnailDescription = transectName

        xLabel = 'Time (yr)'
        yLabel = 'Transport (Sv)'

        filePrefix = 'transport_{}'.format(self.transect.replace(' ', '_'))
        outFileName = '{}/{}.png'.format(self.plotsDirectory, filePrefix)

        fields = [transport]
        lineColors = ['k']
        lineWidths = [2.5]
        meanString = 'mean={:.2f} $\pm$ {:.2f}'.format(trans_mean, trans_std)
        if plotControl:
            controlRunName = self.controlConfig.get('runs', 'mainRunName')
            ref_transport, ref_mean, ref_std = \
                self._load_transport(self.controlConfig)
            refMeanString = 'mean={:.2f} $\pm$ {:.2f}'.format(
                ref_mean, ref_std)
            fields.append(ref_transport)
            lineColors.append('r')
            lineWidths.append(1.2)
            legendText = [
                '{} ({})'.format(mainRunName, meanString),
                '{} ({})'.format(controlRunName, refMeanString)
            ]

        else:
            legendText = [mainRunName]
            title = '{} ({})'.format(title, meanString)

        if config.has_option(self.taskName, 'firstYearXTicks'):
            firstYearXTicks = config.getint(self.taskName, 'firstYearXTicks')
        else:
            firstYearXTicks = None

        if config.has_option(self.taskName, 'yearStrideXTicks'):
            yearStrideXTicks = config.getint(self.taskName, 'yearStrideXTicks')
        else:
            yearStrideXTicks = None

        fig = timeseries_analysis_plot(config,
                                       fields,
                                       calendar=calendar,
                                       title=title,
                                       xlabel=xLabel,
                                       ylabel=yLabel,
                                       movingAveragePoints=movingAverageMonths,
                                       lineColors=lineColors,
                                       lineWidths=lineWidths,
                                       legendText=legendText,
                                       firstYearXTicks=firstYearXTicks,
                                       yearStrideXTicks=yearStrideXTicks)

        if bounds is not None:
            t = transport.Time.values
            plt.gca().fill_between(t,
                                   bounds[0] * numpy.ones_like(t),
                                   bounds[1] * numpy.ones_like(t),
                                   alpha=0.3,
                                   label='observations')
            plt.legend(loc='lower left')

        # do this before the inset because otherwise it moves the inset
        # and cartopy doesn't play too well with tight_layout anyway
        plt.tight_layout()

        add_inset(fig, fc, width=2.0, height=2.0)

        savefig(outFileName)

        caption = 'Transport through the {} Transect'.format(transectName)
        write_image_xml(config=config,
                        filePrefix=filePrefix,
                        componentName='Ocean',
                        componentSubdirectory='ocean',
                        galleryGroup='Transport Time Series',
                        groupLink='transporttime',
                        thumbnailDescription=thumbnailDescription,
                        imageDescription=caption,
                        imageCaption=caption)
Esempio n. 12
0
    def _plot_transect(self, remappedModelClimatology, remappedRefClimatology):
        # {{{
        """ plotting the transect """

        season = self.season
        config = self.config
        configSectionName = self.configSectionName

        mainRunName = config.get('runs', 'mainRunName')

        # broadcast x and z to have the same dimensions
        x, z = xr.broadcast(remappedModelClimatology.x,
                            remappedModelClimatology.z)

        # set lat and lon in case we want to plot versus these quantities
        lat = remappedModelClimatology.lat
        lon = remappedModelClimatology.lon

        # convert x, z, lat, and lon to numpy arrays; make a copy because
        # they are sometimes read-only (not sure why)
        x = x.values.copy().transpose()
        z = z.values.copy().transpose()
        lat = lat.values.copy().transpose()
        lon = lon.values.copy().transpose()
        self.lat = lat
        self.lon = lon

        # This will do strange things at the antemeridian but there's little
        # we can do about that.
        lon_pm180 = numpy.mod(lon + 180., 360.) - 180.

        if self.horizontalBounds is not None:
            mask = numpy.logical_and(
                remappedModelClimatology.x.values >= self.horizontalBounds[0],
                remappedModelClimatology.x.values <= self.horizontalBounds[1])
            inset_lon = lon_pm180[mask]
            inset_lat = lat[mask]
        else:
            inset_lon = lon_pm180
            inset_lat = lat
        fc = FeatureCollection()
        fc.add_feature({
            "type": "Feature",
            "properties": {
                "name": self.transectName,
                "author": 'Xylar Asay-Davis',
                "object": 'transect',
                "component": 'ocean',
                "tags": ''
            },
            "geometry": {
                "type": "LineString",
                "coordinates": list(map(list, zip(inset_lon, inset_lat)))
            }
        })

        # z is masked out with NaNs in some locations (where there is land) but
        # this makes pcolormesh unhappy so we'll zero out those locations
        z[numpy.isnan(z)] = 0.

        modelOutput = nans_to_numpy_mask(
            remappedModelClimatology[self.mpasFieldName].values)
        modelOutput = modelOutput.transpose()

        if remappedRefClimatology is None:
            refOutput = None
            bias = None
        else:
            refOutput = remappedRefClimatology[self.refFieldName]
            dims = refOutput.dims
            refOutput = nans_to_numpy_mask(refOutput.values)
            if dims[1] != 'nPoints':
                assert (dims[0] == 'nPoints')
                refOutput = refOutput.transpose()

            bias = modelOutput - refOutput

        filePrefix = self.filePrefix
        outFileName = '{}/{}.png'.format(self.plotsDirectory, filePrefix)
        title = '{}\n({}, years {:04d}-{:04d})'.format(self.fieldNameInTitle,
                                                       season, self.startYear,
                                                       self.endYear)

        xLabel = 'Distance [km]'
        yLabel = 'Depth [m]'

        # define the axis labels and the data to use for the upper
        # x axis or axes, if such additional axes have been requested

        upperXAxes = config.get('transects', 'upperXAxes')
        numUpperTicks = config.getint('transects', 'numUpperTicks')
        upperXAxisTickLabelPrecision = config.getint(
            'transects', 'upperXAxisTickLabelPrecision')

        self._set_third_x_axis_to_none()

        if upperXAxes == 'neither':
            self._set_second_x_axis_to_none()
        elif upperXAxes == 'lat':
            self._set_second_x_axis_to_latitude()
        elif upperXAxes == 'lon':
            self._set_second_x_axis_to_longitude()
        elif upperXAxes == 'both':
            self._set_second_x_axis_to_longitude()
            self._set_third_x_axis_to_latitude()
        elif upperXAxes == 'greatestExtent':
            if self._greatest_extent(lat, lon):
                self._set_second_x_axis_to_latitude()
            else:
                self._set_second_x_axis_to_longitude()
        elif upperXAxes == 'strictlyMonotonic':
            if self._strictly_monotonic(lat, lon):
                self._set_second_x_axis_to_latitude()
            else:
                self._set_second_x_axis_to_longitude()
        elif upperXAxes == 'mostMonotonic':
            if self._most_monotonic(lat, lon):
                self._set_second_x_axis_to_latitude()
            else:
                self._set_second_x_axis_to_longitude()
        elif upperXAxes == 'mostStepsInSameDirection':
            if self._most_steps_in_same_direction(lat, lon):
                self._set_second_x_axis_to_latitude()
            else:
                self._set_second_x_axis_to_longitude()
        elif upperXAxes == 'fewestDirectionChanges':
            if self._fewest_direction_changes(lat, lon):
                self._set_second_x_axis_to_latitude()
            else:
                self._set_second_x_axis_to_longitude()
        else:
            raise ValueError('invalid option for upperXAxes')

        # get the parameters determining what type of plot to use,
        # what line styles and line colors to use, and whether and how
        # to label contours

        compareAsContours = config.getboolean('transects',
                                              'compareAsContoursOnSinglePlot')

        contourLineStyle = config.get('transects', 'contourLineStyle')
        contourLineColor = config.get('transects', 'contourLineColor')
        comparisonContourLineStyle = config.get('transects',
                                                'comparisonContourLineStyle')
        comparisonContourLineColor = config.get('transects',
                                                'comparisonContourLineColor')

        if compareAsContours:
            labelContours = config.getboolean(
                'transects', 'labelContoursOnContourComparisonPlots')
        else:
            labelContours = config.getboolean('transects',
                                              'labelContoursOnHeatmaps')

        contourLabelPrecision = config.getint('transects',
                                              'contourLabelPrecision')

        # construct a three-panel comparison plot for the transect, or a
        # single-panel contour comparison plot if compareAsContours is True

        fig, axes, suptitle = plot_vertical_section_comparison(
            config,
            x,
            z,
            modelOutput,
            refOutput,
            bias,
            configSectionName,
            cbarLabel=self.unitsLabel,
            xlabel=xLabel,
            ylabel=yLabel,
            title=title,
            modelTitle='{}'.format(mainRunName),
            refTitle=self.refTitleLabel,
            diffTitle=self.diffTitleLabel,
            secondXAxisData=self.secondXAxisData,
            secondXAxisLabel=self.secondXAxisLabel,
            thirdXAxisData=self.thirdXAxisData,
            thirdXAxisLabel=self.thirdXAxisLabel,
            numUpperTicks=numUpperTicks,
            upperXAxisTickLabelPrecision=upperXAxisTickLabelPrecision,
            invertYAxis=False,
            backgroundColor='#918167',
            xLim=self.horizontalBounds,
            compareAsContours=compareAsContours,
            lineStyle=contourLineStyle,
            lineColor=contourLineColor,
            comparisonContourLineStyle=comparisonContourLineStyle,
            comparisonContourLineColor=comparisonContourLineColor,
            labelContours=labelContours,
            contourLabelPrecision=contourLabelPrecision)

        # shift the super-title a little to the left to make room for the inset
        pos = suptitle.get_position()
        suptitle.set_position((pos[0] - 0.05, pos[1]))

        # make a red start axis and green end axis to correspond to the dots
        # in the inset
        for ax in axes:
            ax.spines['left'].set_color('red')
            ax.spines['right'].set_color('green')
            ax.spines['left'].set_linewidth(4)
            ax.spines['right'].set_linewidth(4)

        add_inset(fig, fc, width=1.5, height=1.5, xbuffer=0.1, ybuffer=0.1)

        savefig(outFileName, tight=False)

        caption = '{} {}'.format(season, self.imageCaption)
        write_image_xml(config,
                        filePrefix,
                        componentName='Ocean',
                        componentSubdirectory='ocean',
                        galleryGroup=self.galleryGroup,
                        groupSubtitle=self.groupSubtitle,
                        groupLink=self.groupLink,
                        gallery=self.galleryName,
                        thumbnailDescription=self.thumbnailDescription,
                        imageDescription=caption,
                        imageCaption=caption)
Esempio n. 13
0
def get_longest_contour(contourValue, author):

    def stereo_to_lon_lat(x, y):
        return pyproj.transform(inProj, outProj, x, y)

    bathymetryFileName = 'IBCAO_V3_500m_SM.grd.gz'
    if not os.path.exists(bathymetryFileName):
        print('Downloading IBCAO bathymetry data...')
        # download
        baseURL = 'https://www.ngdc.noaa.gov/mgg/bathymetry/arctic/grids/version3_0'

        download_files([bathymetryFileName], baseURL, './')

    print('Decompressing and reading IBCAO bathymetry data...')
    infile = gzip.open(bathymetryFileName, 'rb')
    tmp = tempfile.NamedTemporaryFile(delete=False)
    shutil.copyfileobj(infile, tmp)
    infile.close()
    tmp.close()
    ds = xarray.open_dataset(tmp.name)
    os.unlink(tmp.name)

    x = ds.x.values
    y = ds.y.values
    z = ds.z.values
    z[(x==numpy.amin(x)) | (x==numpy.amax(x)) |
      (y==numpy.amin(y)) | (y==numpy.amax(y))] = 0.0
    # plot contours
    plt.figure()
    cs = plt.contour(x, y, z, (contourValue,))
    paths = cs.collections[0].get_paths()

    pathLengths = [len(paths[i]) for i in range(len(paths))]
    iLongest = numpy.argmax(pathLengths)

    p = paths[iLongest]
    v = p.vertices
    x = v[:, 0]
    y = v[:, 1]

    # Arctic stereographic
    inProj = pyproj.Proj(init='epsg:3995')
    # lon/lat
    outProj = pyproj.Proj(init='epsg:4326')
    lon, lat = pyproj.transform(inProj, outProj, x, y)

    poly = shapely.geometry.Polygon([(i[0], i[1]) for i in zip(x, y)])

    epsilon = 1e-14
    maxY = numpy.amax(y)
    wedge = shapely.geometry.Polygon([(epsilon, maxY),
                                      (epsilon**2, epsilon),
                                      (0, epsilon),
                                      (-epsilon**2, epsilon),
                                      (-epsilon, maxY),
                                      (epsilon, maxY)])

    difference = poly.difference(wedge)

    difference = shapely.ops.transform(stereo_to_lon_lat, difference)

    fc = FeatureCollection()

    geometry = shapely.geometry.mapping(difference)
    # get rid of the wedge again by rounding the coordinates
    geometry['coordinates'] = _round_coords(geometry['coordinates'])

    fc.add_feature(
        {"type": "Feature",
         "properties": {"name": "Contour {}".format(contourValue),
                        "author": author,
                        "object": 'region',
                        "component": 'ocean'},
         "geometry": geometry})

    return fc
Esempio n. 14
0
def main():
    author = 'Milena Veneziani'

    # make a geometric features object that knows about the geometric data
    # cache up a couple of directories
    gf = GeometricFeatures(cacheLocation='../../geometric_data')

    fc = FeatureCollection()

    # ********* New Hudson Bay (modified feature) *********

    # Extract Foxe Basin from Northwestern Passages, and merge it
    # to old Hudson Bay feature. Also combine Hudson Strait with
    # Hudson Bay. Note that the created feature needs to be further
    # edited by hand to eliminate a seem, due to Foxe Basin not
    # completely aligning with one side of the old Hudson Bay feature
    # (and this feature is not fixed by the last step in this script
    # either).
    fcCAA = gf.read('ocean', 'region', ['Northwestern Passages'])
    fcbox1 = make_rectangle(lon0=-84.3, lon1=-71.7, lat0=67.1, lat1=70.75,
                            name='Foxe Basin Box 1', author=author,
                            tags='Hudson_Bay;Arctic;Atlantic_Basin')
    fcbox2 = make_rectangle(lon0=-86., lon1=-71.7, lat0=63.5, lat1=67.1,
                            name='Foxe Basin Box 2', author=author,
                            tags='Hudson_Bay;Arctic;Atlantic_Basin')
    fcFoxe_tmp = fcbox1.difference(fcCAA)
    fcFoxe_tmp = fcbox1.difference(fcFoxe_tmp)
    fcFoxe = fcbox2.difference(fcCAA)
    fcFoxe = fcbox2.difference(fcFoxe)
    fcFoxe.merge(fcFoxe_tmp)
    fcFoxe = fcFoxe.combine('Foxe Basin')
    fcHudson = gf.read('ocean', 'region', ['Hudson Bay'])
    fcHudson.merge(gf.read('ocean', 'region', ['Hudson Strait']))
    fcHudson.merge(fcFoxe)
    fcHudson = fcHudson.combine('Hudson Bay')
    props = fcHudson.features[0]['properties']
    props['tags'] = 'Hudson Bay;Arctic;Atlantic_Basin'
    props['author'] = author
    fc = fcHudson

    # ********* New Canadian Archipelago (modified feature) *********

    # Remove Foxe Basin from Northwestern Passages and make new
    # Canadian Archipelago feature
    fcCAA = fcCAA.difference(fcFoxe)
    props = fcCAA.features[0]['properties']
    props['name'] = 'Canadian Archipelago'
    props['tags'] = 'Canadian_Archipelago;Arctic;Atlantic_Basin'
    props['author'] = author
    fc.merge(fcCAA)

    # ********* New Barents Sea (modified feature) *********
    # NOTE: this is dependent on existence of *old* features;
    #       in particular, the Barentsz_Sea feature will
    #       be removed after this script is applied

    # Combine Barentsz_Sea and White_Sea into new Barents Sea feature
    fcBS = gf.read('ocean', 'region', ['Barentsz Sea'])
    fcBS.merge(gf.read('ocean', 'region', ['White Sea']))
    fcBS = fcBS.combine('Barents Sea')
    props = fcBS.features[0]['properties']
    props['tags'] = 'Barents_Sea;Arctic;Arctic_NSIDC;Arctic_Basin'
    props['author'] = author
    fc.merge(fcBS)

    # ********* Kara Sea (unchanged feature) *********

    fcKara = gf.read('ocean', 'region', ['Kara Sea'])
    props = fcKara.features[0]['properties']
    props['tags'] = 'Kara_Sea;Arctic;Arctic_NSIDC;Arctic_Basin'
    fc.merge(fcKara)

    # ********* New Arctic Ocean (modified feature) *********
    # NOTE: this is dependent on existence of *old* features;
    #       in particular, the Arctic_Ocean, Chukchi_Sea,
    #       East_Siberian_Sea, and Laptev_Sea features will
    #       be superseded after this script is applied

    # Define triangle between Greenland Sea and Arctic_Ocean
    # (north of Fram Strait) that is not part of any of the
    # currently defined Arctic features
    fc_tmp = gf.read('ocean', 'region', ['Arctic Ocean'])
    fc_tmp.merge(gf.read('ocean', 'region', ['Lincoln Sea']))
    fc_tmp.merge(fcBS)
    fcArctic = make_rectangle(lon0=-36., lon1=20., lat0=86., lat1=79.,
        name='North of Fram Strait', author=author, tags='Arctic_Basin')
    fcArctic = fcArctic.difference(fc_tmp)

    # Define full Arctic *but* Barents and Kara Seas
    fcArctic.merge(gf.read('ocean', 'region', ['Arctic Ocean']))
    fcArctic.merge(gf.read('ocean', 'region', ['Laptev Sea']))
    fcArctic.merge(gf.read('ocean', 'region', ['East Siberian Sea']))
    fcArctic.merge(gf.read('ocean', 'region', ['Chukchi Sea']))
    fcArctic.merge(gf.read('ocean', 'region', ['Beaufort Sea']))
    fcArctic.merge(gf.read('ocean', 'region', ['Lincoln Sea']))
    fcArctic = fcArctic.combine('Arctic Ocean')
    props = fcArctic.features[0]['properties']
    props['tags'] = 'Arctic_Ocean;Arctic;Arctic_Basin'
    props['author'] = author
    fc.merge(fcArctic)

    # ********* Beaufort Gyre (entirely new feature) *********

    fcContour300 = get_longest_contour(contourValue=-300., author=author)
    fcBG_firstTry = make_rectangle(lon0=-170., lon1=-130., lat0=70.5, lat1=80.5,
                                   name='Beaufort Gyre', author=author,
                                   tags='Beaufort_Gyre;Arctic_Proshutinsky')
    fcBG = fcBG_firstTry.difference(fcContour300)
    fcBG = fcBG_firstTry.difference(fcBG)
    fc.merge(fcBG)

    # ********* New NSIDC Chukchi Sea (new feature) *********

    # Define Chukchi Sea as MASIE region #2 minus intersection with
    # Beaufort Gyre, and with Bering Strait transect as southern boundary
    fcChukchi = FeatureCollection()
    fcChukchi.add_feature(
        {"type": "Feature",
         "properties": {"name": 'Chukchi Sea NSIDC',
                        "author": author,
                        "object": 'region',
                        "component": 'ocean',
                        "tags": 'Chukchi_Sea_NSIDC;Arctic_NSIDC'},
         "geometry": {
             "type": "Polygon",
             "coordinates": [[[-167.15, 65.74],
                              [-168.01, 65.84],
                              [-168.62, 65.91],
                              [-169.43, 66.01],
                              [-170.24, 66.1],
                              [-180., 66.6],
                              [-180., 80.0],
                              [-156.48, 80.0],
                              [-156.65, 65.37],
                              [-167.15, 65.74]]]}})
    fcChukchi = fcChukchi.difference(fcBG)
    fc.merge(fcChukchi)

    # ********* Beaufort Gyre shelf (entirely new feature) *********

    # Define Beaufort Gyre shelf region, minus intersection with Chukchi Sea
    fcBGshelf_firstTry = make_rectangle(lon0=-170., lon1=-130.,
                                        lat0=68.0, lat1=80.5,
                                        name='Beaufort Gyre Shelf Box',
                                        author=author,
                                        tags='Beaufort_Gyre_Shelf;Arctic_Proshutinsky')
    fcBGshelf = fcBGshelf_firstTry.difference(fcContour300)
    fcBGshelf_secondTry = fcBGshelf_firstTry.difference(fcBG)
    fcBGshelf_secondTry = fcBGshelf_secondTry.difference(fcBGshelf)
    fcBGshelf.merge(fcBGshelf_secondTry)
    fcBGshelf = fcBGshelf.combine('Beaufort Gyre Shelf')
    fcBGshelf = fcBGshelf.difference(fcChukchi)
    props = fcBGshelf.features[0]['properties']
    props['name'] = 'Beaufort Gyre Shelf'
    props['author'] = author
    props['tags'] = 'Beaufort_Gyre_Shelf;Arctic_Proshutinsky'
    fc.merge(fcBGshelf)

    # ********* New NSIDC East Siberian Sea (new feature) *********

    # Define East Siberian Sea as MASIE region #3
    fcESS = FeatureCollection()
    fcESS = make_rectangle(lon0=180., lon1=145., lat0=67., lat1=80.,
                           name='East Siberian Sea NSIDC', author=author,
                           tags='East_Siberian_Sea_NSIDC;Arctic_NSIDC')
    fc.merge(fcESS)

    # ********* New NSIDC Laptev Sea (new feature) *********

    # Define Laptev Sea as MASIE region #4, minus intersection with
    # Kara Sea
    fcLap = FeatureCollection()
    fcLap.add_feature(
        {"type": "Feature",
         "properties": {"name": 'Laptev Sea NSIDC',
                        "author": author,
                        "object": 'region',
                        "component": 'ocean',
                        "tags": 'Laptev_Sea_NSIDC;Arctic_NSIDC'},
         "geometry": {
             "type": "Polygon",
             "coordinates": [[[145.,  68.],
                              [145.,  80.],
                              [95.4, 81.29],
                              [99.89, 78.27],
                              [102.,  72.],
                              [145.,  68.]]]}})
    fcLap = fcLap.difference(fcKara)
    fc.merge(fcLap)

    # ********* Central Arctic (entirely new feature) *********

    # Define Central Arctic region as New Arctic Ocean minus BG, BGshelf,
    # New Chukchi, New ESS, and New Laptev
    fcCentralArctic = fcArctic.difference(fcBG)
    fcCentralArctic = fcCentralArctic.difference(fcBGshelf)
    fcCentralArctic = fcCentralArctic.difference(fcChukchi)
    fcCentralArctic = fcCentralArctic.difference(fcESS)
    fcCentralArctic = fcCentralArctic.difference(fcLap)
    props = fcCentralArctic.features[0]['properties']
    props['name'] = 'Central Arctic'
    props['tags'] = 'Central_Arctic;Arctic;Arctic_Basin'
    props['author'] = author
    fc.merge(fcCentralArctic)

    # "split" these features into individual files in the geometric data cache
    gf.split(fc)

    # update the database of feature names and tags
    write_feature_names_and_tags(gf.cacheLocation)
    # move the resulting file into place
    shutil.copyfile('features_and_tags.json',
                    '../../geometric_features/features_and_tags.json')

    # Fix features if necessary
    fcArcticTags = gf.read(componentName='ocean', objectType='region',
                           tags=['Arctic'])
    for feature in fcArcticTags.features:
        featureName = feature['properties']['name']
        shape = shapely.geometry.shape(feature['geometry'])
        print('{} is_valid: {}'.format(featureName, shape.is_valid))
        if not shape.is_valid:
            fixed = shape.buffer(0)
            print('  Fixed? {}'.format(fixed.is_valid))
            feature['geometry'] = shapely.geometry.mapping(fixed)
    fcArcticNSIDCTags = gf.read(componentName='ocean', objectType='region',
                                tags=['Arctic_NSIDC'])
    for feature in fcArcticNSIDCTags.features:
        featureName = feature['properties']['name']
        shape = shapely.geometry.shape(feature['geometry'])
        print('{} is_valid: {}'.format(featureName, shape.is_valid))
        if not shape.is_valid:
            fixed = shape.buffer(0)
            print('  Fixed? {}'.format(fixed.is_valid))
            feature['geometry'] = shapely.geometry.mapping(fixed)

    fcArctic = fcArcticTags
    fcArctic.merge(fcArcticNSIDCTags)
    fcArctic.to_geojson('arctic_ocean_regions.geojson')
    fcArctic.plot(projection='northpole')

    # "split" these features into individual files in the geometric data cache
    gf.split(fcArctic)

    # update the database of feature names and tags
    write_feature_names_and_tags(gf.cacheLocation)
    # move the resulting file into place
    shutil.copyfile('features_and_tags.json',
                    '../../geometric_features/features_and_tags.json')

    plt.show()
def main():
    author = 'Milena Veneziani'

    # make a geometric features object that knows about the geometric data
    # cache up a couple of directories
    gf = GeometricFeatures(cacheLocation='../../geometric_data',
                           remoteBranchOrTag='master')

    fc = FeatureCollection()

    # *********** First, fix Atlantic_Basin regions in such a way that ********
    # **********  they do not overlap each other (so that, we can combine
    # *********   them together to form a Atlantic Basin region)

    # ********* New Baltic Sea (modified feature) *********

    # Combine old Baltic Sea feature with other small features
    fcBalticSea = gf.read('ocean', 'region', ['Baltic Sea'])
    fcFinland = gf.read('ocean', 'region', ['Gulf of Finland'])
    fcBothnia = gf.read('ocean', 'region', ['Gulf of Bothnia'])
    fcRiga = gf.read('ocean', 'region', ['Gulf of Riga'])
    fcKattegat = gf.read('ocean', 'region', ['Kattegat'])
    fcSkaggerak = gf.read('ocean', 'region', ['Skaggerak'])
    fcBalticSea.merge(fcFinland)
    fcBalticSea.merge(fcBothnia)
    fcBalticSea.merge(fcRiga)
    fcBalticSea.merge(fcKattegat)
    fcBalticSea.merge(fcSkaggerak)
    fcBalticSea = fcBalticSea.combine('Baltic Sea')
    props = fcBalticSea.features[0]['properties']
    props['tags'] = 'Baltic_Sea;Arctic;Atlantic_Basin'
    props['author'] = author
    fc = fcBalticSea

    # ********* New North Atlantic Ocean (modified feature) *********

    # Fix North Atlantic so that it does not overlap with new Labdrador
    # Sea, Irminger Sea, North Sea, Greenland Sea, and Norwegian Sea
    fcNorthAtlantic = gf.read('ocean', 'region', ['North Atlantic Ocean'])
    fcLabSea = gf.read('ocean', 'region', ['Labrador Sea'])
    fcIrmSea = gf.read('ocean', 'region', ['Irminger Sea'])
    fcGS = gf.read('ocean', 'region', ['Greenland Sea'])
    fcNS = gf.read('ocean', 'region', ['Norwegian Sea'])
    fcNorthSea = gf.read('ocean', 'region', ['North Sea'])
    fc_todiscard = fcLabSea
    fc_todiscard.merge(fcIrmSea)
    fc_todiscard.merge(fcGS)
    fc_todiscard.merge(fcNS)
    fc_todiscard.merge(fcNorthSea)
    fc_todiscard = fc_todiscard.combine('Combined region to discard')
    fcNorthAtlantic.merge(fc_todiscard)
    fcNorthAtlantic = fcNorthAtlantic.combine('North Atlantic Ocean')
    fcNorthAtlantic = fcNorthAtlantic.difference(fc_todiscard)
    props = fcNorthAtlantic.features[0]['properties']
    props['tags'] = 'North_Atlantic_Ocean;Atlantic_Basin'
    props['author'] = author
    fc.merge(fcNorthAtlantic)

    # *********** Second, complete definition of oceanography-relevant *********
    # **********  Arctic regions, started in part I, and identified with
    # *********   tag='Arctic'

    # ********* New Canadian Archipelago (modified feature) *********

    # Modify old CAA by 1) including the shelf in the Arctic Ocean, and
    # 2) including Nares Strait. Old CAA feature will be superseded by this.
    fcContour500 = get_longest_contour(contourValue=-500., author=author)
    fcContour1000 = get_longest_contour(contourValue=-1000., author=author)
    fcCAA1 = make_rectangle(lon0=-130.,
                            lon1=-90.,
                            lat0=67.0,
                            lat1=86.0,
                            name='West Canadian Archipelago',
                            author=author,
                            tags='Canadian_Archipelago;Arctic;Atlantic_Basin')
    fcCAA1 = fcCAA1.difference(fcContour500)
    fcCAA2 = make_rectangle(lon0=-90.,
                            lon1=-70.,
                            lat0=67.0,
                            lat1=86.0,
                            name='Mid Canadian Archipelago',
                            author=author,
                            tags='Canadian_Archipelago;Arctic;Atlantic_Basin')
    fcCAA2 = fcCAA2.difference(fcContour1000)
    fcCAA3 = make_rectangle(lon0=-70.,
                            lon1=-50.5,
                            lat0=76.0,
                            lat1=86.0,
                            name='East Canadian Archipelago',
                            author=author,
                            tags='Canadian_Archipelago;Arctic;Atlantic_Basin')
    fcCAA3 = fcCAA3.difference(fcContour500)
    fcCAA = fcCAA1
    fcCAA.merge(fcCAA2)
    fcCAA.merge(fcCAA3)
    fcCAA = fcCAA.combine('Canadian Archipelago')
    fcHudson = gf.read('ocean', 'region', ['Hudson Bay'])
    fcCAA = fcCAA.difference(fcHudson)
    fcBaffin = gf.read('ocean', 'region', ['Baffin Bay'])
    fcCAA = fcCAA.difference(fcBaffin)
    props = fcCAA.features[0]['properties']
    props['tags'] = 'Canadian_Archipelago;Arctic;Atlantic_Basin'
    props['author'] = author
    fc.merge(fcCAA)

    # ********* Canada Basin (new feature) *********

    # This is a slightly modified version of the Beaufort Gyre feature
    # defined in part I. Differences include 1) a region that expands to
    # the west to touch the northern boundary of the new CAA feature, and
    # 2) a region that includes the Canada Basin shelf (whereas, for the
    # Beuafort Gyre, we have separated the 'Gyre' from the 'Gyre Shelf').
    fcContour300 = get_longest_contour(contourValue=-300., author=author)
    fcCB1 = make_rectangle(lon0=-170.,
                           lon1=-156.65,
                           lat0=67.0,
                           lat1=80.0,
                           name='West Canada Basin',
                           author=author,
                           tags='Canada_Basin;Arctic;Arctic_Basin')
    fcCB = fcCB1.difference(fcContour300)
    fcCB = fcCB1.difference(fcCB)
    fcCB2 = make_rectangle(lon0=-156.65,
                           lon1=-100.0,
                           lat0=67.0,
                           lat1=80.0,
                           name='East Canada Basin',
                           author=author,
                           tags='Canada_Basin;Arctic;Arctic_Basin')
    fcCB2 = fcCB2.difference(fcCAA)
    fcCB.merge(fcCB2)
    fcCB = fcCB.combine('Canada Basin')
    props = fcCB.features[0]['properties']
    props['tags'] = 'Canada_Basin;Arctic;Arctic_Basin'
    props['author'] = author
    fc.merge(fcCB)

    # ********* Chukchi Sea (new feature) *********

    # This supersedes the old Chukchi Sea feature
    fcChukchi = make_rectangle(lon0=-180.,
                               lon1=-156.65,
                               lat0=65.0,
                               lat1=80.0,
                               name='Chukchi Sea',
                               author=author,
                               tags='Chukchi_Sea;Arctic;Arctic_Basin')
    fcChukchi = fcChukchi.difference(fcContour300)
    fcChukchi_NSIDC = gf.read('ocean', 'region', ['Chukchi Sea NSIDC'])
    fcChukchi_todiscard = fcChukchi.difference(fcChukchi_NSIDC)
    fcChukchi = fcChukchi.difference(fcChukchi_todiscard)
    props = fcChukchi.features[0]['properties']
    props['tags'] = 'Chukchi_Sea;Arctic;Arctic_Basin'
    props['author'] = author
    fc.merge(fcChukchi)

    # ********* East Siberian Sea (new feature) *********

    # This supersedes the old East Siberian Sea feature
    fcESS = make_rectangle(lon0=142.,
                           lon1=180.0,
                           lat0=68.5,
                           lat1=80.0,
                           name='East Siberian Sea',
                           author=author,
                           tags='East_Siberian_Sea;Arctic;Arctic_Basin')
    fcESS = fcESS.difference(fcContour300)
    props = fcESS.features[0]['properties']
    props['tags'] = 'East_Siberian_Sea;Arctic;Arctic_Basin'
    props['author'] = author
    fc.merge(fcESS)

    # ********* Laptev Sea (new feature) *********

    # This supersedes the old Laptev Sea feature
    fcLap = make_rectangle(lon0=90.,
                           lon1=142.0,
                           lat0=70.0,
                           lat1=81.25,
                           name='Laptev Sea',
                           author=author,
                           tags='Laptev_Sea;Arctic;Arctic_Basin')
    fcLap = fcLap.difference(fcContour300)
    fcKara = gf.read('ocean', 'region', ['Kara Sea'])
    fcLap = fcLap.difference(fcKara)
    props = fcLap.features[0]['properties']
    props['tags'] = 'Laptev_Sea;Arctic;Arctic_Basin'
    props['author'] = author
    fc.merge(fcLap)

    # ********* Central Arctic (new feature) *********

    # Define Central Arctic region as Arctic Ocean minus Canadian
    # Archipelago, Canada Basin, Chukchi Sea, ESS, and Laptev Sea
    fcArctic = gf.read('ocean', 'region', ['Arctic Ocean'])
    fcCentralArctic = fcArctic.difference(fcCAA)
    fcCentralArctic = fcCentralArctic.difference(fcCB)
    fcCentralArctic = fcCentralArctic.difference(fcChukchi)
    fcCentralArctic = fcCentralArctic.difference(fcESS)
    fcCentralArctic = fcCentralArctic.difference(fcLap)
    props = fcCentralArctic.features[0]['properties']
    props['name'] = 'Central Arctic'
    props['tags'] = 'Central_Arctic;Arctic;Arctic_Basin'
    props['author'] = author
    fc.merge(fcCentralArctic)

    # *********** Third, complete definition of seaice-relevant ***********
    # ***** Arctic regions, started in part I, according to NSIDC
    # ***** (regions map: https://nsidc.org/data/masie/browse_regions)
    # ****  and identified with tag='Arctic_NSIDC'

    # ********* New Chukchi Sea NSIDC (modified feature) *********

    # This supersedes the Chukchi Sea NSIDC feature defined in part I
    fcChukchi_NSIDC = FeatureCollection()
    fcChukchi_NSIDC.add_feature({
        "type": "Feature",
        "properties": {
            "name": 'Chukchi Sea NSIDC',
            "author": author,
            "object": 'region',
            "component": 'ocean',
            "tags": 'Chukchi_Sea_NSIDC;Arctic_NSIDC'
        },
        "geometry": {
            "type":
            "Polygon",
            "coordinates": [[[-156.65, 65.37], [-180.0, 66.0], [-180.0, 80.0],
                             [-156.48, 80.0], [-156.65, 65.37]]]
        }
    })
    fc.merge(fcChukchi_NSIDC)

    # ********* Beaufort Sea NSIDC (new feature) *********

    fcBS_NSIDC = FeatureCollection()
    fcBS_NSIDC.add_feature({
        "type": "Feature",
        "properties": {
            "name": 'Beaufort Sea NSIDC',
            "author": author,
            "object": 'region',
            "component": 'ocean',
            "tags": 'Beaufort_Sea_NSIDC;Arctic_NSIDC'
        },
        "geometry": {
            "type":
            "Polygon",
            "coordinates":
            [[[-156.65, 65.37], [-156.48, 80.0], [-112.34, 77.69],
              [-124.58, 75.67], [-124.0, 65.0], [-156.65, 65.37]]]
        }
    })
    fc.merge(fcBS_NSIDC)

    # ********* Canadian Archipelago NSIDC (new feature) *********

    fcCAA_NSIDC = FeatureCollection()
    fcCAA_NSIDC.add_feature({
        "type": "Feature",
        "properties": {
            "name": 'Canadian Archipelago NSIDC',
            "author": author,
            "object": 'region',
            "component": 'ocean',
            "tags": 'Canadian_Archipelago_NSIDC;Arctic_NSIDC'
        },
        "geometry": {
            "type":
            "Polygon",
            "coordinates":
            [[[-103.41, 60.69], [-124.0, 65.0], [-124.58, 75.67],
              [-112.34, 77.69], [-69.33, 82.67], [-81.21, 71.79],
              [-83.94, 70.43], [-84.45, 67.27], [-93.04, 65.70],
              [-103.41, 60.69]]]
        }
    })
    fc.merge(fcCAA_NSIDC)

    # ********* Hudson Bay NSIDC (new feature) *********

    fcHudson_NSIDC = FeatureCollection()
    fcHudson_NSIDC.add_feature({
        "type": "Feature",
        "properties": {
            "name": 'Hudson Bay NSIDC',
            "author": author,
            "object": 'region',
            "component": 'ocean',
            "tags": 'Hudson_Bay_NSIDC;Arctic_NSIDC'
        },
        "geometry": {
            "type":
            "Polygon",
            "coordinates": [[[-81.24, 49.19], [-103.41, 60.69],
                             [-93.04, 65.70], [-84.45, 67.27], [-83.94, 70.43],
                             [-81.21, 71.79], [-70.70, 66.95], [-70.12, 65.99],
                             [-63.70, 57.35], [-81.24, 49.19]]]
        }
    })
    fc.merge(fcHudson_NSIDC)

    # ********* Baffin Bay NSIDC (new feature) *********

    fcBaffin_NSIDC = FeatureCollection()
    fcBaffin_NSIDC.add_feature({
        "type": "Feature",
        "properties": {
            "name": 'Baffin Bay NSIDC',
            "author": author,
            "object": 'region',
            "component": 'ocean',
            "tags": 'Baffin_Bay_NSIDC;Arctic_NSIDC'
        },
        "geometry": {
            "type":
            "Polygon",
            "coordinates": [[[-53.20, 42.0], [-68.07, 38.38], [-76.82, 48.01],
                             [-60.85, 54.33], [-63.70, 57.35], [-70.12, 65.99],
                             [-70.70, 66.95], [-81.21, 71.79], [-69.33, 82.67],
                             [-45.0, 60.0], [-45.0, 42.0], [-53.20, 42.0]]]
        }
    })
    fc.merge(fcBaffin_NSIDC)

    # ********* Central Arctic NSIDC (new feature) *********

    fcCentralArctic_NSIDC = FeatureCollection()
    fcCentralArctic_NSIDC.add_feature({
        "type": "Feature",
        "properties": {
            "name": 'Central Arctic NSIDC',
            "author": author,
            "object": 'region',
            "component": 'ocean',
            "tags": 'Central_Arctic_NSIDC;Arctic_NSIDC'
        },
        "geometry": {
            "type":
            "Polygon",
            "coordinates": [[[180.0, 80.0], [180.0, 90.0], [-69.33, 90.0],
                             [-180.0, 90.0], [-180.0, 80.0], [-156.48, 80.0],
                             [-112.34, 77.69], [-69.33, 82.67],
                             [-51.66, 74.25], [-12.72, 81.41], [18.99, 79.18],
                             [58.68, 81.08], [94.95, 81.08], [145.0, 80.0],
                             [180.0, 80.0]]]
        }
    })
    fc.merge(fcCentralArctic_NSIDC)

    # "split" these features into individual files in the geometric data cache
    gf.split(fc)

    # update the database of feature names and tags
    write_feature_names_and_tags(gf.cacheLocation)
    # move the resulting file into place
    shutil.copyfile('features_and_tags.json',
                    '../../geometric_features/features_and_tags.json')

    # Fix features if necessary
    fcArcticTags = gf.read(componentName='ocean',
                           objectType='region',
                           tags=['Arctic'])
    for feature in fcArcticTags.features:
        featureName = feature['properties']['name']
        shape = shapely.geometry.shape(feature['geometry'])
        print('{} is_valid: {}'.format(featureName, shape.is_valid))
        if not shape.is_valid:
            fixed = shape.buffer(0)
            print('  Fixed? {}'.format(fixed.is_valid))
            feature['geometry'] = shapely.geometry.mapping(fixed)
    fcArcticTags.plot(projection='northpole')
    fcArcticTags.to_geojson('arctic_ocean_regions.geojson')

    fcArcticNSIDCTags = gf.read(componentName='ocean',
                                objectType='region',
                                tags=['Arctic_NSIDC'])
    for feature in fcArcticNSIDCTags.features:
        featureName = feature['properties']['name']
        shape = shapely.geometry.shape(feature['geometry'])
        print('{} is_valid: {}'.format(featureName, shape.is_valid))
        if not shape.is_valid:
            fixed = shape.buffer(0)
            print('  Fixed? {}'.format(fixed.is_valid))
            feature['geometry'] = shapely.geometry.mapping(fixed)
    fcArcticNSIDCTags.plot(projection='northpole')
    fcArcticNSIDCTags.to_geojson('arcticNSIDC_ocean_regions.geojson')

    fcArctic = fcArcticTags
    fcArctic.merge(fcArcticNSIDCTags)

    # "split" these features into individual files in the geometric data cache
    gf.split(fcArctic)

    # update the database of feature names and tags
    write_feature_names_and_tags(gf.cacheLocation)
    # move the resulting file into place
    shutil.copyfile('features_and_tags.json',
                    '../../geometric_features/features_and_tags.json')

    plt.show()