def image(self, state): if not self.valid(state): return gridded_forecast.empty_image() try: path, pts = self.locator.locate(self.pattern, state.variable, state.initial_time, state.valid_time, state.pressure) except SearchFail: print("Search failed: {}".format(self.pattern)) return gridded_forecast.empty_image() print(path, pts) units = self.read_units(path, state.variable) data = load_image_pts(path, state.variable, pts, pts) if (len(state.pressures) > 0) and (state.pressure is not None): level = "{} hPa".format(int(state.pressure)) else: level = "Surface" data.update( gridded_forecast.coordinates(state.valid_time, state.initial_time, state.pressures, state.pressure)) data["name"] = [self.name] data["units"] = [units] return data
def test(self): result = gridded_forecast.empty_image() self.assertEqual( result.keys(), { 'x', 'y', 'dw', 'dh', 'image', 'name', 'units', 'valid', 'initial', 'length', 'level' }) for value in result.values(): self.assertEqual(value, [])
def image(self, state): '''gets actual data. X and Y passed to :meth:`geo.stretch_image` must be 1D arrays. NWCSAF data are not on a regular grid so must be regridded. `values` passed to :meth:`geo.stretch_image` must be a NumPy Masked Array. :param state: Bokeh State object of info from UI :returns: Output data from :meth:`geo.stretch_image`''' data = empty_image() for nc in self.locator._sets: if str( datetime.datetime.strptime( nc.nominal_product_time.replace('Z', 'UTC'), '%Y-%m-%dT%H:%M:%S%Z') ) == state.valid_time and self.locator.varlist[ state.variable] in nc.variables: #regrid to regular grid x = nc['lon'][:].flatten() # lat & lon both 2D arrays y = nc['lat'][:].flatten() # z = nc[self.locator.varlist[state.variable]][:].flatten() #define grid xi, yi = np.meshgrid( np.linspace(x.min(), x.max(), nc.dimensions['nx'].size), np.linspace(y.min(), y.max(), nc.dimensions['ny'].size), ) zi = griddata(np.array([x, y]).transpose(), z, (xi, yi), method='linear', fill_value=np.nan) zi = np.ma.masked_invalid(zi, copy=False) zi = np.ma.masked_outside( zi, nc[self.locator.varlist[state.variable]].valid_range[0], nc[self.locator.varlist[state.variable]].valid_range[1], copy=False) data = geo.stretch_image(xi[0, :], yi[:, 0], zi) #data = geo.stretch_image(x[0,:], y[:,0], nc[state.variable][:]) data.update( coordinates(state.valid_time, state.initial_time, state.pressures, state.pressure)) data.update({ 'name': [str(nc[self.locator.varlist[state.variable]].long_name)], }) if 'units' in nc[self.locator.varlist[ state.variable]].ncattrs(): data.update({ 'units': [str(nc[self.locator.varlist[state.variable]].units)] }) return data
def image(self, state): """ Main image loading function. This function will actually realise the data, """ if self.variable_id != state.variable: self.variable_id = state.variable self._cube = None valid_time = state.valid_time pressure = state.pressure selected_time = gridded_forecast._to_datetime(valid_time) # the guts of creating the bokeh object has been put into a separate # function so that it can be cached, so if image is called multiple # time the calculations are only done once (hopefully). cube = self.cube coord_names = [c1.name() for c1 in cube.coords()] if 'air_pressure' in coord_names and pressure is None: data = gridded_forecast.empty_image() return data data = _get_bokeh_image(cube, self.experiment_id, self.variable_id, self.institution_id, state.initial_time, self.member_id, selected_time, pressure) data.update(gridded_forecast.coordinates(str(selected_time), state.initial_time, state.pressures, pressure)) data.update({ 'name': [self._label], 'units': [str(cube.units)], 'experiment': [self.experiment_id], 'institution': [self.institution_id], 'memberid': [self.member_id], 'variableid': [self.variable_id] }) return data
def _get_bokeh_image(cube, experiment_id, variable_id, institution_id, initial_time, member_id, selected_time, pressure, ): """ A helper function to do the creation of the image dict required by bokeh. This includes downloading the actual data required for the current view, so this function is cached to reduce remote queries. """ def time_comp(select_time, time_cell): # data_time = gridded_forecast._to_datetime(time_cell.point) if abs((select_time - data_time).days) < 2: return True return False def lat_filter(lat): """ Due to the way the current projection of gridded data works, the poles are not well handled, resulting in NaNs if we use the full range of latitudes. The current hack is to chop off latitude greater than 85 degrees north and south. Given the importance of data at the poles in climate change research, we will need to fix this in future. """ return -85.0 < lat < 85.0 def pressure_select(select_pressure, data_pressure): return abs(select_pressure - data_pressure.point) < 1.0 if cube is None or initial_time is None: data = gridded_forecast.empty_image() else: constraint_dict = {'time': functools.partial(time_comp, selected_time), 'latitude': lat_filter, } coord_names = [c1.name() for c1 in cube.coords()] if 'air_pressure' in coord_names: constraint_dict['air_pressure'] = functools.partial( pressure_select, pressure, ) cube_cropped = cube.extract(iris.Constraint(**constraint_dict)) lat_pts = cube_cropped.coord('latitude').points long_pts = cube_cropped.coord('longitude').points - 180.0 cube_data_cropped = cube_cropped.data cube_width = int(cube_data_cropped.shape[1] / 2) cube_data_cropped = numpy.concatenate( [cube_data_cropped[:, cube_width:], cube_data_cropped[:, :cube_width]], axis=1) data = geo.stretch_image(long_pts, lat_pts, cube_data_cropped) data['image'] = [numpy.ma.masked_array(data['image'][0], mask=numpy.isnan( data['image'][0]))] return data