def plot_v1_0(): if request.method == 'GET': args = request.args else: args = request.form query = json.loads(args.get('query')) with open_dataset(get_dataset_url(query.get('dataset'))) as dataset: if 'time' in query: query['time'] = dataset.convert_to_timestamp(query.get('time')) else: query['starttime'] = dataset.convert_to_timestamp( query.get('starttime')) query['endtime'] = dataset.convert_to_timestamp( query.get('endtime')) resp = routes.routes_impl.plot_impl(args, query) m = hashlib.md5() m.update(str(resp).encode()) if 'data' in request.args: plotData = { 'data': str(resp), 'shape': resp.shape, 'mask': str(resp.mask) } plotData = json.dumps(plotData) return Response(plotData, status=200, mimetype='application/json') return resp
def range_query_v1_0(dataset, variable, interp, radius, neighbours, projection, extent, depth, time): with open_dataset(get_dataset_url(dataset)) as ds: date = ds.convert_to_timestamp(time) return routes.routes_impl.range_query_impl(interp, radius, neighbours, dataset, projection, extent, variable, depth, date)
def load_data(self): with open_dataset(get_dataset_url(self.dataset_name)) as d: if self.time < 0: self.time += len(d.timestamps) time = np.clip(self.time, 0, len(d.timestamps) - 1) timestamp = d.timestamps[time] try: self.load_misc(d, self.variables) except IndexError as e: raise ClientError( gettext( "The selected variable(s) were not found in the dataset. \ Most likely, this variable is a derived product from existing dataset variables. \ Please select another variable. ") + str(e)) point_data, point_depths = self.get_data(d, self.variables, time) point_data = self.apply_scale_factors(point_data) self.variable_units, point_data = self.kelvin_to_celsius( self.variable_units, point_data) self.data = self.subtract_other(point_data) self.depths = point_depths self.timestamp = timestamp
def tile_v1_0(projection, interp, radius, neighbours, dataset, variable, time, depth, scale, zoom, x, y): with open_dataset(get_dataset_url(dataset)) as ds: date = ds.convert_to_timestamp(time) return routes.routes_impl.tile_impl(projection, interp, radius, neighbours, dataset, variable, date, depth, scale, zoom, x, y)
def load_data(self): if not isinstance(self.depth, list): self.depth = [self.depth] self.depth = sorted(self.depth) with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.starttime < 0: self.starttime += len(dataset.timestamps) if self.endtime < 0: self.endtime += len(dataset.timestamps) start = np.clip(self.starttime, 0, len(dataset.timestamps) - 1) end = np.clip(self.endtime, 0, len(dataset.timestamps) - 1) timestamp = dataset.timestamps[start:end + 1] self.load_misc(dataset, self.variables) point_data = [] point_depth = [] for p in self.points: data = [] depth = [] for v in self.variables: dd = [] jj = [] for d in self.depth: da, dp = dataset.get_timeseries_point( float(p[0]), float(p[1]), d, start, end, v, return_depth=True) dd.append(da) jj.append(dp) data.append(np.ma.array(dd)) depth.append(np.ma.array(jj)) point_data.append(np.ma.array(data)) point_depth.append(np.ma.array(depth)) point_data = np.ma.array(point_data) point_depth = np.ma.array(point_depth) for idx, factor in enumerate(self.scale_factors): if factor != 1.0: point_data[idx] = np.multiply(point_data[idx], factor) self.variable_units, point_data = self.kelvin_to_celsius( self.variable_units, point_data) self.data = self.subtract_other(point_data) self.data_depth = point_depth self.timestamp = timestamp
def load_data(self): with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.time < 0: self.time += len(dataset.timestamps) time = np.clip(self.time, 0, len(dataset.timestamps) - 1) self.timestamp = dataset.timestamps[time] self.load_temp_sal(dataset, time) self.variable_units[0], self.temperature = \ super(plPoint.PointPlotter, self).kelvin_to_celsius( self.variable_units[0], self.temperature )
def stats_v1_0(): if request.method == 'GET': args = request.args else: args = request.form query = json.loads(args.get('query')) with open_dataset(get_dataset_url(query.get('dataset'))) as dataset: date = dataset.convert_to_timestamp(query.get('time')) date = {'time': date} query.update(date) return routes.routes_impl.stats_impl(args, query)
def subtract_other(self, data): if self.compare: with Dataset( get_dataset_url(self.compare['dataset']), 'r' ) as dataset: cli = self.get_data( dataset, self.compare['variables'], self.compare['time'] ) for idx, v in enumerate(self.variables): data[:, idx, :] = \ data[:, idx, :] - cli[:, idx, :] return data
def timestamp_for_date_impl(old_dataset, date, new_dataset): """ API Format: /api/timestamp/<string:old_dataset>/<int:date>/<string:new_dataset> <string:old_dataset> : Previous dataset used <int:date> : Date of desired data - Can be found using /api/timestamps/?datasets='...' <string:new_dataset> : Dataset to extract data - Can be found using /api/datasets **Used when Changing datasets** """ with open_dataset(get_dataset_url(old_dataset)) as ds: timestamp = ds.timestamps[date] with open_dataset(get_dataset_url(new_dataset)) as ds: timestamps = ds.timestamps diffs = np.vectorize(lambda x: x.total_seconds())(timestamps - timestamp) idx = np.where(diffs <= 0)[0] res = 0 if len(idx) > 0: res = idx.max().item() # https://stackoverflow.com/a/11389998/2231969 return Response(json.dumps(res), status=200, mimetype='application/json')
def get_scale(dataset, variable, depth, time, projection, extent, interp, radius, neighbours): x = np.linspace(extent[0], extent[2], 50) y = np.linspace(extent[1], extent[3], 50) xx, yy = np.meshgrid(x, y) dest = Proj(init=projection) lon, lat = dest(xx, yy, inverse=True) variables_anom = variable.split(",") variables = [re.sub('_anom$', '', v) for v in variables_anom] with open_dataset(get_dataset_url(dataset)) as ds: timestamp = ds.timestamps[time] d = ds.get_area(np.array([lat, lon]), depth, time, variables[0], interp, radius, neighbours) if len(variables) > 1: d0 = d d1 = ds.get_area(np.array([lat, lon]), depth, time, variables[1], interp, radius, neighbours) d = np.sqrt(d0**2 + d1**2) variable_unit = get_variable_unit(dataset, ds.variables[variables[0]]) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" d = np.add(d, -273.15) if variables != variables_anom: with open_dataset(get_dataset_climatology(dataset), 'r') as ds: c = ds.get_area(np.array([lat, lon]), depth, timestamp.month - 1, variables[0], interp, radius, neighbours) if len(variables) > 1: c0 = c c1 = ds.get_area(np.array([lat, lon]), depth, timestamp.month - 1, variables[1], interp, radius, neighbours) c = np.sqrt(c0**2 + c1**2) d = d - c m = max(abs(d.nanmin()), abs(d.nanmax())) return -m, m # Return min and max values of selected variable, while ignoring # nan values return np.nanmin(d), np.nanmax(d)
def subset_query_impl(args): """ API Format: /subset/?query='...' **Query must be written in JSON and converted to encodedURI** **Not all components of query are required """ working_dir = None subset_filename = None with open_dataset(get_dataset_url(args.get('dataset_name'))) as dataset: working_dir, subset_filename = dataset.subset(args) return send_from_directory(working_dir, subset_filename, as_attachment=True)
def time_query_conversion(dataset, index): """ API Format: /api/timestamps/?dataset=' ' dataset : Dataset to extract data - Can be found using /api/datasets Finds all data timestamps available for a specific dataset """ with open_dataset(get_dataset_url(dataset)) as ds: try: date = ds.timestamps[index] return date.replace(tzinfo=pytz.UTC).isoformat() except IndexError: return ClientError("Timestamp does not exist")
def depth_impl(args): """ API Format: /api/depth/?dataset=''&variable=' ' dataset : Dataset to extract data - Can be found using /api/datasets variable : Type of data to retrieve - found using /api/variables/?dataset='...' Returns all depths available for that variable in the dataset """ #Checking for valid Query if 'variable' not in args or ('dataset' not in args): if 'dataset' in args: raise APIError("Please Specify a variable using &variable='...' ") if 'variable' in args: raise APIError("Please Specify a Dataset using &dataset='...' ") raise APIError( "Please Specify a Dataset and Variable using ?dataset='...'&variable='...' " ) #~~~~~~~~~~~~~~~~~~~~~~~~ var = args.get('variable') variables = var.split(',') variables = [re.sub('_anom$', '', v) for v in variables] data = [] dataset = args['dataset'] with open_dataset(get_dataset_url(dataset)) as ds: for variable in variables: if variable and \ variable in ds.variables and \ set(ds.depth_dimensions) & \ set(ds.variables[variable].dimensions): if str(args.get('all')).lower() in ['true', 'yes', 'on']: data.append({'id': 'all', 'value': gettext('All Depths')}) for idx, value in enumerate(np.round(ds.depths)): data.append({'id': idx, 'value': "%d m" % (value)}) if len(data) > 0: data.insert(0, {'id': 'bottom', 'value': gettext('Bottom')}) data = [e for i, e in enumerate(data) if data.index(e) == i] resp = jsonify(data) return resp
def timestamp_outOfBounds(dataset, time): """ API Format: /api/timestamps/?dataset=' ' dataset : Dataset to extract data - Can be found using /api/datasets Finds all data timestamps available for a specific dataset """ with open_dataset(get_dataset_url(dataset)) as ds: length = len(ds.timestamps) if time < length: return False #Valid timestamp else: print("Timestamp out of bounds") return True
def get_point_data(dataset, variable, time, depth, location): variables_anom = variable.split(",") variables = [re.sub('_anom$', '', v) for v in variables_anom] data = [] names = [] units = [] with open_dataset(get_dataset_url(dataset)) as ds: timestamp = ds.timestamps[time] for v in variables: d = ds.get_point(location[0], location[1], depth, time, v) variable_name = get_variable_name(dataset, ds.variables[v]) variable_unit = get_variable_unit(dataset, ds.variables[v]) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" d = np.add(d, -273.15) data.append(d) names.append(variable_name) units.append(variable_unit) if variables != variables_anom: with open_dataset(get_dataset_climatology(dataset)) as ds: for idx, v in enumerate(variables): d = ds.get_point(location[0], location[1], depth, timestamp.month, v) data[idx] = data[idx] - d names[idx] = names[idx] + " Anomaly" result = { 'value': ['%s' % float('%.4g' % f) for f in data], 'location': [round(f, 4) for f in location], 'name': names, 'units': units, } return result
def time_query_impl(args): """ API Format: /api/timestamps/?dataset=' ' dataset : Dataset to extract data - Can be found using /api/datasets Finds all data timestamps available for a specific dataset """ if 'dataset' not in args: raise APIError("Please Specify a Dataset Using ?dataset='...' ") #~~~~~~~~~~~~~~~~~~~~~~~ data = [] dataset = args['dataset'] quantum = args.get('quantum') with open_dataset(get_dataset_url(dataset)) as ds: for idx, date in enumerate(ds.timestamps): if quantum == 'month': date = datetime.datetime(date.year, date.month, 15) data.append({'id': idx, 'value': date.replace(tzinfo=pytz.UTC)}) data = sorted(data, key=lambda k: k['id']) class DateTimeEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, datetime.datetime): return o.isoformat() return json.JSONEncoder.default(self, o) js = json.dumps(data, cls=DateTimeEncoder) resp = Response(js, status=200, mimetype='application/json') return resp
def scale(args): dataset_name = args.get('dataset') scale = args.get('scale') scale = [float(component) for component in scale.split(',')] variable = args.get('variable') anom = False if variable.endswith('_anom'): variable = variable[0:-5] anom = True variable = variable.split(',') with open_dataset(get_dataset_url(dataset_name)) as dataset: variable_unit = get_variable_unit(dataset_name, dataset.variables[variable[0]]) variable_name = get_variable_name(dataset_name, dataset.variables[variable[0]]) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" if anom: cmap = colormap.colormaps['anomaly'] variable_name = gettext("%s Anomaly") % variable_name else: cmap = colormap.find_colormap(variable_name) if len(variable) == 2: if not anom: cmap = colormap.colormaps.get('speed') variable_name = re.sub( r"(?i)( x | y |zonal |meridional |northward |eastward )", " ", variable_name) variable_name = re.sub(r" +", " ", variable_name) fig = plt.figure(figsize=(2, 5), dpi=75) ax = fig.add_axes([0.05, 0.05, 0.25, 0.9]) norm = matplotlib.colors.Normalize(vmin=scale[0], vmax=scale[1]) formatter = ScalarFormatter() formatter.set_powerlimits((-3, 4)) bar = ColorbarBase(ax, cmap=cmap, norm=norm, orientation='vertical', format=formatter) bar.set_label("%s (%s)" % (variable_name.title(), utils.mathtext(variable_unit)), fontsize=12) # Increase tick font size bar.ax.tick_params(labelsize=12) buf = BytesIO() plt.savefig(buf, format='png', dpi='figure', transparent=False, bbox_inches='tight', pad_inches=0.05) plt.close(fig) buf.seek(0) # Move buffer back to beginning return buf
def load_data(self): if isinstance(self.observation[0], numbers.Number): self.observation_variable_names = [] self.observation_variable_units = [] with Dataset(current_app.config["OBSERVATION_AGG_URL"], 'r') as ds: t = netcdftime.utime(ds['time'].units) for idx, o in enumerate(self.observation): observation = {} ts = t.num2date(ds['time'][o]).replace(tzinfo=pytz.UTC) observation['time'] = ts.isoformat() observation['longitude'] = ds['lon'][o] observation['latitude'] = ds['lat'][o] observation['depth'] = ds['z'][:] observation['depthunit'] = ds['z'].units observation['datatypes'] = [] data = [] for v in sorted(ds.variables): if v in ['z', 'lat', 'lon', 'profile', 'time']: continue var = ds[v] if var.datatype == '|S1': continue observation['datatypes'].append( "%s [%s]" % (var.long_name, var.units)) data.append(var[o, :]) if idx == 0: self.observation_variable_names.append( var.long_name) self.observation_variable_units.append(var.units) observation['data'] = np.ma.array(data).transpose() self.observation[idx] = observation self.points = [[o['latitude'], o['longitude']] for o in self.observation] with open_dataset(get_dataset_url(self.dataset_name)) as dataset: ts = dataset.timestamps observation_times = [] timestamps = [] for o in self.observation: observation_time = dateutil.parser.parse(o['time']) observation_times.append(observation_time) deltas = [(x.replace(tzinfo=pytz.UTC) - observation_time).total_seconds() for x in ts] time = np.abs(deltas).argmin() timestamp = ts[time] timestamps.append(timestamp) try: self.load_misc(dataset, self.variables) except IndexError as e: raise ClientError( gettext( "The selected variable(s) were not found in the dataset. \ Most likely, this variable is a derived product from existing dataset variables. \ Please select another variable.") + str(e)) point_data, self.depths = self.get_data(dataset, self.variables, time) point_data = np.ma.array(point_data) point_data = self.apply_scale_factors(point_data) self.variable_units, point_data = self.kelvin_to_celsius( self.variable_units, point_data) self.data = point_data self.observation_time = observation_time self.observation_times = observation_times self.timestamps = timestamps self.timestamp = timestamp
def load_data(self): with open_dataset(get_dataset_url(self.dataset_name)) as dataset: self.load_misc(dataset, self.variables) self.fix_startend_times(dataset, self.starttime, self.endtime) if len(self.variables) == 1: self.variable_unit = get_variable_unit( self.dataset_name, dataset.variables[self.variables[0]]) self.variable_name = get_variable_name( self.dataset_name, dataset.variables[self.variables[0]]) else: self.variable_name = self.vector_name(self.variable_names[0]) self.variable_unit = self.variable_units[0] var = self.variables[0] if self.depth != 'all' and self.depth != 'bottom' and \ (set(dataset.variables[var].dimensions) & set(dataset.depth_dimensions)): self.depth_label = " at %d m" % (np.round( dataset.depths[self.depth])) elif self.depth == 'bottom': self.depth_label = ' at Bottom' else: self.depth_label = '' if not (set(dataset.variables[var].dimensions) & set(dataset.depth_dimensions)): self.depth = 0 times = None point_data = [] for p in self.points: data = [] for v in self.variables: if self.depth == 'all': d, dep = dataset.get_timeseries_profile( float(p[0]), float(p[1]), self.starttime, self.endtime, v) else: d, dep = dataset.get_timeseries_point( float(p[0]), float(p[1]), self.depth, self.starttime, self.endtime, v, return_depth=True) data.append(d) point_data.append(np.ma.array(data)) point_data = np.ma.array(point_data) for idx, factor in enumerate(self.scale_factors): if factor != 1.0: point_data[idx] = np.multiply(point_data[idx], factor) times = dataset.timestamps[self.starttime:self.endtime + 1] if self.query.get('dataset_quantum') == 'month': times = [datetime.date(x.year, x.month, 1) for x in times] # depths = dataset.depths depths = dep # TODO: pint if self.variable_unit.startswith("Kelvin"): self.variable_unit = "Celsius" for idx, v in enumerate(self.variables): point_data[:, idx, :] = point_data[:, idx, :] - 273.15 if point_data.shape[1] == 2: # Under the current API this indicates that velocity data is being # loaded. Save each velocity component (X and Y) for possible CSV # export later. self.quiver_data = [point_data[:, 0, :], point_data[:, 1, :]] point_data = np.ma.expand_dims( np.sqrt(point_data[:, 0, :]**2 + point_data[:, 1, :]**2), 1) self.times = times self.data = point_data self.depths = depths self.depth_unit = "m"
def load_data(self): """ Calculates and returns the depth, depth-value, and depth unit from a given dataset Args: depth: Stored depth information (self.depth or self.compare['depth']) clip_length: How many depth values to clip (usually len(dataset.depths) - 1) dataset: Opened dataset Returns: (depth, depth_value, depth_unit) """ def find_depth(depth, clip_length, dataset): depth_value = 0 depth_unit = "m" if depth: if depth == 'bottom': depth_value = 'Bottom' depth_unit = '' return (depth, depth_value, depth_unit) else: depth = np.clip(int(depth), 0, clip_length) depth_value = np.round(dataset.depths[depth]) depth_unit = "m" return (depth, depth_value, depth_unit) return (depth, depth_value, depth_unit) # Load left/Main Map with open_dataset(get_dataset_url(self.dataset_name)) as dataset: latvar, lonvar = utils.get_latlon_vars(dataset) self.depth, self.depth_value, self.depth_unit = find_depth( self.depth, len(dataset.depths) - 1, dataset) self.fix_startend_times(dataset, self.starttime, self.endtime) time = list(range(self.starttime, self.endtime + 1)) if len(self.variables) > 1: v = [] for name in self.variables: self.path_points, self.distance, t, value = dataset.get_path( self.points, self.depth, time, name) v.append(value**2) value = np.sqrt(np.ma.sum(v, axis=0)) self.variable_name = self.get_variable_names( dataset, self.variables)[0] self.variable_name = self.vector_name(self.variable_name) else: self.path_points, self.distance, t, value = dataset.get_path( self.points, self.depth, time, self.variables[0]) self.variable_name = self.get_variable_names( dataset, self.variables)[0] variable_units = self.get_variable_units(dataset, self.variables) scale_factors = self.get_variable_scale_factors( dataset, self.variables) self.variable_unit, self.data = self.kelvin_to_celsius( variable_units[0], value) self.times = dataset.timestamps[self.starttime:self.endtime + 1] self.data = np.multiply(self.data, scale_factors[0]) self.data = self.data.transpose() # Get colourmap if self.cmap is None: self.cmap = colormap.find_colormap(self.variable_name) # Load data sent from Right Map (if in compare mode) if self.compare: with open_dataset(get_dataset_url( self.compare['dataset'])) as dataset: latvar, lonvar = utils.get_latlon_vars(dataset) self.compare['depth'], self.compare[ 'depth_value'], self.compare['depth_unit'] = find_depth( self.compare['depth'], len(dataset.depths) - 1, dataset) self.fix_startend_times(dataset, self.compare['starttime'], self.compare['endtime']) time = list( range(self.compare['starttime'], self.compare['endtime'] + 1)) if len(self.compare['variables']) > 1: v = [] for name in self.compare['variables']: path, distance, t, value = dataset.get_path( self.points, self.compare['depth'], time, name) v.append(value**2) value = np.sqrt(np.ma.sum(v, axis=0)) self.compare['variable_name'] = self.get_variable_names( dataset, self.compare['variables'])[0] self.compare['variable_name'] = self.vector_name( self.compare['variable_name']) else: path, distance, t, value = dataset.get_path( self.points, self.compare['depth'], time, self.compare['variables'][0]) self.compare['variable_name'] = self.get_variable_names( dataset, self.compare['variables'])[0] # Colourmap if (self.compare['colormap'] == 'default'): self.compare['colormap'] = colormap.find_colormap( self.compare['variable_name']) else: self.compare['colormap'] = colormap.find_colormap( self.compare['colormap']) variable_units = self.get_variable_units( dataset, self.compare['variables']) scale_factors = self.get_variable_scale_factors( dataset, self.compare['variables']) self.compare['variable_unit'], self.compare[ 'data'] = self.kelvin_to_celsius(variable_units[0], value) self.compare['times'] = dataset.timestamps[ self.compare['starttime']:self.compare['endtime'] + 1] self.compare['data'] = np.multiply(self.compare['data'], scale_factors[0]) self.compare['data'] = self.compare['data'].transpose() # Comparison over different time ranges makes no sense if self.starttime != self.compare['starttime'] or\ self.endtime != self.compare['endtime']: raise ClientError( gettext( "Please ensure the Start Time and End Time for the Left and Right maps are identical." ))
def get_data_v1_0(dataset, variable, time, depth, location): with open_dataset(get_dataset_url(dataset)) as ds: date = ds.convert_to_timestamp(time) #print(date) return routes.routes_impl.get_data_impl(dataset, variable, date, depth, location)
def get_values(self, area_info, dataset_name, variables): with open_dataset(get_dataset_url(dataset_name)) as dataset: if self.time is None or (type(self.time) == str and len(self.time) == 0): time = -1 else: time = int(self.time) if time < 0: time += len(dataset.timestamps) time = np.clip(time, 0, len(dataset.timestamps) - 1) depth = 0 depthm = 0 if self.depth: if self.depth == 'bottom': depth = 'bottom' depthm = 'Bottom' if len(self.depth) > 0 and \ self.depth != 'bottom': depth = int(self.depth) depth = np.clip(depth, 0, len(dataset.depths) - 1) depthm = dataset.depths[depth] lat, lon = np.meshgrid( np.linspace(area_info.bounds[0], area_info.bounds[2], 50), area_info.spaced_points) output_fmtstr = "%6.5g" for v_idx, v in enumerate(variables): var = dataset.variables[v] variable_name = get_variable_name(dataset_name, var) variable_unit = get_variable_unit(dataset_name, var) scale_factor = get_variable_scale_factor(dataset_name, var) lat, lon, d = dataset.get_raw_point(lat.ravel(), lon.ravel(), depth, time, v) if scale_factor != 1.0: d = np.multiply(d, scale_factor) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" d = d - 273.15 lon[np.where(lon > 180)] -= 360 if len(var.dimensions) == 3: variable_depth = "" elif depth == 'bottom': variable_depth = "(@ Bottom)" else: variable_depth = "(@%d m)" % np.round(depthm) points = [ Point(p) for p in zip(lat.values.ravel(), lon.values.ravel()) ] for i, a in enumerate(area_info.area_query): indices = np.where( map(lambda p, poly=area_info.area_polys[i]: poly. contains(p), points)) selection = np.ma.array(d.values.ravel()[indices]) if len(selection) > 0 and not selection.mask.all(): area_info.output[i]['variables'].append({ 'name': ("%s %s" % (variable_name, variable_depth)).strip(), 'unit': variable_unit, 'min': output_fmtstr % (np.ma.amin(selection).astype(float)), 'max': output_fmtstr % (np.ma.amax(selection).astype(float)), 'mean': output_fmtstr % (np.ma.mean(selection).astype(float)), 'median': output_fmtstr % (np.ma.median(selection).astype(float)), 'stddev': output_fmtstr % (np.ma.std(selection).astype(float)), 'num': "%d" % selection.count(), }) else: area_info.output[i]['variables'].append({ 'name': ("%s %s" % (variable_name, variable_depth)).strip(), 'unit': variable_unit, 'min': gettext("No Data"), 'max': gettext("No Data"), 'mean': gettext("No Data"), 'median': gettext("No Data"), 'stddev': gettext("No Data"), 'num': "0", }) ClientError( gettext( "there are no datapoints in the area you selected. \ you may have selected a area on land or you may \ have an ara that is smallenough to fit between \ the datapoints try selection a different area or \ a larger area")) area_info.stats = area_info.output return raise ServerError( gettext("An Error has occurred. When opening the dataset. \ Please try again or try a different dataset. \ If you would like to report this error please \ contact [email protected]"))
def load_data(self): distance = VincentyDistance() height = distance.measure( (self.bounds[0], self.centroid[1]), (self.bounds[2], self.centroid[1])) * 1000 * 1.25 width = distance.measure( (self.centroid[0], self.bounds[1]), (self.centroid[0], self.bounds[3])) * 1000 * 1.25 if self.projection == 'EPSG:32661': # north pole projection near_pole, covers_pole = self.pole_proximity(self.points[0]) blat = min(self.bounds[0], self.bounds[2]) blat = 5 * np.floor(blat / 5) if self.centroid[0] > 80 or near_pole or covers_pole: self.basemap = basemap.load_map( 'npstere', self.centroid, height, width, min(self.bounds[0], self.bounds[2])) else: self.basemap = basemap.load_map('lcc', self.centroid, height, width) elif self.projection == 'EPSG:3031': # south pole projection near_pole, covers_pole = self.pole_proximity(self.points[0]) blat = max(self.bounds[0], self.bounds[2]) blat = 5 * np.ceil(blat / 5) if ((self.centroid[0] < -80 or self.bounds[1] < -80 or self.bounds[3] < -80) or covers_pole ) or near_pole: # is centerered close to the south pole self.basemap = basemap.load_map( 'spstere', self.centroid, height, width, max(self.bounds[0], self.bounds[2])) else: self.basemap = basemap.load_map('lcc', self.centroid, height, width) elif abs(self.centroid[1] - self.bounds[1]) > 90: height_bounds = [self.bounds[0], self.bounds[2]] width_bounds = [self.bounds[1], self.bounds[3]] height_buffer = (abs(height_bounds[1] - height_bounds[0])) * 0.1 width_buffer = (abs(width_bounds[0] - width_bounds[1])) * 0.1 if abs(width_bounds[1] - width_bounds[0]) > 360: raise ClientError( gettext( "You have requested an area that exceeds the width of the world. \ Thinking big is good but plots need to be less than 360 deg wide." )) if height_bounds[1] < 0: height_bounds[1] = height_bounds[1] + height_buffer else: height_bounds[1] = height_bounds[1] + height_buffer if height_bounds[0] < 0: height_bounds[0] = height_bounds[0] - height_buffer else: height_bounds[0] = height_bounds[0] - height_buffer new_width_bounds = [] new_width_bounds.append(width_bounds[0] - width_buffer) new_width_bounds.append(width_bounds[1] + width_buffer) if abs(new_width_bounds[1] - new_width_bounds[0]) > 360: width_buffer = np.floor( (360 - abs(width_bounds[1] - width_bounds[0])) / 2) new_width_bounds[0] = width_bounds[0] - width_buffer new_width_bounds[1] = width_bounds[1] + width_buffer if new_width_bounds[0] < -360: new_width_bounds[0] = -360 if new_width_bounds[1] > 720: new_width_bounds[1] = 720 self.basemap = basemap.load_map( 'merc', self.centroid, (height_bounds[0], height_bounds[1]), (new_width_bounds[0], new_width_bounds[1])) else: self.basemap = basemap.load_map('lcc', self.centroid, height, width) if self.basemap.aspect < 1: gridx = 500 gridy = int(500 * self.basemap.aspect) else: gridy = 500 gridx = int(500 / self.basemap.aspect) self.longitude, self.latitude = self.basemap.makegrid(gridx, gridy) with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.time < 0: self.time += len(dataset.timestamps) self.time = np.clip(self.time, 0, len(dataset.timestamps) - 1) self.variable_unit = self.get_variable_units( dataset, self.variables)[0] self.variable_name = self.get_variable_names( dataset, self.variables)[0] scale_factor = self.get_variable_scale_factors( dataset, self.variables)[0] if self.cmap is None: if len(self.variables) == 1: self.cmap = colormap.find_colormap(self.variable_name) else: self.cmap = colormap.colormaps.get('speed') if len(self.variables) == 2: self.variable_name = self.vector_name(self.variable_name) if self.depth == 'bottom': depth_value = 'Bottom' else: self.depth = np.clip(int(self.depth), 0, len(dataset.depths) - 1) depth_value = dataset.depths[self.depth] data = [] allvars = [] for v in self.variables: var = dataset.variables[v] allvars.append(v) if self.filetype in ['csv', 'odv', 'txt']: d, depth_value = dataset.get_area(np.array( [self.latitude, self.longitude]), self.depth, self.time, v, self.interp, self.radius, self.neighbours, return_depth=True) else: d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, v, self.interp, self.radius, self.neighbours) d = np.multiply(d, scale_factor) self.variable_unit, d = self.kelvin_to_celsius( self.variable_unit, d) data.append(d) if self.filetype not in ['csv', 'odv', 'txt']: if len(var.dimensions) == 3: self.depth_label = "" elif self.depth == 'bottom': self.depth_label = " at Bottom" else: self.depth_label = " at " + \ str(int(np.round(depth_value))) + " m" if len(data) == 2: data[0] = np.sqrt(data[0]**2 + data[1]**2) self.data = data[0] quiver_data = [] # Store the quiver data on the same grid as the main variable. This # will only be used for CSV export. quiver_data_fullgrid = [] if self.quiver is not None and \ self.quiver['variable'] != '' and \ self.quiver['variable'] != 'none': for v in self.quiver['variable'].split(','): allvars.append(v) var = dataset.variables[v] quiver_unit = get_variable_unit(self.dataset_name, var) quiver_name = get_variable_name(self.dataset_name, var) quiver_lon, quiver_lat = self.basemap.makegrid(50, 50) d = dataset.get_area( np.array([quiver_lat, quiver_lon]), self.depth, self.time, v, self.interp, self.radius, self.neighbours, ) quiver_data.append(d) # Get the quiver data on the same grid as the main # variable. d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, v, self.interp, self.radius, self.neighbours, ) quiver_data_fullgrid.append(d) self.quiver_name = self.vector_name(quiver_name) self.quiver_longitude = quiver_lon self.quiver_latitude = quiver_lat self.quiver_unit = quiver_unit self.quiver_data = quiver_data self.quiver_data_fullgrid = quiver_data_fullgrid if all( [len(dataset.variables[v].dimensions) == 3 for v in allvars]): self.depth = 0 contour_data = [] if self.contour is not None and \ self.contour['variable'] != '' and \ self.contour['variable'] != 'none': d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, self.contour['variable'], self.interp, self.radius, self.neighbours, ) contour_unit = get_variable_unit( self.dataset_name, dataset.variables[self.contour['variable']]) contour_name = get_variable_name( self.dataset_name, dataset.variables[self.contour['variable']]) contour_factor = get_variable_scale_factor( self.dataset_name, dataset.variables[self.contour['variable']]) contour_unit, d = self.kelvin_to_celsius(contour_unit, d) d = np.multiply(d, contour_factor) contour_data.append(d) self.contour_unit = contour_unit self.contour_name = contour_name self.contour_data = contour_data self.timestamp = dataset.timestamps[self.time] if self.compare: self.variable_name += " Difference" with open_dataset(get_dataset_url( self.compare['dataset'])) as dataset: data = [] for v in self.compare['variables']: var = dataset.variables[v] d = dataset.get_area( np.array([self.latitude, self.longitude]), self.compare['depth'], self.compare['time'], v, self.interp, self.radius, self.neighbours, ) data.append(d) if len(data) == 2: data = np.sqrt(data[0]**2 + data[1]**2) else: data = data[0] u, data = self.kelvin_to_celsius( dataset.variables[self.compare['variables'][0]].unit, data) self.data -= data # Load bathymetry data self.bathymetry = overlays.bathymetry(self.basemap, self.latitude, self.longitude, blur=2) if self.depth != 'bottom' and self.depth != 0: if len(quiver_data) > 0: quiver_bathymetry = overlays.bathymetry( self.basemap, quiver_lat, quiver_lon) self.data[np.where(self.bathymetry < depth_value)] = np.ma.masked for d in self.quiver_data: d[np.where(quiver_bathymetry < depth_value)] = np.ma.masked for d in self.contour_data: d[np.where(self.bathymetry < depth_value)] = np.ma.masked else: mask = maskoceans(self.longitude, self.latitude, self.data, True, 'h', 1.25).mask self.data[~mask] = np.ma.masked for d in self.quiver_data: mask = maskoceans(self.quiver_longitude, self.quiver_latitude, d).mask d[~mask] = np.ma.masked for d in contour_data: mask = maskoceans(self.longitude, self.latitude, d).mask d[~mask] = np.ma.masked if self.area and self.filetype in ['csv', 'odv', 'txt', 'geotiff']: area_polys = [] for a in self.area: rings = [LinearRing(p) for p in a['polygons']] innerrings = [LinearRing(p) for p in a['innerrings']] polygons = [] for r in rings: inners = [] for ir in innerrings: if r.contains(ir): inners.append(ir) polygons.append(Poly(r, inners)) area_polys.append(MultiPolygon(polygons)) points = [ Point(p) for p in zip(self.latitude.ravel(), self.longitude.ravel()) ] indicies = [] for a in area_polys: indicies.append( np.where( list(map(lambda p, poly=a: poly.contains(p), points)))[0]) indicies = np.unique(np.array(indicies).ravel()) newmask = np.ones(self.data.shape, dtype=bool) newmask[np.unravel_index(indicies, newmask.shape)] = False self.data.mask |= newmask self.depth_value = depth_value
def load_data(self): with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.time < 0: self.time += len(dataset.timestamps) time = np.clip(self.time, 0, len(dataset.timestamps) - 1) for idx, v in enumerate(self.variables): var = dataset.variables[v] if not (set(var.dimensions) & set(dataset.depth_dimensions)): for potential in dataset.variables: if potential in self.variables: continue pot = dataset.variables[potential] if (set(pot.dimensions) & set(dataset.depth_dimensions)): if len(pot.dimensions) > 3: self.variables[idx] = potential.key value = parallel = perpendicular = magnitude = None variable_names = self.get_variable_names(dataset, self.variables) variable_units = self.get_variable_units(dataset, self.variables) scale_factors = self.get_variable_scale_factors(dataset, self.variables) # Load data sent from primary/Left Map if len(self.variables) > 1: # Only velocity has 2 variables v = [] for name in self.variables: v.append(dataset.variables[name]) distances, times, lat, lon, bearings = geo.path_to_points( self.points, 100 ) transect_pts, distance, x, dep = dataset.get_path_profile( self.points, time, self.variables[0], 100) transect_pts, distance, y, dep = dataset.get_path_profile( self.points, time, self.variables[1], 100) # Calculate vector components x = np.multiply(x, scale_factors[0]) y = np.multiply(y, scale_factors[1]) r = np.radians(np.subtract(90, bearings)) theta = np.arctan2(y, x) - r magnitude = np.sqrt(x ** 2 + y ** 2) parallel = magnitude * np.cos(theta) perpendicular = magnitude * np.sin(theta) else: # Get data for one variable transect_pts, distance, value, dep = dataset.get_path_profile( self.points, time, self.variables[0]) value = np.multiply(value, scale_factors[0]) # Get variable units and convert to Celsius if needed variable_units[0], value = self.kelvin_to_celsius( variable_units[0], value ) if len(self.variables) == 2: variable_names[0] = self.vector_name(variable_names[0]) # If a colourmap has not been manually specified by the # Navigator... if self.cmap is None: self.cmap = colormap.find_colormap(variable_names[0]) self.timestamp = dataset.timestamps[int(time)] self.depth = dep self.depth_unit = "m" self.transect_data = { "points": transect_pts, "distance": distance, "data": value, "name": variable_names[0], "unit": variable_units[0], "parallel": parallel, "perpendicular": perpendicular, "magnitude": magnitude, } if self.surface is not None: surface_pts, surface_dist, t, surface_value = \ dataset.get_path( self.points, 0, time, self.surface, ) surface_unit = get_variable_unit( self.dataset_name, dataset.variables[self.surface] ) surface_name = get_variable_name( self.dataset_name, dataset.variables[self.surface] ) surface_factor = get_variable_scale_factor( self.dataset_name, dataset.variables[self.surface] ) surface_value = np.multiply(surface_value, surface_factor) surface_unit, surface_value = self.kelvin_to_celsius( surface_unit, surface_value ) self.surface_data = { "points": surface_pts, "distance": surface_dist, "data": surface_value, "name": surface_name, "unit": surface_unit } # Load data sent from Right Map (if in compare mode) if self.compare: def interpolate_depths(data, depth_in, depth_out): output = [] for i in range(0, depth_in.shape[0]): f = interp1d( depth_in[i], data[:, i], bounds_error=False, assume_sorted=True, ) output.append( f(depth_out[i].view(np.ma.MaskedArray).filled()) ) return np.ma.masked_invalid(output).transpose() with open_dataset(get_dataset_url(self.compare['dataset'])) as dataset: # Get and format date self.compare['date'] = np.clip(np.int64(self.compare['time']), 0, len(dataset.timestamps) - 1) self.compare['date'] = dataset.timestamps[int(self.compare['date'])] # 1 variable if len(self.compare['variables']) == 1: # Get and store the "nicely formatted" string for the variable name self.compare['name'] = self.get_variable_names(dataset, self.compare['variables'])[0] # Find correct colourmap if (self.compare['colormap'] == 'default'): self.compare['colormap'] = colormap.find_colormap(self.compare['name']) else: self.compare['colormap'] = colormap.find_colormap(self.compare['colormap']) climate_points, climate_distance, climate_data, cdep = \ dataset.get_path_profile(self.points, self.compare['time'], self.compare['variables'][0]) # Get variable units and convert to Celsius if needed self.compare['unit'], climate_data = self.kelvin_to_celsius( dataset.variables[self.compare['variables'][0]].unit, climate_data ) self.__fill_invalid_shift(climate_data) if (self.depth.shape != cdep.shape) or \ (self.depth != cdep).any(): # Need to interpolate the depths climate_data = interpolate_depths( climate_data, cdep, self.depth ) if self.transect_data['data'] is None: self.transect_data['magnitude'] -= climate_data self.transect_data['parallel'] -= climate_data self.transect_data['perpendicular'] -= climate_data else: self.transect_data['compare_data'] = climate_data # Velocity variables else: # Get and store the "nicely formatted" string for the variable name self.compare['name'] = self.get_variable_names(dataset, self.compare['variables'])[0] climate_pts, climate_distance, climate_x, cdep = \ dataset.get_path_profile( self.points, self.compare['time'], self.compare['variables'][0], 100 ) climate_pts, climate_distance, climate_y, cdep = \ dataset.get_path_profile( self.points, self.compare['time'], self.compare['variables'][0], 100 ) climate_distances, ctimes, clat, clon, bearings = \ geo.path_to_points(self.points, 100) r = np.radians(np.subtract(90, bearings)) theta = np.arctan2(climate_y, climate_x) - r mag = np.sqrt(climate_x ** 2 + climate_y ** 2) if np.all(self.depth != cdep): theta = interpolate_depths( theta, cdep, self.depth ) self.__fill_invalid_shift(theta) mag = interpolate_depths( mag, cdep, self.depth ) self.__fill_invalid_shift(mag) self.compare['parallel'] = mag * np.cos(theta) self.compare['perpendicular'] = mag * np.sin(theta) """ if self.transect_data['parallel'] is None: self.transect_data['data'] -= mag else: self.transect_data['parallel'] -= climate_parallel self.transect_data['perpendicular'] -= climate_perpendicular """ # Bathymetry with Dataset(current_app.config['BATHYMETRY_FILE'], 'r') as dataset: bath_x, bath_y = bathymetry( dataset.variables['y'], dataset.variables['x'], dataset.variables['z'], self.points) self.bathymetry = { 'x': bath_x, 'y': bath_y }
def load_data(self): ds_url = current_app.config['DRIFTER_URL'] data_names = [] data_units = [] with Dataset(ds_url % self.drifter, 'r') as ds: self.name = ds.buoyid self.imei = str(chartostring(ds['imei'][0])) self.wmo = str(chartostring(ds['wmo'][0])) t = netcdftime.utime(ds['data_date'].units) d = [] for v in self.buoyvariables: d.append(ds[v][:]) if "long_name" in ds[v].ncattrs(): data_names.append(ds[v].long_name) else: data_names.append(v) if "units" in ds[v].ncattrs(): data_units.append(ds[v].units) else: data_units.append(None) self.data = d self.times = t.num2date(ds['data_date'][:]) self.points = np.array([ ds['latitude'][:], ds['longitude'][:], ]).transpose() data_names = data_names[:len(self.buoyvariables)] data_units = data_units[:len(self.buoyvariables)] for i, t in enumerate(self.times): if t.tzinfo is None: self.times[i] = t.replace(tzinfo=pytz.UTC) self.data_names = data_names self.data_units = data_units if self.starttime is not None: d = dateutil.parser.parse(self.starttime) self.start = np.where(self.times >= d)[0].min() else: self.start = 0 if self.endtime is not None: d = dateutil.parser.parse(self.endtime) self.end = np.where(self.times <= d)[0].max() + 1 else: self.end = len(self.times) - 1 if self.start < 0: self.start += len(self.times) self.start = np.clip(self.start, 0, len(self.times) - 1) if self.end < 0: self.end += len(self.times) self.end = np.clip(self.end, 0, len(self.times) - 1) with open_dataset(get_dataset_url(self.dataset_name)) as dataset: depth = int(self.depth) try: model_start = np.where( dataset.timestamps <= self.times[self.start] )[0][-1] except IndexError: model_start = 0 model_start -= 1 model_start = np.clip(model_start, 0, len(dataset.timestamps) - 1) try: model_end = np.where( dataset.timestamps >= self.times[self.end] )[0][0] except IndexError: model_end = len(dataset.timestamps) - 1 model_end += 1 model_end = np.clip( model_end, model_start, len(dataset.timestamps) - 1 ) model_times = [time.mktime(t.timetuple()) for t in dataset.timestamps[model_start:model_end + 1]] output_times = [time.mktime(t.timetuple()) for t in self.times[self.start:self.end + 1]] d = [] for v in self.variables: pts, dist, mt, md = dataset.get_path( self.points[self.start:self.end + 1], depth, list(range(model_start, model_end + 1)), v, times=output_times ) f = interp1d( model_times, md, assume_sorted=True, bounds_error=False, ) d.append(np.diag(f(mt))) model_data = np.ma.array(d) variable_names = [] variable_units = [] scale_factors = [] for v in self.variables: variable_units.append(get_variable_unit(self.dataset_name, dataset.variables[v])) variable_names.append(get_variable_name(self.dataset_name, dataset.variables[v])) scale_factors.append( get_variable_scale_factor(self.dataset_name, dataset.variables[v]) ) for idx, sf in enumerate(scale_factors): model_data[idx, :] = np.multiply(model_data[idx, :], sf) for idx, u in enumerate(variable_units): variable_units[idx], model_data[idx, :] = \ self.kelvin_to_celsius(u, model_data[idx, :]) self.model_data = model_data self.model_times = list(map(datetime.datetime.utcfromtimestamp, mt)) self.variable_names = variable_names self.variable_units = variable_units
def vars_query_impl(args): """ API Format: /api/variables/?dataset='...'&3d_only='...'&vectors_only='...'&vectors='...' **Only use variables required for your specific request** dataset : Dataset to extract data - Can be found using /api/datasets 3d_only : Boolean Value; When True, only variables with depth will be shown vectors_only : Boolean Value; When True, ONLY variables with magnitude will be shown vectors : Boolean Value; When True, magnitude components will be included **Boolean: True / False** """ if 'dataset' not in args.keys(): raise APIError("Please Specify a Dataset Using ?dataset='...' ") data = [] #Initializes empty data list dataset = args['dataset'] #Dataset Specified in query #Queries config files if get_dataset_climatology( dataset ) != "" and 'anom' in args: #If a url exists for the dataset and an anomaly with open_dataset(get_dataset_climatology(dataset)) as ds: climatology_variables = list(map(str, ds.variables)) else: climatology_variables = [] #three_d = '3d_only' in args #Checks if 3d_only is in args #If three_d is true - Only 3d variables will be returned with open_dataset(get_dataset_url(dataset)) as ds: if 'vectors_only' not in args: #Vectors_only -> Magnitude Only # 'v' is a Variable in the Dataset # v Contains: dimensions, key, name, unit, valid_min, valid_max for v in ds.variables: #Iterates through all the variables in the dataset #If a time period and at least one other unit type is specified if ('time_counter' in v.dimensions or 'time' in v.dimensions) \ and ('y' in v.dimensions or 'yc' in v.dimensions or 'node' in v.dimensions or 'nele' in v.dimensions or 'latitude' in v.dimensions or 'lat' in v.dimensions): if ('3d_only' in args) and not (set(ds.depth_dimensions) & set(v.dimensions)): continue else: if not is_variable_hidden(dataset, v): data.append({ 'id': v.key, 'value': get_variable_name(dataset, v), 'scale': get_variable_scale(dataset, v) }) if v.key in climatology_variables: data.append({ 'id': v.key + "_anom", 'value': get_variable_name(dataset, v) + " Anomaly", 'scale': [-10, 10] }) VECTOR_MAP = { 'vozocrtx': 'vozocrtx,vomecrty', 'itzocrtx': 'itzocrtx,itmecrty', 'iicevelu': 'iicevelu,iicevelv', 'u_wind': 'u_wind,v_wind', 'u': 'u,v', 'ua': 'ua,va', 'u-component_of_wind_height_above_ground': 'u-component_of_wind_height_above_ground,v-component_of_wind_height_above_ground', } #If Vectors are needed if 'vectors' in args or 'vectors_only' in args: rxp = r"(?i)(x |y |zonal |meridional |northward |eastward |East |North)" for key, value in list(VECTOR_MAP.items()): if key in ds.variables: n = get_variable_name( dataset, ds.variables[key]) #Returns a normal variable type data.append({ 'id': value, 'value': re.sub(r" +", " ", re.sub(rxp, " ", n)), 'scale': [0, get_variable_scale(dataset, ds.variables[key])[1]] }) data = sorted( data, key=lambda k: k['value']) #Sorts data alphabetically using the value #Data is set of scale, id, value objects resp = jsonify(data) return resp
def plot(projection, x, y, z, args): lat, lon = get_latlon_coords(projection, x, y, z) if len(lat.shape) == 1: lat, lon = np.meshgrid(lat, lon) dataset_name = args.get('dataset') variable = args.get('variable') if variable.endswith('_anom'): variable = variable[0:-5] anom = True else: anom = False variable = variable.split(',') depth = args.get('depth') scale = args.get('scale') scale = [float(component) for component in scale.split(',')] data = [] with open_dataset(get_dataset_url(dataset_name)) as dataset: if args.get('time') is None or (type(args.get('time')) == str and len(args.get('time')) == 0): time = -1 else: time = int(args.get('time')) t_len = len(dataset.timestamps) while time >= t_len: time -= t_len while time < 0: time += len(dataset.timestamps) timestamp = dataset.timestamps[time] for v in variable: data.append( dataset.get_area(np.array([lat, lon]), depth, time, v, args.get('interp'), args.get('radius'), args.get('neighbours'))) variable_name = get_variable_name(dataset_name, dataset.variables[variable[0]]) variable_unit = get_variable_unit(dataset_name, dataset.variables[variable[0]]) scale_factor = get_variable_scale_factor( dataset_name, dataset.variables[variable[0]]) if anom: cmap = colormap.colormaps['anomaly'] else: cmap = colormap.find_colormap(variable_name) if depth != 'bottom': depthm = dataset.depths[depth] else: depthm = 0 if scale_factor != 1.0: for idx, val in enumerate(data): data[idx] = np.multiply(val, scale_factor) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" for idx, val in enumerate(data): data[idx] = np.add(val, -273.15) if len(data) == 1: data = data[0] if len(data) == 2: data = np.sqrt(data[0]**2 + data[1]**2) if not anom: cmap = colormap.colormaps.get('speed') if anom: with open_dataset(get_dataset_climatology(dataset_name)) as dataset: a = dataset.get_area(np.array([lat, lon]), depth, timestamp.month - 1, v, args.get('interp'), args.get('radius'), args.get('neighbours')) data -= a data = data.transpose() xpx = x * 256 ypx = y * 256 with Dataset(current_app.config['ETOPO_FILE'] % (projection, z), 'r') as dataset: bathymetry = dataset["z"][ypx:(ypx + 256), xpx:(xpx + 256)] bathymetry = gaussian_filter(bathymetry, 0.5) data[np.where(bathymetry > -depthm)] = np.ma.masked sm = matplotlib.cm.ScalarMappable(matplotlib.colors.Normalize( vmin=scale[0], vmax=scale[1]), cmap=cmap) img = sm.to_rgba(np.ma.masked_invalid(np.squeeze(data))) im = Image.fromarray((img * 255.0).astype(np.uint8)) buf = BytesIO() im.save(buf, format='PNG', optimize=True) return buf