class GridLayer(BaseLayer): def __init__(self, lon_edges, lat_edges, values, cmap, alpha=255, vmin=None, vmax=None): self.lon_edges = lon_edges self.lat_edges = lat_edges self.values = values self.cmap = colors.ColorMap(cmap, alpha=alpha) if vmin: self.vmin = vmin else: self.vmin = 0 if vmax: self.vmax = vmax else: self.vmax = self.values.max() def invalidate(self, proj): self.painter = BatchPainter() xv, yv = proj.lonlat_to_screen(self.lon_edges, self.lat_edges) rects = [] cols = [] for ix in range(len(xv) - 1): for iy in range(len(yv) - 1): d = self.values[iy, ix] if d > self.vmin: rects.append((xv[ix], yv[iy], xv[ix + 1], yv[iy + 1])) cols.append(self.cmap.to_color(d, self.vmax, 'lin')) self.painter.batch_rects(rects, cols) def draw(self, proj, mouse_x, mouse_y, ui_manager): self.painter.batch_draw()
class GridLayer(BaseLayer): def __init__(self, lon_edges, lat_edges, values, cmap, alpha=255, vmin=None, vmax=None): self.lon_edges = lon_edges self.lat_edges = lat_edges self.values = values self.cmap = colors.ColorMap(cmap, alpha=alpha) if vmin: self.vmin = vmin else: self.vmin = 0 if vmax: self.vmax = vmax else: self.vmax = self.values.max() def invalidate(self, proj): self.painter = BatchPainter() xv, yv = proj.lonlat_to_screen(self.lon_edges, self.lat_edges) rects = [] cols = [] for ix in range(len(xv)-1): for iy in range(len(yv)-1): d = self.values[iy, ix] if d > self.vmin: rects.append((xv[ix], yv[iy], xv[ix+1], yv[iy+1])) cols.append(self.cmap.to_color(d, self.vmax, 'lin')) self.painter.batch_rects(rects, cols) def draw(self, proj, mouse_x, mouse_y, ui_manager): self.painter.batch_draw()
class GridLayer(BaseLayer): def __init__(self, lon_edges, lat_edges, values, cmap, alpha=255, vmin=None, vmax=None, levels=10, colormap_scale='lin', show_colorbar=True): """ Values over a uniform grid :param lon_edges: longitude edges :param lat_edges: latitude edges :param values: matrix representing values on the grid :param cmap: colormap name :param alpha: color alpha :param vmin: minimum value for the colormap :param vmax: maximum value for the colormap :param levels: number of levels for the colormap :param colormap_scale: colormap scale :param show_colorbar: show the colorbar in the UI """ self.lon_edges = lon_edges self.lat_edges = lat_edges self.values = values self.cmap = colors.ColorMap(cmap, alpha=alpha, levels=levels) self.colormap_scale = colormap_scale self.show_colorbar = show_colorbar if vmin: self.vmin = vmin else: self.vmin = 0 if vmax: self.vmax = vmax else: self.vmax = self.values[~np.isnan(self.values)].max() def invalidate(self, proj): self.painter = BatchPainter() xv, yv = proj.lonlat_to_screen(self.lon_edges, self.lat_edges) rects = [] cols = [] for ix in range(len(xv) - 1): for iy in range(len(yv) - 1): d = self.values[iy, ix] if d > self.vmin: rects.append((xv[ix], yv[iy], xv[ix + 1], yv[iy + 1])) cols.append( self.cmap.to_color(d, self.vmax, self.colormap_scale)) self.painter.batch_rects(rects, cols) def draw(self, proj, mouse_x, mouse_y, ui_manager): self.painter.batch_draw() if self.show_colorbar: ui_manager.add_colorbar(self.cmap, self.vmax, self.colormap_scale) def bbox(self): return BoundingBox(north=self.lat_edges[-1], south=self.lat_edges[0], west=self.lon_edges[0], east=self.lon_edges[-1])
class KDELayer(BaseLayer): def __init__(self, values, bw, cmap='hot', method='hist', scaling='sqrt', alpha=220, cut_below=None, clip_above=None, binsize=1, cmap_levels=10, show_colorbar=False): """ Kernel density estimation visualization :param data: data access object :param bw: kernel bandwidth (in screen coordinates) :param cmap: colormap :param method: if kde use KDEMultivariate from statsmodel, which provides a more accurate but much slower estimation. If hist, estimates density applying gaussian smoothing on a 2D histogram, which is much faster but less accurate :param scaling: colorscale, lin log or sqrt :param alpha: color alpha :param cut_below: densities below cut_below are not drawn :param clip_above: defines the max value for the colorscale :param binsize: size of the bins for hist estimator :param cmap_levels: discretize colors into cmap_levels :param show_colorbar: show colorbar """ self.values = values self.bw = bw self.cmap = colors.ColorMap(cmap, alpha=alpha, levels=cmap_levels) self.method = method self.scaling = scaling self.cut_below = cut_below self.clip_above = clip_above self.binsize = binsize self.show_colorbar = show_colorbar def _get_grid(self, proj): west, north = proj.lonlat_to_screen([proj.bbox().west], [proj.bbox().north]) east, south = proj.lonlat_to_screen([proj.bbox().east], [proj.bbox().south]) xgrid = np.arange(west, east, self.binsize) ygrid = np.arange(south, north, self.binsize) return xgrid, ygrid def invalidate(self, proj): self.painter = BatchPainter() xv, yv = proj.lonlat_to_screen(self.values['lon'], self.values['lat']) rects_vertices = [] rects_colors = [] if self.method == 'kde': try: import statsmodels.api as sm except: raise Exception('KDE requires statsmodel') kde_res = sm.nonparametric.KDEMultivariate(data=[xv, yv], var_type='cc', bw=self.bw) xgrid, ygrid = self._get_grid(proj) xmesh, ymesh = np.meshgrid(xgrid, ygrid) grid_coords = np.append(xmesh.reshape(-1, 1), ymesh.reshape(-1, 1), axis=1) z = kde_res.pdf(grid_coords.T) z = z.reshape(len(ygrid), len(xgrid)) # np.save('z.npy', z) # z = np.load('z.npy') print(('smallest non-zero density:', z[z > 0][0])) print(('max density:', z.max())) if self.cut_below is None: zmin = z[z > 0][0] else: zmin = self.cut_below if self.clip_above is None: zmax = z.max() else: zmax = self.clip_above for ix in range(len(xgrid) - 1): for iy in range(len(ygrid) - 1): if z[iy, ix] > zmin: rects_vertices.append((xgrid[ix], ygrid[iy], xgrid[ix + 1], ygrid[iy + 1])) rects_colors.append( self.cmap.to_color(z[iy, ix], zmax, self.scaling)) elif self.method == 'hist': try: from scipy.ndimage import gaussian_filter except: raise Exception('KDE requires scipy') xgrid, ygrid = self._get_grid(proj) H, _, _ = np.histogram2d(yv, xv, bins=(ygrid, xgrid)) if H.sum() == 0: print('no data in current view') return H = gaussian_filter(H, sigma=self.bw) print(('smallest non-zero count', H[H > 0][0])) print(('max count:', H.max())) if self.cut_below is None: Hmin = H[H > 0][0] else: Hmin = self.cut_below if self.clip_above is None: self.Hmax = H.max() else: self.Hmax = self.clip_above if self.scaling == 'ranking': from statsmodels.distributions.empirical_distribution import ECDF ecdf = ECDF(H.flatten()) for ix in range(len(xgrid) - 2): for iy in range(len(ygrid) - 2): if H[iy, ix] > Hmin: rects_vertices.append((xgrid[ix], ygrid[iy], xgrid[ix + 1], ygrid[iy + 1])) if self.scaling == 'ranking': rects_colors.append( self.cmap.to_color( ecdf(H[iy, ix]) - ecdf(Hmin), 1 - ecdf(Hmin), 'lin')) else: rects_colors.append( self.cmap.to_color(H[iy, ix], self.Hmax, self.scaling)) else: raise Exception('method not supported') self.painter.batch_rects(rects_vertices, rects_colors) def draw(self, proj, mouse_x, mouse_y, ui_manager): self.painter.batch_draw() if self.show_colorbar: ui_manager.add_colorbar(self.cmap, self.Hmax, self.scaling)
class KDELayer(BaseLayer): def __init__(self, values, bw, cmap='hot', method='hist', scaling='sqrt', alpha=220, cut_below=None, clip_above=None, binsize=1, cmap_levels=10): """ Kernel density estimation visualization :param data: data access object :param bw: kernel bandwidth (in screen coordinates) :param cmap: colormap :param method: if kde use KDEMultivariate from statsmodel, which provides a more accurate but much slower estimation. If hist, estimates density applying gaussian smoothing on a 2D histogram, which is much faster but less accurate :param scaling: colorscale, lin log or sqrt :param alpha: color alpha :param cut_below: densities below cut_below are not drawn :param clip_above: defines the max value for the colorscale :param binsize: size of the bins for hist estimator :param cmap_levels: discretize colors into cmap_levels """ self.values = values self.bw = bw self.cmap = colors.ColorMap(cmap, alpha=alpha, levels=cmap_levels) self.method = method self.scaling = scaling self.cut_below = cut_below self.clip_above = clip_above self.binsize = binsize def _get_grid(self, proj): west, north = proj.lonlat_to_screen([proj.bbox().west], [proj.bbox().north]) east, south = proj.lonlat_to_screen([proj.bbox().east], [proj.bbox().south]) xgrid = np.arange(west, east, self.binsize) ygrid = np.arange(south, north, self.binsize) return xgrid, ygrid def invalidate(self, proj): self.painter = BatchPainter() xv, yv = proj.lonlat_to_screen(self.values['lon'], self.values['lat']) rects_vertices = [] rects_colors = [] if self.method == 'kde': try: import statsmodels.api as sm except: raise Exception('KDE requires statsmodel') kde_res = sm.nonparametric.KDEMultivariate(data=[xv, yv], var_type='cc', bw=self.bw) xgrid, ygrid = self._get_grid(proj) xmesh, ymesh = np.meshgrid(xgrid,ygrid) grid_coords = np.append(xmesh.reshape(-1,1), ymesh.reshape(-1,1),axis=1) z = kde_res.pdf(grid_coords.T) z = z.reshape(len(ygrid), len(xgrid)) # np.save('z.npy', z) # z = np.load('z.npy') print('smallest non-zero density:', z[z > 0][0]) print('max density:', z.max()) if self.cut_below is None: zmin = z[z > 0][0] else: zmin = self.cut_below if self.clip_above is None: zmax = z.max() else: zmax = self.clip_above for ix in range(len(xgrid)-1): for iy in range(len(ygrid)-1): if z[iy, ix] > zmin: rects_vertices.append((xgrid[ix], ygrid[iy], xgrid[ix+1], ygrid[iy+1])) rects_colors.append(self.cmap.to_color(z[iy, ix], zmax, self.scaling)) elif self.method == 'hist': try: from scipy.ndimage import gaussian_filter except: raise Exception('KDE requires scipy') xgrid, ygrid = self._get_grid(proj) H, _, _ = np.histogram2d(yv, xv, bins=(ygrid, xgrid)) H = gaussian_filter(H, sigma=self.bw) print('smallest non-zero count', H[H > 0][0]) print('max count:', H.max()) if self.cut_below is None: Hmin = H[H > 0][0] else: Hmin = self.cut_below if self.clip_above is None: Hmax = H.max() else: Hmax = self.clip_above if self.scaling == 'ranking': from statsmodels.distributions.empirical_distribution import ECDF ecdf = ECDF(H.flatten()) for ix in range(len(xgrid)-2): for iy in range(len(ygrid)-2): if H[iy, ix] > Hmin: rects_vertices.append((xgrid[ix], ygrid[iy], xgrid[ix+1], ygrid[iy+1])) if self.scaling == 'ranking': rects_colors.append(self.cmap.to_color(ecdf(H[iy, ix]) - ecdf(Hmin), 1 - ecdf(Hmin), 'lin')) else: rects_colors.append(self.cmap.to_color(H[iy, ix], Hmax, self.scaling)) else: raise Exception('method not supported') self.painter.batch_rects(rects_vertices, rects_colors) def draw(self, proj, mouse_x, mouse_y, ui_manager): self.painter.batch_draw()
class GridLayer(BaseLayer): def __init__(self, lon_edges, lat_edges, values, cmap, alpha=255, vmin=None, vmax=None, levels=10, colormap_scale='lin', show_colorbar=True): """ Values over a uniform grid :param lon_edges: longitude edges :param lat_edges: latitude edges :param values: matrix representing values on the grid :param cmap: colormap name :param alpha: color alpha :param vmin: minimum value for the colormap :param vmax: maximum value for the colormap :param levels: number of levels for the colormap :param colormap_scale: colormap scale :param show_colorbar: show the colorbar in the UI """ self.lon_edges = lon_edges self.lat_edges = lat_edges self.values = values self.cmap = colors.ColorMap(cmap, alpha=alpha, levels=levels) self.colormap_scale = colormap_scale self.show_colorbar = show_colorbar if vmin: self.vmin = vmin else: self.vmin = 0 if vmax: self.vmax = vmax else: self.vmax = self.values[~np.isnan(self.values)].max() def invalidate(self, proj): self.painter = BatchPainter() xv, yv = proj.lonlat_to_screen(self.lon_edges, self.lat_edges) rects = [] cols = [] for ix in range(len(xv)-1): for iy in range(len(yv)-1): d = self.values[iy, ix] if d > self.vmin: rects.append((xv[ix], yv[iy], xv[ix+1], yv[iy+1])) cols.append(self.cmap.to_color(d, self.vmax, self.colormap_scale)) self.painter.batch_rects(rects, cols) def draw(self, proj, mouse_x, mouse_y, ui_manager): self.painter.batch_draw() if self.show_colorbar: ui_manager.add_colorbar(self.cmap, self.vmax, self.colormap_scale) def bbox(self): return BoundingBox(north=self.lat_edges[-1], south=self.lat_edges[0], west=self.lon_edges[0], east=self.lon_edges[-1])