Пример #1
0
def determine_grid_type(dataset_url):
    try:
        UGrid.from_ncfile(dataset_url)
        grid_type = 'ugrid'
    except ValueError:
        try:
            from_ncfile(dataset_url)
            grid_type = 'sgrid'
        except SGridNonCompliantError:
            grid_type = None
    return grid_type
Пример #2
0
def determine_grid_type(dataset_url):
    try:
        UGrid.from_ncfile(dataset_url)
        grid_type = 'ugrid'
    except ValueError:
        try:
            from_ncfile(dataset_url)
            grid_type = 'sgrid'
        except SGridNonCompliantError:
            grid_type = None
    return grid_type
Пример #3
0
def _get_grid(self):
    grid = 'unknown'
    # SGRID.
    try:
        return pysgrid.from_ncfile(self.filename)
    except SGridNonCompliantError:
        pass
    # UGRID.
    try:
        return pyugrid.UGrid.from_ncfile(self.filename)
    except ValueError:
        pass
    return grid
Пример #4
0
def _get_grid(self):
    grid = 'unknown'
    # SGRID.
    try:
        return pysgrid.from_ncfile(self.filename)
    except SGridNonCompliantError:
        pass
    # UGRID.
    try:
        return pyugrid.UGrid.from_ncfile(self.filename)
    except ValueError:
        pass
    return grid
Пример #5
0
 def wgs84_bounds(self, layer):
     try:
         cached_sg = from_ncfile(self.topology_file)
     except:
         pass
     else:
         centers = cached_sg.centers
         longitudes = centers[..., 0]
         latitudes = centers[..., 1]
         lon_name, lat_name = cached_sg.face_coordinates
         lon_var_obj = getattr(cached_sg, lon_name)
         lat_var_obj = getattr(cached_sg, lat_name)
         lon_trimmed = longitudes[lon_var_obj.center_slicing]
         lat_trimmed = latitudes[lat_var_obj.center_slicing]
         lon_max = lon_trimmed.max()
         lon_min = lon_trimmed.min()
         lat_max = lat_trimmed.max()
         lat_min = lat_trimmed.min()
         return DotDict(minx=lon_min,
                        miny=lat_min,
                        maxx=lon_max,
                        maxy=lat_max)
Пример #6
0
 def wgs84_bounds(self, layer):
     try:
         cached_sg = from_ncfile(self.topology_file)
     except:
         pass
     else:
         centers = cached_sg.centers
         longitudes = centers[..., 0]
         latitudes = centers[..., 1]
         lon_name, lat_name = cached_sg.face_coordinates
         lon_var_obj = getattr(cached_sg, lon_name)
         lat_var_obj = getattr(cached_sg, lat_name)
         lon_trimmed = longitudes[lon_var_obj.center_slicing]
         lat_trimmed = latitudes[lat_var_obj.center_slicing]
         lon_max = lon_trimmed.max()
         lon_min = lon_trimmed.min()
         lat_max = lat_trimmed.max()
         lat_min = lat_trimmed.min()
         return DotDict(minx=lon_min,
                        miny=lat_min,
                        maxx=lon_max,
                        maxy=lat_max
                        )
Пример #7
0
    def getmap(self, layer, request):
        time_index, time_value = self.nearest_time(layer, request.GET['time'])
        wgs84_bbox = request.GET['wgs84_bbox']

        with self.dataset() as nc:
            cached_sg = from_ncfile(self.topology_file)
            lon_name, lat_name = cached_sg.face_coordinates
            lon_obj = getattr(cached_sg, lon_name)
            lat_obj = getattr(cached_sg, lat_name)
            centers = cached_sg.centers
            lon = centers[..., 0][lon_obj.center_slicing]
            lat = centers[..., 1][lat_obj.center_slicing]

            if isinstance(layer, Layer):
                data_obj = getattr(cached_sg, layer.access_name)
                raw_var = nc.variables[layer.access_name]
                if len(raw_var.shape) == 4:
                    z_index, z_value = self.nearest_z(layer, request.GET['elevation'])
                    raw_data = raw_var[time_index, z_index, data_obj.center_slicing[-2], data_obj.center_slicing[-1]]
                elif len(raw_var.shape) == 3:
                    raw_data = raw_var[time_index, data_obj.center_slicing[-2], data_obj.center_slicing[-1]]
                elif len(raw_var.shape) == 2:
                    raw_data = raw_var[data_obj.center_slicing]
                else:
                    raise BaseException('Unable to trim variable {0} data.'.format(layer.access_name))
                # handle edge variables
                if data_obj.location is not None and 'edge' in data_obj.location:
                    raw_data = avg_to_cell_center(raw_data, data_obj.center_axis)

                if request.GET['image_type'] == 'pcolor':
                    return mpl_handler.pcolormesh_response(lon, lat, data=raw_data, request=request)
                elif request.GET['image_type'] == 'filledcontours':
                    return mpl_handler.contourf_response(lon, lat, data=raw_data, request=request)
                else:
                    raise NotImplementedError('Image type "{}" is not supported.'.format(request.GET['image_type']))

            elif isinstance(layer, VirtualLayer):
                x_var = None
                y_var = None
                raw_vars = []
                for l in layer.layers:
                    data_obj = getattr(cached_sg, l.access_name)
                    raw_var = nc.variables[l.access_name]
                    raw_vars.append(raw_var)
                    if len(raw_var.shape) == 4:
                        z_index, z_value = self.nearest_z(layer, request.GET['elevation'])
                        raw_data = raw_var[time_index, z_index, data_obj.center_slicing[-2], data_obj.center_slicing[-1]]
                    elif len(raw_var.shape) == 3:
                        raw_data = raw_var[time_index, data_obj.center_slicing[-2], data_obj.center_slicing[-1]]
                    elif len(raw_var.shape) == 2:
                        raw_data = raw_var[data_obj.center_slicing]
                    else:
                        raise BaseException('Unable to trim variable {0} data.'.format(l.access_name))

                    raw_data = avg_to_cell_center(raw_data, data_obj.center_axis)
                    if x_var is None:
                        if data_obj.vector_axis and data_obj.vector_axis.lower() == 'x':
                            x_var = raw_data
                        elif data_obj.center_axis == 1:
                            x_var = raw_data

                    if y_var is None:
                        if data_obj.vector_axis and data_obj.vector_axis.lower() == 'y':
                            y_var = raw_data
                        elif data_obj.center_axis == 0:
                            y_var = raw_data

                if x_var is None or y_var is None:
                    raise BaseException('Unable to determine x and y variables.')

                dim_lengths = [ len(v.dimensions) for v in raw_vars ]
                if len(list(set(dim_lengths))) != 1:
                    raise AttributeError('One or both of the specified variables has screwed up dimensions.')

                if request.GET['image_type'] == 'vectors':
                    angles = cached_sg.angles[lon_obj.center_slicing]
                    vectorstep = request.GET['vectorstep']
                    # don't do this if the vectorstep is 1; let's save a microsecond or two
                    # it's identical to getting all the data
                    if vectorstep > 1:
                        data_dim = len(lon.shape)
                        step_slice = (np.s_[::vectorstep],) * data_dim  # make sure the vector step is used for all applicable dimensions
                        lon = lon[step_slice]
                        lat = lat[step_slice]
                        x_var = x_var[step_slice]
                        y_var = y_var[step_slice]
                        angles = angles[step_slice]
                    vectorscale = request.GET['vectorscale']
                    padding_factor = calc_safety_factor(vectorscale)
                    # figure out the average distance between lat/lon points
                    # do the math after taking into the vectorstep if specified
                    spatial_idx_padding = calc_lon_lat_padding(lon, lat, padding_factor)
                    spatial_idx = data_handler.lat_lon_subset_idx(lon, lat,
                                                                  lonmin=wgs84_bbox.minx,
                                                                  latmin=wgs84_bbox.miny,
                                                                  lonmax=wgs84_bbox.maxx,
                                                                  latmax=wgs84_bbox.maxy,
                                                                  padding=spatial_idx_padding
                                                                  )
                    subset_lon = self._spatial_data_subset(lon, spatial_idx)
                    subset_lat = self._spatial_data_subset(lat, spatial_idx)
                    # rotate vectors
                    x_rot, y_rot = rotate_vectors(x_var, y_var, angles)
                    spatial_subset_x_rot = self._spatial_data_subset(x_rot, spatial_idx)
                    spatial_subset_y_rot = self._spatial_data_subset(y_rot, spatial_idx)
                    return mpl_handler.quiver_response(subset_lon,
                                                       subset_lat,
                                                       spatial_subset_x_rot,
                                                       spatial_subset_y_rot,
                                                       request,
                                                       vectorscale
                                                       )
                else:
                    raise NotImplementedError('Image type "{}" is not supported.'.format(request.GET['image_type']))
Пример #8
0
    def minmax(self, layer, request):
        time_index, time_value = self.nearest_time(layer, request.GET['time'])
        wgs84_bbox = request.GET['wgs84_bbox']

        with self.dataset() as nc:
            cached_sg = from_ncfile(self.topology_file)
            lon_name, lat_name = cached_sg.face_coordinates
            lon_obj = getattr(cached_sg, lon_name)
            lat_obj = getattr(cached_sg, lat_name)
            centers = cached_sg.centers
            lon = centers[..., 0][lon_obj.center_slicing]
            lat = centers[..., 1][lat_obj.center_slicing]
            spatial_idx = data_handler.lat_lon_subset_idx(lon, lat,
                                                          lonmin=wgs84_bbox.minx,
                                                          latmin=wgs84_bbox.miny,
                                                          lonmax=wgs84_bbox.maxx,
                                                          latmax=wgs84_bbox.maxy)
            subset_lon = np.unique(spatial_idx[0])
            subset_lat = np.unique(spatial_idx[1])
            grid_variables = cached_sg.grid_variables

            vmin = None
            vmax = None
            raw_data = None
            if isinstance(layer, Layer):
                data_obj = getattr(cached_sg, layer.access_name)
                raw_var = nc.variables[layer.access_name]
                if len(raw_var.shape) == 4:
                    z_index, z_value = self.nearest_z(layer, request.GET['elevation'])
                    raw_data = raw_var[time_index, z_index, subset_lon, subset_lat]
                elif len(raw_var.shape) == 3:
                    raw_data = raw_var[time_index, subset_lon, subset_lat]
                elif len(raw_var.shape) == 2:
                    raw_data = raw_var[subset_lon, subset_lat]
                else:
                    raise BaseException('Unable to trim variable {0} data.'.format(layer.access_name))

                # handle grid variables
                if set([layer.access_name]).issubset(grid_variables):
                    raw_data = avg_to_cell_center(raw_data, data_obj.center_axis)

                vmin = np.nanmin(raw_data).item()
                vmax = np.nanmax(raw_data).item()

            elif isinstance(layer, VirtualLayer):
                x_var = None
                y_var = None
                raw_vars = []
                for l in layer.layers:
                    data_obj = getattr(cached_sg, l.access_name)
                    raw_var = nc.variables[l.access_name]
                    raw_vars.append(raw_var)
                    if len(raw_var.shape) == 4:
                        z_index, z_value = self.nearest_z(layer, request.GET['elevation'])
                        raw_data = raw_var[time_index, z_index, subset_lon, subset_lat]
                    elif len(raw_var.shape) == 3:
                        raw_data = raw_var[time_index, subset_lon, subset_lat]
                    elif len(raw_var.shape) == 2:
                        raw_data = raw_var[subset_lon, subset_lat]
                    else:
                        raise BaseException('Unable to trim variable {0} data.'.format(l.access_name))

                    if x_var is None:
                        if data_obj.vector_axis and data_obj.vector_axis.lower() == 'x':
                            x_var = raw_data
                        elif data_obj.center_axis == 1:
                            x_var = raw_data

                    if y_var is None:
                        if data_obj.vector_axis and data_obj.vector_axis.lower() == 'y':
                            y_var = raw_data
                        elif data_obj.center_axis == 0:
                            y_var = raw_data

                if ',' in layer.var_name and raw_data is not None:
                    # Vectors, so return magnitude
                    data = [ sqrt((u*u) + (v*v)) for (u, v,) in zip(x_var.flatten(), y_var.flatten()) if u != np.nan and v != np.nan]
                    vmin = min(data)
                    vmax = max(data)

            return gmd_handler.from_dict(dict(min=vmin, max=vmax))
Пример #9
0
    def getmap(self, layer, request):
        time_index, time_value = self.nearest_time(layer, request.GET['time'])
        wgs84_bbox = request.GET['wgs84_bbox']

        with self.dataset() as nc:
            cached_sg = from_ncfile(self.topology_file)
            lon_name, lat_name = cached_sg.face_coordinates
            lon_obj = getattr(cached_sg, lon_name)
            lat_obj = getattr(cached_sg, lat_name)
            centers = cached_sg.centers
            lon = centers[..., 0][lon_obj.center_slicing]
            lat = centers[..., 1][lat_obj.center_slicing]

            if isinstance(layer, Layer):
                data_obj = getattr(cached_sg, layer.access_name)
                raw_var = nc.variables[layer.access_name]
                if len(raw_var.shape) == 4:
                    z_index, z_value = self.nearest_z(layer,
                                                      request.GET['elevation'])
                    raw_data = raw_var[time_index, z_index,
                                       data_obj.center_slicing[-2],
                                       data_obj.center_slicing[-1]]
                elif len(raw_var.shape) == 3:
                    raw_data = raw_var[time_index, data_obj.center_slicing[-2],
                                       data_obj.center_slicing[-1]]
                elif len(raw_var.shape) == 2:
                    raw_data = raw_var[data_obj.center_slicing]
                else:
                    raise BaseException(
                        'Unable to trim variable {0} data.'.format(
                            layer.access_name))
                # handle edge variables
                if data_obj.location is not None and 'edge' in data_obj.location:
                    raw_data = avg_to_cell_center(raw_data,
                                                  data_obj.center_axis)

                if request.GET['image_type'] == 'pcolor':
                    return mpl_handler.pcolormesh_response(lon,
                                                           lat,
                                                           data=raw_data,
                                                           request=request)
                elif request.GET['image_type'] in [
                        'filledhatches', 'hatches', 'filledcontours',
                        'contours'
                ]:
                    return mpl_handler.contouring_response(lon,
                                                           lat,
                                                           data=raw_data,
                                                           request=request)
                else:
                    raise NotImplementedError(
                        'Image type "{}" is not supported.'.format(
                            request.GET['image_type']))

            elif isinstance(layer, VirtualLayer):
                x_var = None
                y_var = None
                raw_vars = []
                for l in layer.layers:
                    data_obj = getattr(cached_sg, l.access_name)
                    raw_var = nc.variables[l.access_name]
                    raw_vars.append(raw_var)
                    if len(raw_var.shape) == 4:
                        z_index, z_value = self.nearest_z(
                            layer, request.GET['elevation'])
                        raw_data = raw_var[time_index, z_index,
                                           data_obj.center_slicing[-2],
                                           data_obj.center_slicing[-1]]
                    elif len(raw_var.shape) == 3:
                        raw_data = raw_var[time_index,
                                           data_obj.center_slicing[-2],
                                           data_obj.center_slicing[-1]]
                    elif len(raw_var.shape) == 2:
                        raw_data = raw_var[data_obj.center_slicing]
                    else:
                        raise BaseException(
                            'Unable to trim variable {0} data.'.format(
                                l.access_name))

                    raw_data = avg_to_cell_center(raw_data,
                                                  data_obj.center_axis)
                    if x_var is None:
                        if data_obj.vector_axis and data_obj.vector_axis.lower(
                        ) == 'x':
                            x_var = raw_data
                        elif data_obj.center_axis == 1:
                            x_var = raw_data

                    if y_var is None:
                        if data_obj.vector_axis and data_obj.vector_axis.lower(
                        ) == 'y':
                            y_var = raw_data
                        elif data_obj.center_axis == 0:
                            y_var = raw_data

                if x_var is None or y_var is None:
                    raise BaseException(
                        'Unable to determine x and y variables.')

                dim_lengths = [len(v.dimensions) for v in raw_vars]
                if len(list(set(dim_lengths))) != 1:
                    raise AttributeError(
                        'One or both of the specified variables has screwed up dimensions.'
                    )

                if request.GET['image_type'] == 'vectors':
                    angles = cached_sg.angles[lon_obj.center_slicing]
                    vectorstep = request.GET['vectorstep']
                    # don't do this if the vectorstep is 1; let's save a microsecond or two
                    # it's identical to getting all the data
                    if vectorstep > 1:
                        data_dim = len(lon.shape)
                        step_slice = (
                            np.s_[::vectorstep],
                        ) * data_dim  # make sure the vector step is used for all applicable dimensions
                        lon = lon[step_slice]
                        lat = lat[step_slice]
                        x_var = x_var[step_slice]
                        y_var = y_var[step_slice]
                        angles = angles[step_slice]
                    vectorscale = request.GET['vectorscale']
                    padding_factor = calc_safety_factor(vectorscale)
                    # figure out the average distance between lat/lon points
                    # do the math after taking into the vectorstep if specified
                    spatial_idx_padding = calc_lon_lat_padding(
                        lon, lat, padding_factor)
                    spatial_idx = data_handler.lat_lon_subset_idx(
                        lon,
                        lat,
                        lonmin=wgs84_bbox.minx,
                        latmin=wgs84_bbox.miny,
                        lonmax=wgs84_bbox.maxx,
                        latmax=wgs84_bbox.maxy,
                        padding=spatial_idx_padding)
                    subset_lon = self._spatial_data_subset(lon, spatial_idx)
                    subset_lat = self._spatial_data_subset(lat, spatial_idx)
                    # rotate vectors
                    x_rot, y_rot = rotate_vectors(x_var, y_var, angles)
                    spatial_subset_x_rot = self._spatial_data_subset(
                        x_rot, spatial_idx)
                    spatial_subset_y_rot = self._spatial_data_subset(
                        y_rot, spatial_idx)
                    return mpl_handler.quiver_response(subset_lon, subset_lat,
                                                       spatial_subset_x_rot,
                                                       spatial_subset_y_rot,
                                                       request, vectorscale)
                else:
                    raise NotImplementedError(
                        'Image type "{}" is not supported.'.format(
                            request.GET['image_type']))
Пример #10
0
    def minmax(self, layer, request):
        time_index, time_value = self.nearest_time(layer, request.GET['time'])
        wgs84_bbox = request.GET['wgs84_bbox']

        with self.dataset() as nc:
            cached_sg = from_ncfile(self.topology_file)
            lon_name, lat_name = cached_sg.face_coordinates
            lon_obj = getattr(cached_sg, lon_name)
            lat_obj = getattr(cached_sg, lat_name)
            centers = cached_sg.centers
            lon = centers[..., 0][lon_obj.center_slicing]
            lat = centers[..., 1][lat_obj.center_slicing]
            spatial_idx = data_handler.lat_lon_subset_idx(
                lon,
                lat,
                lonmin=wgs84_bbox.minx,
                latmin=wgs84_bbox.miny,
                lonmax=wgs84_bbox.maxx,
                latmax=wgs84_bbox.maxy)
            subset_lon = np.unique(spatial_idx[0])
            subset_lat = np.unique(spatial_idx[1])
            grid_variables = cached_sg.grid_variables

            vmin = None
            vmax = None
            raw_data = None
            if isinstance(layer, Layer):
                data_obj = getattr(cached_sg, layer.access_name)
                raw_var = nc.variables[layer.access_name]
                if len(raw_var.shape) == 4:
                    z_index, z_value = self.nearest_z(layer,
                                                      request.GET['elevation'])
                    raw_data = raw_var[time_index, z_index, subset_lon,
                                       subset_lat]
                elif len(raw_var.shape) == 3:
                    raw_data = raw_var[time_index, subset_lon, subset_lat]
                elif len(raw_var.shape) == 2:
                    raw_data = raw_var[subset_lon, subset_lat]
                else:
                    raise BaseException(
                        'Unable to trim variable {0} data.'.format(
                            layer.access_name))

                # handle grid variables
                if set([layer.access_name]).issubset(grid_variables):
                    raw_data = avg_to_cell_center(raw_data,
                                                  data_obj.center_axis)

                vmin = np.nanmin(raw_data).item()
                vmax = np.nanmax(raw_data).item()

            elif isinstance(layer, VirtualLayer):
                x_var = None
                y_var = None
                raw_vars = []
                for l in layer.layers:
                    data_obj = getattr(cached_sg, l.access_name)
                    raw_var = nc.variables[l.access_name]
                    raw_vars.append(raw_var)
                    if len(raw_var.shape) == 4:
                        z_index, z_value = self.nearest_z(
                            layer, request.GET['elevation'])
                        raw_data = raw_var[time_index, z_index, subset_lon,
                                           subset_lat]
                    elif len(raw_var.shape) == 3:
                        raw_data = raw_var[time_index, subset_lon, subset_lat]
                    elif len(raw_var.shape) == 2:
                        raw_data = raw_var[subset_lon, subset_lat]
                    else:
                        raise BaseException(
                            'Unable to trim variable {0} data.'.format(
                                l.access_name))

                    if x_var is None:
                        if data_obj.vector_axis and data_obj.vector_axis.lower(
                        ) == 'x':
                            x_var = raw_data
                        elif data_obj.center_axis == 1:
                            x_var = raw_data

                    if y_var is None:
                        if data_obj.vector_axis and data_obj.vector_axis.lower(
                        ) == 'y':
                            y_var = raw_data
                        elif data_obj.center_axis == 0:
                            y_var = raw_data

                if ',' in layer.var_name and raw_data is not None:
                    # Vectors, so return magnitude
                    data = [
                        sqrt((u * u) + (v * v)) for (
                            u,
                            v,
                        ) in zip(x_var.flatten(), y_var.flatten())
                        if u != np.nan and v != np.nan
                    ]
                    vmin = min(data)
                    vmax = max(data)

            return gmd_handler.from_dict(dict(min=vmin, max=vmax))
Пример #11
0
    def getmap(self, layer, request):
        time_index, time_value = self.nearest_time(layer, request.GET['time'])
        wgs84_bbox = request.GET['wgs84_bbox']

        with self.dataset() as nc:
            cached_sg = from_ncfile(self.topology_file)
            lon_name, lat_name = cached_sg.face_coordinates
            lon_obj = getattr(cached_sg, lon_name)
            lat_obj = getattr(cached_sg, lat_name)
            centers = cached_sg.centers
            lon = centers[..., 0][lon_obj.center_slicing]
            lat = centers[..., 1][lat_obj.center_slicing]
            if request.GET['image_type'] == 'vectors':
                vectorstep = request.GET['vectorstep']
                vectorscale = request.GET['vectorscale']
                padding_factor = calc_safety_factor(vectorscale)
                spatial_idx_padding = calc_lon_lat_padding(lon, lat, padding_factor)
            else:
                spatial_idx_padding = 0.18
                vectorstep = None
            spatial_idx = data_handler.lat_lon_subset_idx(lon, lat,
                                                          lonmin=wgs84_bbox.minx,
                                                          latmin=wgs84_bbox.miny,
                                                          lonmax=wgs84_bbox.maxx,
                                                          latmax=wgs84_bbox.maxy,
                                                          padding=spatial_idx_padding
                                                         )
            subset_x = np.unique(spatial_idx[0])
            subset_y = np.unique(spatial_idx[1])
            if subset_x.shape == (0, ) and subset_y.shape == (0, ):
                return mpl_handler.empty_response()  # return an empty tile if subset contains no data
            else:
                x_min_idx = subset_x.min()
                x_max_idx = subset_x.max() + 1
                y_min_idx = subset_y.min()
                y_max_idx = subset_y.max() + 1
                lonlat_mask = np.ones(lon.shape)
                lonlat_mask[spatial_idx[0], spatial_idx[1]] = 0
                trimmed_lon = ma.masked_array(lon, mask=lonlat_mask).data[x_min_idx:x_max_idx:vectorstep, y_min_idx:y_max_idx:vectorstep]
                trimmed_lat = ma.masked_array(lat, mask=lonlat_mask).data[x_min_idx:x_max_idx:vectorstep, y_min_idx:y_max_idx:vectorstep]
                if isinstance(layer, Layer):
                    data_obj = getattr(cached_sg, layer.access_name)
                    raw_var = nc.variables[layer.access_name]
                    raw_data = self._retrieve_data(request=request,
                                                   nc_variable=raw_var,
                                                   sg_variable=data_obj,
                                                   layer=layer,
                                                   subset_x=subset_x,
                                                   subset_y=subset_y,
                                                   time_index=time_index,
                                                   vectorstep=1
                                                   )
                    # handle edge variables
                    if data_obj.location is not None and 'edge' in data_obj.location:
                        raw_data = avg_to_cell_center(raw_data, data_obj.center_axis)
                    if request.GET['image_type'] == 'pcolor':
                        return mpl_handler.pcolormesh_response(trimmed_lon, trimmed_lat, data=raw_data, request=request)
                    elif request.GET['image_type'] == 'filledcontours':
                        return mpl_handler.contourf_response(trimmed_lon, trimmed_lat, data=raw_data, request=request)
                    else:
                        raise NotImplementedError('Image type "{}" is not supported.'.format(request.GET['image_type']))
                elif isinstance(layer, VirtualLayer):
                    x_var = None
                    y_var = None
                    raw_vars = []
                    for l in layer.layers:
                        data_obj = getattr(cached_sg, l.access_name)
                        raw_var = nc.variables[l.access_name]
                        raw_vars.append(raw_var)
                        raw_data = self._retrieve_data(request=request,
                                                       nc_variable=raw_var,
                                                       sg_variable=data_obj,
                                                       layer=layer,
                                                       subset_x=subset_x,
                                                       subset_y=subset_y,
                                                       time_index=time_index,
                                                       vectorstep=vectorstep
                                                       )
                        raw_data = self._avg_to_cell_center(raw_data, data_obj.center_axis, vectorstep)
                        if x_var is None:
                            if data_obj.vector_axis and data_obj.vector_axis.lower() == 'x':
                                x_var = raw_data
                            elif data_obj.center_axis == 1:
                                x_var = raw_data
    
                        if y_var is None:
                            if data_obj.vector_axis and data_obj.vector_axis.lower() == 'y':
                                y_var = raw_data
                            elif data_obj.center_axis == 0:
                                y_var = raw_data
    
                    if x_var is None or y_var is None:
                        raise BaseException('Unable to determine x and y variables.')
    
                    dim_lengths = [ len(v.dimensions) for v in raw_vars ]
                    if len(list(set(dim_lengths))) != 1:
                        raise AttributeError('One or both of the specified variables has screwed up dimensions.')
    
                    if request.GET['image_type'] == 'vectors':
                        angles = cached_sg.angles[lon_obj.center_slicing]
                        trimmed_angles = ma.masked_array(angles, mask=lonlat_mask).data[x_min_idx:x_max_idx:vectorstep, y_min_idx:y_max_idx:vectorstep]
                        # rotate vectors
                        x_rot, y_rot = rotate_vectors(x_var, y_var, trimmed_angles)
                        return mpl_handler.quiver_response(trimmed_lon,
                                                           trimmed_lat,
                                                           x_rot,
                                                           y_rot,
                                                           request,
                                                           vectorscale
                                                           )
                    else:
                        raise NotImplementedError('Image type "{}" is not supported.'.format(request.GET['image_type']))