Beispiel #1
0
def reproject(layer: ogr.Layer, srs: osr.SpatialReference):
    '''Reprojects an existing layer given a spatial reference'''
    layer_name = layer.GetName()
    logging.info(f'reprojecting {layer_name}')

    projection = layer.GetSpatialRef()
    if projection is None:
        raise baseException(
            f'layer: {layer_name} does not have a spatial reference.',
            baseException.ERR_INPUT_LEVEL)

    # no action needed
    if projection.IsSame(srs):
        logging.info('no reprojection required')
        return

    try:
        # transform
        coordTrans = osr.CoordinateTransformation(projection, srs)

        # copy features
        layer.ResetReading()

        for ft in layer:
            geom = ft.GetGeometryRef()
            geom.Transform(coordTrans)
            ft.SetGeometry(geom)
    except Exception as e:
        raise baseException(f'layer: {layer_name} could not be reprojected.',
                            baseException.ERR_CODE_LEVEL, e)
Beispiel #2
0
def reproject_shapefile(fp: str, srs: osr.SpatialReference, out_dir: str) -> str:
  '''Reprojects an existing layer given a spatial reference'''
  logging.info(f'reprojecting {fp}')
  driver = ogr.GetDriverByName('ESRI Shapefile')

  # check if reprojection is needed
  in_ds = driver.Open(fp)
  in_srs = in_ds.GetLayer().GetSpatialRef()

  # no spatial reference found
  if in_srs is None:
    raise baseException(f'layer: {in_ds.GetLayer().GetName()} does not have a spatial reference.',
                        baseException.ERR_INPUT_LEVEL)

  # spatial references match, no action needed
  if in_srs.IsSame(srs):
    logging.info('no reprojection required')
    in_ds.Release()
    in_ds = None
    return fp

  # copy datasource
  out = os.path.join(out_dir, os.path.basename(fp))
  out_ds = driver.CopyDataSource(in_ds, out)
  layer = out_ds.GetLayer()

  try:
    # transform
    coordTrans = osr.CoordinateTransformation(in_srs, srs)

    # copy features
    layer.ResetReading()

    for ft in layer:
      geom = ft.GetGeometryRef()
      geom.Transform(coordTrans)
      ft.SetGeometry(geom)
  except Exception as e:
    raise baseException(f'layer: {layer.GetName()} could not be reprojected.',
                        baseException.ERR_CODE_LEVEL, e)
  finally:
    in_ds.Release()
    out_ds.Release()
    in_ds, out_ds = None, None
  
  return out
Beispiel #3
0
def close_shapefile(shp: ogr.DataSource) -> str:
    '''Closes the shapefile'''
    logging.info(f'closing shapefile {shp.GetName()}')
    try:
        shp.Release()
        shp = None
    except Exception as e:
        raise baseException(f'shapefile: {shp.GetName()} could not be closed',
                            baseException.ERR_CODE_LEVEL, e)
Beispiel #4
0
def open_shapefile(fp: str, edit: bool = False) -> ogr.DataSource:
    '''Returns an opened ogr DataSource in r/w mode'''
    logging.info(f'opening shapefile {fp}')
    try:
        driver = ogr.GetDriverByName('ESRI Shapefile')
        return driver.Open(fp, int(edit))
    except Exception as e:
        raise baseException(f'shapefile: {fp} could not be opened.',
                            baseException.ERR_CODE_LEVEL, e)
def make_dir(path: str):
  '''Create a new dictory given path'''
  if not os.path.exists(path):
    try:
      os.makedirs(path)
      logging.info(f'created directory {path}')
    except OSError as e:
      if e.errno != errno.EEXIST:
        raise baseException(f'There was an issue creating the directory {path}.', baseException.ERR_UNK_LEVEL, e)
Beispiel #6
0
def set_label(layout: QgsPrintLayout, item_id: str, text: str):
  '''Set the text for existing layout items'''
  logging.info(f'setting text with label id={item_id}')
  item = layout.itemById(item_id)

  if item is not None:
    item.setText(text)
  else:
    raise baseException(f'item_id {item_id} does not exist', 
                        baseException.ERR_CODE_LEVEL)
Beispiel #7
0
def format_label(layout: QgsPrintLayout, item_id: str, params: List[Union[int, str]]):
  '''Formats the text for existing layout items'''
  logging.info(f'formatting text with label id={item_id}')

  item = layout.itemById(item_id)
  text = item.text().format(*params)

  if item is not None:
    item.setText(text)
  else:
    raise baseException(f'item_id {item_id} does not exist', 
                        baseException.ERR_CODE_LEVEL)
Beispiel #8
0
def open_template(layout: QgsPrintLayout, fp: str):
  '''Load items from template into layout'''
  logging.info(f'opening template: {fp}')
  doc = QDomDocument()
  context = QgsReadWriteContext()

  # read template
  with open(fp, 'rt', encoding='utf-8') as f:
    content = f.read()

  # set content and load items from template
  doc.setContent(content)
  _, ok = layout.loadFromTemplate(doc, context)
  if not ok:
    raise baseException(f'failed to load QGS template: {fp}',
                        baseException.ERR_CODE_LEVEL)
def set_median_predom(const: dict, layer: ogr.Layer, region: str, *unused):
    '''Set the Median Predominance burn-in value'''
    try:
        burn_field = const['burn_field']
        burn = ogr.FieldDefn(burn_field, ogr.OFTInteger)

        layer.CreateField(burn)

        # set burn-in values for each feature
        logging.info('setting median predominance')
        layer.ResetReading()
        for ft in layer:
            predominant = get_predom(const, ft)
            ft.SetField(burn_field, predominant)
            layer.SetFeature(ft)

    except Exception as e:
        raise baseException(
            f'could not set values in {layer.GetName()} for median predominance',
            baseException.ERR_CODE_LEVEL, e)
def set_median_ct(const: dict, layer: ogr.Layer, region: str, ice_type: str,
                  *unused):
    '''Set the Median Concentration burn-in value'''
    try:
        water, land, nodata = const['water'], const['land'], const['nodata']
        burn_field = const['burn_field']
        burn = ogr.FieldDefn(burn_field, ogr.OFTInteger)

        layer.CreateField(burn)

        # set burn-in values for each feature
        logging.info('setting median ct')
        layer.ResetReading()
        for ft in layer:
            fa = ft.GetField('FA')
            fb = ft.GetField('FB')
            fc = ft.GetField('FC')
            concn = ft.GetField(ice_type)

            if concn is None or concn == '':
                concn = water
            elif '08' in [fa, fb, fc] and concn in ['9.7', '10.0']:
                concn = '11.0'
            elif '07' in [fa, fb, fc] and concn == '10.0':
                concn = '10.0'
            ft.SetField(burn_field, int(float(concn)))

            pnt_type = ft.GetField('PNT_TYPE')
            if pnt_type in ['101', '115', '107']:
                ft.SetField(burn_field, water)
            elif pnt_type in ['400', '900']:
                ft.SetField(burn_field, land)
            elif pnt_type in ['123', '128', '133', '143']:
                ft.SetField(burn_field, nodata)

            layer.SetFeature(ft)

    except Exception as e:
        raise baseException(
            f'could not set values in {layer.GetName()} for median concentration',
            baseException.ERR_CODE_LEVEL, e)
Beispiel #11
0
def set_frequency(const: dict,
                  layer: ogr.Layer,
                  region: str,
                  ice_type: str,
                  threshold: int = 1):
    '''Set the Frequency burn-in value'''
    try:
        water, nodata = const['water'], const['nodata']
        burn_field = const['burn_field']
        burn = ogr.FieldDefn(burn_field, ogr.OFTInteger)

        layer.CreateField(burn)

        # set burn-in values for each feature
        logging.info(f'setting frequency using threshold: {threshold}')
        layer.ResetReading()
        for ft in layer:
            pnt_type = ft.GetField('PNT_TYPE')
            concn = ft.GetField(ice_type)
            concn = 0.0 if not concn else float(concn)

            if pnt_type in ['101', '107', '115', '400', '900']:
                ft.SetField(burn_field, water)
            elif pnt_type in ['123', '128', '133', '143']:
                ft.SetField(burn_field, nodata)
            elif pnt_type in ['106', '117', '118', '120', '122', '144'
                              ] and concn >= float(threshold):
                ft.SetField(burn_field, 1)
            elif pnt_type in ['106', '117', '118', '120', '122', '144'
                              ] and concn < float(threshold):
                ft.SetField(burn_field, water)
            else:
                ft.SetField(burn_field, nodata)

            layer.SetFeature(ft)

    except Exception as e:
        raise baseException(
            f'could not set values in {layer.GetName()} for frequency',
            baseException.ERR_CODE_LEVEL, e)
Beispiel #12
0
def open_layer(project: QgsProject, fp: str) -> QgsLayer:
  '''Opens and returns a QgsVectorLayer/QgsRasterLayer'''
  if fp is None:
    return None

  logging.info(f'opening layer: {fp}')
  basename, ext = os.path.splitext(os.path.basename(fp))
  vector = not (ext in ['.tif', '.tiff'])

  # create vector or raster layer
  if vector:
    layer = QgsVectorLayer(fp, basename)
  else:
    layer = QgsRasterLayer(fp, basename)

  if not layer.isValid():
    raise baseException(f'failed to load layer: {fp}', 
                        baseException.ERR_CFG_LEVEL)

  # add layer to project
  project.addMapLayer(layer)
  return layer
Beispiel #13
0
def make_dummy(ds: ogr.DataSource, name: str, burn: Tuple) -> ogr.DataSource:
    '''Returns a dummy layer for CTMED populated with burn[1] values'''
    logging.info(f'creating dummy: {name} layer')

    try:
        # create dummy layer
        mem = create_shapefile('memory', 'MEMORY')
        dummy = mem.CopyLayer(ds.GetLayer(), name, ['OVERWRITE=YES'])

        # add burn field and populate
        fdefn = ogr.FieldDefn(burn[0], ogr.OFTInteger)
        dummy.CreateField(fdefn)

        dummy.ResetReading()
        for ft in dummy:
            ft.SetField(burn[0], burn[1])
            dummy.SetFeature(ft)

        return mem

    except Exception as e:
        close_shapefile(ds)
        raise baseException(f'dummy: {name} layer could not be created.',
                            baseException.ERR_CODE_LEVEL, e)
Beispiel #14
0
def main():
    args = argparser_init()
    args.config = os.path.join(ROOT, args.config)

    with BaseHandler(args.inputs, args.config) as chart:
        chart.start_logging()
        chart.set_methods(set_frequency, calc_frequency, set_frequency_colours)
        chart.start()

    return 0


if __name__ == '__main__':
    try:
        status = main()
    except Exception as e:
        status = 1
        # pylint: disable=no-member
        if isinstance(e, baseException):
            print(e.to_json())
        else:
            if hasattr(e, 'message'):
                print(
                    baseException(e.message, baseException.ERR_UNK_LEVEL,
                                  e).to_json())
            else:
                print(
                    baseException('', baseException.ERR_UNK_LEVEL,
                                  e).to_json())
    finally:
        sys.exit(status)
Beispiel #15
0
def calc_freezeup(config: dict, ctmeds: str, region: str, threshold: int,
                  out: str):
    '''
  Calculates Freezeup Dates
  
  Parameters:
    config: config file as JSON
    ctmeds: directory containing f'{region}_{chart}{date}.tif' files
    region: region to make chart for
    threshold: minimum concentration [0-10]
    out: output file path
  '''
    logging.info(
        f'calculating freezeup using threshold: {threshold} for {region}')

    const = config['constants']
    pixel_size = const['pixel_size']
    land, nodata = const['land'], const['nodata']

    dates = config['ctfup']
    hd = dates.get(region, dates['default'])

    # retrieve relevant rasters
    # reason: AddBand is not supported. Cannot add bands dynamically
    rasters, missing = [], []
    for date in hd:
        found = False
        pattern = f'{region.lower()}_ctmed{date}'

        for f in os.listdir(ctmeds):
            fn, ext = os.path.splitext(f)

            if fn.startswith(pattern) and ext == '.tif':
                rasters.append(os.path.join(ctmeds, f))
                found = True

        if not found:
            missing.append(date)

    # ensure all ctmeds present
    if missing:
        fn = os.path.splitext(os.path.basename(out))[0]
        raise baseException(
            f'unable to create {fn} - insufficient ctmed charts, missing {missing}',
            baseException.ERR_CODE_LEVEL)

    try:
        # get aoi info
        aoi = open_shapefile(os.path.join(*config[region]['aoi']))
        spref = aoi.GetLayer().GetSpatialRef()
        extent = round_extent(aoi, pixel_size)
        close_shapefile(aoi)

        # stack all bands
        stack = []
        for r in rasters:
            tmp_ds = gdal.Open(r)
            tmp_band = tmp_ds.GetRasterBand(1).ReadAsArray()
            stack.append(tmp_band)
            tmp_ds = None
        stack = np.array(stack)

        # create land grid from band = 1
        band = stack[0]
        land = np.where(band < land, nodata, land)

        # create zero grid
        zero = np.where(np.logical_or(band > (land - 1), band == nodata),
                        nodata, 0)

        # add historic date attributes
        tmp_grid1 = (np.logical_and(stack >= threshold * 10,
                                    stack <= 100)).astype(int)
        tmp_grid2 = np.full(tmp_grid1.shape, nodata, dtype=int)

        for i in range(stack.shape[0]):
            tmp_grid2[i] = np.where(tmp_grid1[i] == 1, int(hd[i]), nodata)

        # merge - for each column, retrieve the index of first non-null
        tmp_grid3 = np.vstack((land[None], tmp_grid2, zero[None]))

        mask = tmp_grid3 != nodata
        index = np.where(mask.any(axis=0), mask.argmax(axis=0), -1)
        idx, idy = np.ogrid[0:index.shape[0], 0:index.shape[1]]
        result = tmp_grid3[index[idx, idy], idx, idy]

    except Exception as e:
        raise baseException('error calculating freezeup.',
                            baseException.ERR_CODE_LEVEL, e)

    try:
        tif = create_tif(out, extent, spref, pixel_size)
        set_nodata(tif, nodata)
        save_array(tif, result)
        tif = None
    except Exception as e:
        raise baseException('error saving raster results for freezeup.',
                            baseException.ERR_CODE_LEVEL, e)