def time_equal(a, b):
    if (a is None) and (b is None):
        return True
    elif (a is None) or (b is None):
        return False
    else:
        return _to_datetime(a) == _to_datetime(b)
Exemple #2
0
def coordinates(valid_time, initial_time, pressures, pressure):
    valid = _to_datetime(valid_time)
    initial = _to_datetime(initial_time)
    hours = (valid - initial).total_seconds() / (60 * 60)
    length = "T{:+}".format(int(hours))
    level = "Sea Surface"
    return {
        'valid': [valid],
        'initial': [initial],
        'length': [length],
        'level': [level]
    }
    def _load_cube(self, path, variable, lon0, lat0, time=None):
        """ Load vertical profile slice from file via iris. """

        try:
            cube = iris.load_cube(path, variable)
        except iris.exceptions.ConstraintMismatchError as e:
            print("WARNING: {} No data found for profile plot".format(type(e).__name__))
            return {
                "x": [],
                "y": []}

        # reference longitude axis by "axis='X'" and latitude axis as axis='Y',
        # to accommodate various types of coordinate system.
        # e.g. 'grid_longitude'. See iris.utils.guess_coord_axis.
        if cube.coord(axis='X').points[-1] > 180.0:
            # get circular longitude values
            lon0 = iris.analysis.cartography.wrap_lons(np.asarray(lon0), 0, 360)
        # Construct constraint
        lon_nearest = _find_nearest(lon0, cube.coord(axis='X').points)
        lat_nearest = _find_nearest(lat0, cube.coord(axis='Y').points)
        coord_values={
            cube.coord(axis='X').standard_name: (lambda cell: lon_nearest == cell.point),
            cube.coord(axis='Y').standard_name: (lambda cell: lat_nearest == cell.point),
            }
        if time is not None and 'time' in [coord.name() for coord in cube.coords()]:
            coord_values['time'] = (
                lambda cell: _to_datetime(time) == cell
            )
        constraint = iris.Constraint(coord_values=coord_values)

        # Extract nearest profile
        cube = cube.extract(constraint)
        assert cube is not None, ("Error: No profile data found for {}\n\t"
                                  "at these coordinates: time,lat,lon {},{},{}").format(
                                  path, _to_datetime(time), lat_nearest, lon_nearest)

        # Get level info and data values
        if 'pressure' in [coord.name() for coord in cube.coords()]:
            pressure_coord = cube.coord('pressure')
            pressures = pressure_coord.points.tolist()
        else:
            pressures = [0,]
        if time is None and 'time' in [coord.name() for coord in cube.coords()]:
            print("Warning: no time specified, selecting first element of array")
            values = cube.data[0,...]
        else:
            values = cube.data

        return {
            "x": values,
            "y": pressures}
def coordinates(valid_time, initial_time, pressures, pressure):
    valid = _to_datetime(valid_time)
    initial = _to_datetime(initial_time)
    hours = (valid - initial).total_seconds() / (60 * 60)
    length = "T{:+}".format(int(hours))
    if (len(pressures) > 0) and (pressure is not None):
        level = "{} hPa".format(int(pressure))
    else:
        level = "Surface"
    return {
        'valid': [valid],
        'initial': [initial],
        'length': [length],
        'level': [level]
    }
def select_args(state):
    """Select args needed by :func:`ProfileView.render`

    .. note:: If all criteria are not present None is returned

    :returns: args tuple or None
    """
    if any(att not in state
            for att in [
                "variable",
                "initial_time",
                "position"]):
        return
    if "valid_time" in state:
        optional = (_to_datetime(state["valid_time"]),)
    else:
        optional = ()
    return (
            _to_datetime(state["initial_time"]),
            state["variable"],
            state["position"]["x"],
            state["position"]["y"],
            state["tools"]["profile"]) + optional
 def image(self, state):
     cube = self._cubes[state.variable]
     valid_datetime = _to_datetime(state.valid_time)
     cube = self.extract_cube(cube, valid_datetime)
     if cube is None:
         data = empty_image()
     else:
         data = geo.stretch_image(
             cube.coord('longitude').points,
             cube.coord('latitude').points, cube.data)
         data.update(
             coordinates(state.valid_time, state.initial_time,
                         state.pressures, state.pressure))
         data.update({'name': [self._label], 'units': [str(cube.units)]})
     return data
Exemple #7
0
 def scatter(self, state):
     """Scatter plot of flash position colored by time since flash"""
     valid_time = _to_datetime(state.valid_time)
     paths = self.locator.find(valid_time)
     frame = self.loader.load(paths)
     frame = self.select_date(frame, valid_time)
     frame = frame[:400]  # Limit points
     frame["time_since_flash"] = self.since_flash(frame["date"], valid_time)
     if len(frame) == 0:
         return self.empty_image
     x, y = geo.web_mercator(frame.longitude, frame.latitude)
     self.color_mapper.low = np.min(frame.time_since_flash)
     self.color_mapper.high = np.max(frame.time_since_flash)
     self.sources["scatter"].data = {
         "x": x,
         "y": y,
         "date": frame.date,
         "longitude": frame.longitude,
         "latitude": frame.latitude,
         "flash_type": frame.flash_type,
         "time_since_flash": frame.time_since_flash,
     }
Exemple #8
0
    def image(self, state):
        cube = self._cubes[state.variable]
        valid_datetime = _to_datetime(state.valid_time)
        cube = cube.extract(iris.Constraint(time=valid_datetime))

        if cube is None:
            data = empty_image()
        else:
            data = geo.stretch_image(
                cube.coord("longitude").points,
                cube.coord("latitude").points,
                cube.data,
            )
            data.update(
                coordinates(
                    state.valid_time,
                    state.initial_time,
                    state.pressures,
                    state.pressure,
                ))
            data.update({"name": [self._label], "units": [str(cube.units)]})
        return data
Exemple #9
0
    def image(self, state):
        """Image colored by time since flash or flash density"""
        valid_time = _to_datetime(state.valid_time)

        # 15 minute/1 hour slice of data?
        window = dt.timedelta(minutes=60)  # 1 hour window
        paths = self.locator.find_period(valid_time, window)
        frame = self.loader.load(paths)
        frame = self.select_date(frame, valid_time, window)

        # Filter intra-cloud/cloud-ground rows
        if "intra-cloud" in state.variable.lower():
            frame = frame[frame["flash_type"] == "IC"]
        elif "cloud-ground" in state.variable.lower():
            frame = frame[frame["flash_type"] == "CG"]

        # EarthNetworks validity box (not needed if tiling algorithm)
        longitude_range = (26, 40)
        latitude_range = (-12, 4)
        x_range, y_range = geo.web_mercator(longitude_range, latitude_range)

        x, y = geo.web_mercator(frame["longitude"], frame["latitude"])
        frame["x"] = x
        frame["y"] = y
        pixels = 256
        canvas = datashader.Canvas(
            plot_width=pixels,
            plot_height=pixels,
            x_range=x_range,
            y_range=y_range,
        )

        if "density" in state.variable.lower():
            # N flashes per pixel
            agg = canvas.points(frame, "x", "y", datashader.count())
        else:
            frame["since_flash"] = self.since_flash(frame["date"], valid_time)
            agg = canvas.points(frame, "x", "y", datashader.max("since_flash"))

        # Note: DataArray objects are not JSON serializable, .values is the
        #       same data cast as a numpy array
        x = agg.x.values.min()
        y = agg.y.values.min()
        dw = agg.x.values.max() - x
        dh = agg.y.values.max() - y
        image = np.ma.masked_array(
            agg.values.astype(np.float), mask=np.isnan(agg.values)
        )
        if "density" in state.variable.lower():
            image[image == 0] = np.ma.masked  # Remove pixels with no data

        # Update color_mapper
        color_mapper = self.color_mappers["image"]
        if "density" in state.variable.lower():
            color_mapper.palette = bokeh.palettes.all_palettes["Spectral"][8]
            color_mapper.low = 0
            color_mapper.high = agg.values.max()
        else:
            color_mapper.palette = bokeh.palettes.all_palettes["RdGy"][8]
            color_mapper.low = 0
            color_mapper.high = 60 * 60  # 1 hour

        # Update tooltips
        for hover_tool in self.hover_tools["image"]:
            hover_tool.tooltips = self.tooltips(state.variable)
            hover_tool.formatters = self.formatters(state.variable)

        if "density" in state.variable.lower():
            units = "events"
        else:
            units = "seconds"

        data = {
            "x": [x],
            "y": [y],
            "dw": [dw],
            "dh": [dh],
            "image": [image],
        }
        meta_data = {
            "variable": [state.variable],
            "date": [valid_time],
            "units": [units],
            "window": [window.total_seconds()],
        }
        data.update(meta_data)
        self.sources["image"].data = data
Exemple #10
0
 def _key(t):
     return str(_to_datetime(t))
Exemple #11
0
 def datetimes(self):
     return [_to_datetime(t) for t in self.times]