def setUp(self): self.dmap_element = DynamicMap(lambda: Image([])) self.dmap_overlay = DynamicMap(lambda: Overlay([Curve([]), Points([])])) self.dmap_ndoverlay = DynamicMap(lambda: NdOverlay({0: Curve([]), 1: Curve([])})) self.element = Scatter([]) self.el1, self.el2 = Path([]), HLine(0) self.overlay = Overlay([self.el1, self.el2]) self.ndoverlay = NdOverlay({0: VectorField([]), 1: VectorField([])})
def test_ndlayout_overlay_ndlayout_partial_reverse(self): items = [(0, self.view1), (1, self.view2), (3, self.view2)] grid = NdLayout(items, 'X') items2 = [(0, self.view2), (2, self.view2), (3, self.view3)] grid2 = NdLayout(items2, 'X') expected_items = [(0, Overlay([self.view2, self.view1])), (1, Overlay([self.view2])), (2, Overlay([self.view2])), (3, Overlay([self.view3, self.view2]))] expected = NdLayout(expected_items, 'X') self.assertEqual(grid2 * grid, expected)
def test_gridspace_overlay_gridspace_partial_reverse(self): items = [(0, self.view1), (1, self.view2), (3, self.view2)] grid = GridSpace(items, 'X') items2 = [(0, self.view2), (2, self.view2), (3, self.view3)] grid2 = GridSpace(items2, 'X') expected_items = [(0, Overlay([self.view2, self.view1])), (1, Overlay([self.view2])), (2, Overlay([self.view2])), (3, Overlay([self.view3, self.view2]))] expected = GridSpace(expected_items, 'X') self.assertEqual(grid2 * grid, expected)
def __init__(self, **params): self._session = params.get("session") self.title = params.get("viz_instance").title self.overlays = Overlay() self.traces = [] self.tracesParam = [] self.id = params.get("viz_instance").id self.dictParameters = self.get_param_values() self.configTracePanel = pn.Column() self.configVizPanel = pn.Column() self.debugPanel = pn.Column() self.silently = False super(BaseVizApp, self).__init__(**params)
def test_overlay_options_complete(self): """ Complete specification style. """ data = [zip(range(10), range(10)), zip(range(5), range(5))] o = Overlay([Curve(c) for c in data])({ 'Curve.Curve': { 'plot': { 'show_grid': True }, 'style': { 'color': 'b' } } }) self.assertEqual( Store.lookup_options('matplotlib', o.Curve.I, 'plot').kwargs['show_grid'], True) self.assertEqual( Store.lookup_options('matplotlib', o.Curve.II, 'plot').kwargs['show_grid'], True) self.assertEqual( Store.lookup_options('matplotlib', o.Curve.I, 'style').kwargs['color'], 'b') self.assertEqual( Store.lookup_options('matplotlib', o.Curve.II, 'style').kwargs['color'], 'b')
def test_overlay_options_partitioned(self): """ The new style introduced in #73 """ data = [zip(range(10), range(10)), zip(range(5), range(5))] o = Overlay([Curve(c) for c in data ])(dict(plot={'Curve.Curve': { 'show_grid': False }}, style={'Curve.Curve': { 'color': 'k' }})) self.assertEqual( Store.lookup_options('matplotlib', o.Curve.I, 'plot').kwargs['show_grid'], False) self.assertEqual( Store.lookup_options('matplotlib', o.Curve.II, 'plot').kwargs['show_grid'], False) self.assertEqual( Store.lookup_options('matplotlib', o.Curve.I, 'style').kwargs['color'], 'k') self.assertEqual( Store.lookup_options('matplotlib', o.Curve.II, 'style').kwargs['color'], 'k')
def test_interleaved_overlay(self): """ Test to avoid regression after fix of https://github.com/ioam/holoviews/issues/41 """ o = Overlay([ Curve(np.array([[0, 1]])), Scatter([[1, 1]]), Curve(np.array([[0, 1]])) ]) OverlayPlot(o)
def test_overlay_from_values_retains_custom_path_with_label(self): overlay = Overlay([('Custom', self.el6)]) paths = Overlay.from_values([overlay, self.el2]).keys() self.assertEqual(paths, [('Custom', 'LabelA'), ('Element', 'I')])
def test_overlay_constructor2(self): t = Overlay([self.el8]) self.assertEqual(t.keys(), [('ValA', 'LabelB')])
def compose_overlay_plot(self, x_range: Optional[Sequence[float]] = (-1.6, -1.2), y_range: Optional[Sequence[float]] = (50.8, 51.05)) \ -> Union[Overlay, Element]: """ Compose all generated HoloViews layers in self.data_layers into a single overlay plot. Overlaid in a first-on-the-bottom manner. If plot bounds has moved outside of data bounds, generate more as required. :param tuple x_range: (min, max) longitude range in EPSG:4326 coordinates :param tuple y_range: (min, max) latitude range in EPSG:4326 coordinates :returns: overlay plot of stored layers """ from itertools import chain try: if not self._preload_complete: # If layers aren't preloaded yet just return the map tiles self._progress_callback('Still preloading layer data...') plot = self._base_tiles else: # Construct box around requested bounds bounds_poly = make_bounds_polygon(x_range, y_range) raster_shape = self._get_raster_dimensions( bounds_poly, self.raster_resolution_m) # Ensure bounds are small enough to render without OOM or heat death of universe if bounds_poly.area < 0.2: from time import time t0 = time() self._progress_bar_callback(10) self.generate_layers(bounds_poly, raster_shape) self._progress_bar_callback(50) plot = Overlay([ res[0] for res in self._generated_data_layers.values() ]) print("Generated all layers in ", time() - t0) if self.annotation_layers: import matplotlib.pyplot as mpl plot = Overlay([ res[0] for res in self._generated_data_layers.values() ]) raw_datas = [ res[2] for res in self._generated_data_layers.values() ] raster_indices = dict( Longitude=np.linspace(x_range[0], x_range[1], num=raster_shape[0]), Latitude=np.linspace(y_range[0], y_range[1], num=raster_shape[1])) raster_grid = np.zeros( (raster_shape[1], raster_shape[0]), dtype=np.float64) for res in self._generated_data_layers.values(): layer_raster_grid = res[1] if layer_raster_grid is not None: nans = np.isnan(layer_raster_grid) layer_raster_grid[nans] = 0 raster_grid += layer_raster_grid raster_grid = np.flipud(raster_grid) raster_indices['Latitude'] = np.flip( raster_indices['Latitude']) self._progress_callback('Annotating Layers...') res = jl.Parallel( n_jobs=1, verbose=1, backend='threading')( jl.delayed(layer.annotate)(raw_datas, ( raster_indices, raster_grid)) for layer in self.annotation_layers) annotation_overlay = Overlay( [annot for annot in res if annot is not None]) plot = Overlay( [self._base_tiles, plot, annotation_overlay]).collate() else: plot = Overlay([self._base_tiles, plot]).collate() self._progress_bar_callback(90) else: self._progress_callback('Area too large to render!') if not self._generated_data_layers: plot = self._base_tiles else: plot = Overlay([ self._base_tiles, *list(self._generated_data_layers.values()) ]) layers = [] for layer in chain(self.data_layers, self.annotation_layers): d = {'key': layer.key} if hasattr(layer, '_colour'): d.update(colour=layer._colour) if hasattr(layer, '_osm_tag'): d.update(dataTag=layer._osm_tag) layers.append(d) self._progress_callback("Rendering new map...") self._update_callback( list(chain(self.data_layers, self.annotation_layers))) except Exception as e: # Catch-all to prevent plot blanking out and/or crashing app # Just display map tiles in case this was transient import traceback traceback.print_exc() print(e) plot = self._base_tiles return plot.opts(width=self.plot_size[0], height=self.plot_size[1], tools=self.tools, active_tools=self.active_tools)
def overlaypairs(self, pairs): "returns an overlay to display the pairings" return Overlay([ Curve([self._toxy(f1), self._toxy(f2)]) for i, (f1, f2) in enumerate(pairs) ])
def test_overlay_group(self): t1 = (self.el1 * self.el2) t2 = Overlay(list(t1.relabel(group='NewValue'))) self.assertEqual(t2.keys(), [('NewValue', 'I'), ('NewValue', 'II')])
def test_overlay_from_values1(self): t = Overlay.from_values(self.el1) self.assertEqual(t.keys(), [('Element', 'I')])
def test_overlay_from_values2(self): t = Overlay.from_values(self.el8) self.assertEqual(t.keys(), [('ValA', 'LabelB')])
def test_overlay_constructor1(self): t = Overlay([self.el1]) self.assertEqual(t.keys(), [('Element', 'I')])
def test_overlay_keys_2(self): t = Overlay([self.el1, self.el2]) self.assertEqual(t.keys(), [('Element', 'I'), ('Element', 'II')])
def test_overlay_constructor_retains_custom_path(self): overlay = Overlay([('Custom', self.el1)]) paths = Overlay([overlay, self.el2]).keys() self.assertEqual(paths, [('Custom', 'I'), ('Element', 'I')])
class BaseVizApp(param.Parameterized): rafraichir = param.Action(lambda self: self.refreshViz()) nb_loaded = param.String(default='') viewable = param.Boolean(True) loaded = param.Boolean(default=False) change_state = param.Boolean(True) traceSelector = param.ObjectSelector() def __init__(self, **params): self._session = params.get("session") self.title = params.get("viz_instance").title self.overlays = Overlay() self.traces = [] self.tracesParam = [] self.id = params.get("viz_instance").id self.dictParameters = self.get_param_values() self.configTracePanel = pn.Column() self.configVizPanel = pn.Column() self.debugPanel = pn.Column() self.silently = False super(BaseVizApp, self).__init__(**params) @param.depends( "viewable", "loaded", "change_state" ) # ajouter aussi dans les classes heritantes de la baseVizApp def view(self): if self.viewable and not self.loaded: # lorque la Viz app est chargé coté client on lance les chargements assynchrone des données FULL print("Chargement assynchrone des données ") self.tracesLoader(assyncLoading=True) if self.viewable != True: return elif self.viewable: print(""" -------------------- Rendu du composant {} -------------------- """.format(self)) return self.getView() ###### Gestion des Panels def getDebugPanel(self): self.debugPanel = pn.Column(self.param) return self.debugPanel def getConfigTracePanel(self, **params): return self.configTracePanel def getConfigVizPanel(self): return self.configVizPanel ###### Gestion des Rafraichissements def refreshViz(self): for trace in self.traces: self.doRefreshByTrace(trace) def doRefreshByTrace(self, trace): traceP = self.getTraceParamByTrace(trace) overlay = self.configureOverlay(trace) self.refreshOverlay(overlay, traceP=traceP) self.changeState() def doRefreshByTraceParam(self, traceP): trace = self.getTraceByTraceParam(traceP) overlay = self.configureOverlay(trace) self.refreshOverlay(overlay, traceP=traceP) self.changeState() def changeState(self): if self.change_state == True: self.change_state = False else: self.change_state = True ###### Gestion des TRACES def getTraceParamByTrace(self, trace): for tuple in self.tracesParam: if tuple[0] == trace: return tuple[1] def getTraceByTraceParam(self, traceParam): for tuple in self.tracesParam: if tuple[1] == traceParam: return tuple[0] def getAllTraceParam(self): return [tuple[1] for tuple in self.tracesParam] def addTrace(self, trace): if not trace in self.traces: self.traces.append(trace) traceP = TraceParam(trace=trace, data=trace.dataFrame, viz=self) self.tracesParam.append((trace, traceP)) def tracesLoader(self, assyncLoading=True): for trace in self.traces: self.dataLoader(trace, assyncLoading) self.nb_loaded = str(trace.dataFrame.shape[0]) if not assyncLoading: self.setLoaded() trace.setReady() def dataLoader(self, trace, assyncLoading=True): allDataAlreadyGetFromCache = None traceP = self.getTraceParamByTrace(trace) # on regarde d'abord si les full data sont en cache trace.configureConnector(FULL) if trace.isDataInCache: trace.lookCachedData() allDataAlreadyGetFromCache = True else: print("Les données Full ne sont pas en cache") # on regarde maintenant si le sample est en cache trace.configureConnector(SAMPLE) if trace.isDataInCache: trace.lookCachedData() else: print("Les données SAMPLE ne sont pas en cache") # sinon on charge les données sample trace.loadData() trace.finishConnection() if trace.getTotalNbEntity == trace.dataFrame.shape[0]: # on a toute les données disponible même avec le sample allDataAlreadyGetFromCache = True self.nb_loaded = str(trace.dataFrame.shape[0]) if allDataAlreadyGetFromCache: self.setLoaded() trace.setReady() self.doRefreshByTrace(trace) return else: overlay = self.configureOverlay(trace=trace) self.addOverlay(overlay, traceParam=traceP) if assyncLoading == True: self.initProgressBarForAllVizWithSameTrace(trace=trace) self.assyncLoading(trace) else: print(trace.dataFrame.head()) def assyncLoading(self, trace): trace.configureConnector(FULL) # on va chercher toutes les données en assync # tache assynchrone de loading de l'ensemble des entités loop = IOLoop.current() traceParam = self.getTraceParamByTrace(trace) trace.connectorInterface.connector.nbEntityLoaded = 0 for i in range(0, traceParam.progress.num_tasks): future = executor.submit(blocking_function, self, trace=trace, step=i * LIMIT_PARAM) loop.add_future(future, self.updateProgressBar) loop.add_future(future, self.update) def updateProgressBar(self, future): trace = future.result()[1] traceParam = self.getTraceParamByTrace(trace) with pn.io.unlocked(): traceParam.progress.completed += 1 if traceParam.progress.completed == traceParam.progress.num_tasks: traceParam.progress.reset() self.setLoaded() trace.setReady() def update(self, future): trace = future.result()[1] viz = future.result()[0] #self.refreshAllVizWithSameTrace(trace=trace) with pn.io.unlocked(): self = viz # update des reference pour le cache trace.connectorInterface.full_data = trace.dataFrame self.doRefreshByTrace(trace) def setLoaded(self): if self.loaded == False: self.loaded = True self.loaded = True ###### gestion des OVERLAYS def configureOverlay(self, trace, viz=None): # on ajoute une traceParam à la viz pour pouvoir la manipuler par la suite if not viz == None: self = viz traceP = self.getTraceParamByTrace(trace) if not traceP: traceP = TraceParam(trace=trace, data=trace.dataFrame, viz=self) self.tracesParam.append((trace, traceP)) else: # on met à jour le dataframe de la traceP traceP.data = traceP.getUpdatedData(trace.dataFrame) overlay = self.createOverlay(traceParam=traceP, label=trace.name) self.nb_loaded = str(trace.dataFrame.shape[0]) return overlay def finderOverlayByGroup(self, tree, groupName): children = tree.get('children') for child in children: node = tree.get(child) if node.group == groupName: return node else: if hasattr(node, 'children'): self.finderOverlayByGroup(node, groupName) else: return None def delGroupOverlay(self, groupName): if groupName in self.overlays.children: self.overlays.__delitem__(groupName) def addOverlay(self, newOverlay, traceParam): if not newOverlay: return if self.overlays: if traceParam.groupeName: self.delGroupOverlay(traceParam.groupeName) self.overlays = self.overlays * newOverlay else: self.overlays = self.overlays * newOverlay else: self.overlays = hv.Overlay([newOverlay]) traceParam.setOverlay(newOverlay) return self.overlays def clearAllOverlays(self): self.overlays = hv.Overlay() def getAllOverlay(self): new_attrtree = AttrTree() for path, item in self.overlays.data.items(): if path[0] != 'Tiles': new_attrtree.set_path(path, item) return new_attrtree def refreshOverlay(self, overlay, traceP): self.addOverlay(overlay, traceParam=traceP) print("After refreshing overlay with options : ", self.overlays.opts.info()) def findAllPathStringOverlayWithout(self, idToNotKeep): pathList = [] for keys, overlay in self.overlays.data.items(): if overlay.id != idToNotKeep.id: pathList.append('.'.join(keys)) return pathList def findPathStringOverlayByTraceId(self, overlayId): for keys, overlay in self.overlays.data.items(): if overlay.id == overlayId: pathString = '.'.join(keys) return pathString def setOption(self, option): options = hv.Options(option) return self.opts(options) #### Fonctions sur de multiples Instances Viz def refreshAllVizWithSameTrace(self, trace=None): vizListe = VizConstructor.getVizByTraceIdAndSessionId( traceId=trace.id, sessionId=self._session) for viz in vizListe: viz.doRefreshByTrace(trace) def createAllVizWithSameTrace(self, trace=None): vizListe = VizConstructor.getVizByTraceIdAndSessionId( traceId=trace.id, sessionId=self._session) for viz in vizListe: overlay = self.configureOverlay(trace=trace, viz=viz) traceP = self.getTraceParamByTrace(trace) viz.addOverlay(overlay, traceParam=traceP) if len(vizListe) > 1: pass #DataLink(vizListe[0].overlays.Polygons, vizListe[1].overlays.Polygons) def initProgressBarForAllVizWithSameTrace(self, trace=None): traceParam = self.getTraceParamByTrace(trace) traceParam.progress.num_tasks = trace.getNbRequest #### Divers def formatter(value): return str(value) ############## @abstractmethod # abstractMethod def createOverlay(self, **kwargs): data = kwargs["traceParam"].data return data.hvplot() def getView(self): pass def getPanel(self): pass
def test_overlay_id_inheritance(self): overlay = Overlay([], id=1) self.assertEqual(overlay.clone().id, 1) self.assertEqual(overlay.clone()._plot_id, overlay._plot_id) self.assertNotEqual(overlay.clone([])._plot_id, overlay._plot_id)
def test_overlay_values_2(self): t = Overlay([self.el1, self.el2]) self.assertEqual(t.values(), [self.el1, self.el2])
def test_overlay_with_holomap(self): overlay = Overlay([('Custom', self.el6)]) composite = overlay * HoloMap({0: Element(None, group='HoloMap')}) self.assertEqual(composite.last.keys(), [('Custom', 'LabelA'), ('HoloMap', 'I')])
def compose_overlay_plot(self, x_range: Optional[Sequence[float]] = (-1.6, -1.2), y_range: Optional[Sequence[float]] = (50.8, 51.05)) \ -> Union[Overlay, Element]: """ Compose all generated HoloViews layers in self.data_layers into a single overlay plot. Overlaid in a first-on-the-bottom manner. If plot bounds has moved outside of data bounds, generate more as required. :param tuple x_range: (min, max) longitude range in EPSG:4326 coordinates :param tuple y_range: (min, max) latitude range in EPSG:4326 coordinates :returns: overlay plot of stored layers """ try: if not self._preload_complete: # If layers aren't preloaded yet just return the map tiles self._progress_callback('Still preloading layer data...') plot = self._base_tiles else: # Construct box around requested bounds bounds_poly = make_bounds_polygon(x_range, y_range) raster_shape = self._get_raster_dimensions( bounds_poly, self.raster_resolution_m) # Ensure bounds are small enough to render without OOM or heat death of universe if (raster_shape[0] * raster_shape[1]) < 7e5: from time import time t0 = time() self._progress_bar_callback(10) # TODO: This will give multiple data layers, these need to be able to fed into their relevent pathfinding layers for annlayer in self.annotation_layers: new_layer = FatalityRiskLayer( 'Fatality Risk', ac=annlayer.aircraft['name']) self.add_layer(new_layer) self.remove_duplicate_layers() self._progress_bar_callback(20) self.generate_layers(bounds_poly, raster_shape) self._progress_bar_callback(50) plt_lyr = list(self._generated_data_layers)[0] plot = Overlay([self._generated_data_layers[plt_lyr][0]]) print("Generated all layers in ", time() - t0) if self.annotation_layers: plot = Overlay( [self._generated_data_layers[plt_lyr][0]]) res = [] prog_bar = 50 for dlayer in self.data_layers: raster_indices = dict( Longitude=np.linspace(x_range[0], x_range[1], num=raster_shape[0]), Latitude=np.linspace(y_range[0], y_range[1], num=raster_shape[1])) raw_data = [ self._generated_data_layers[dlayer.key][2] ] raster_grid = np.sum([ remove_raster_nans( self._generated_data_layers[dlayer.key][1]) ], axis=0) raster_grid = np.flipud(raster_grid) raster_indices['Latitude'] = np.flip( raster_indices['Latitude']) for alayer in self.annotation_layers: if alayer.aircraft == dlayer.ac_dict: self._progress_bar_callback(prog_bar) prog_bar += 40 / len( self.annotation_layers) self._progress_callback( f'Finding a path for {alayer.aircraft["name"]}' ) res.append( alayer.annotate( raw_data, (raster_indices, raster_grid))) self._progress_callback('Plotting paths') self._progress_bar_callback(90) # res = jl.Parallel(n_jobs=1, verbose=1, backend='threading')( # jl.delayed(layer.annotate)(raw_datas, (raster_indices, raster_grid)) for layer in # self.annotation_layers ) plot = Overlay([ self._base_tiles, plot, *[annot for annot in res if annot is not None] ]).collate() else: plot = Overlay([self._base_tiles, plot]).collate() self._progress_bar_callback(90) else: self._progress_callback('Area too large to render!') if not self._generated_data_layers: plot = self._base_tiles else: plot = Overlay([ self._base_tiles, *list(self._generated_data_layers.values()) ]) self._update_layer_list() self._progress_callback("Rendering new map...") except Exception as e: # Catch-all to prevent plot blanking out and/or crashing app # Just display map tiles in case this was transient import traceback traceback.print_exc() self._progress_callback( f'Plotting failed with the following error: {e}. Please attempt to re-generate the plot' ) print(e) plot = self._base_tiles return plot.opts(width=self.plot_size[0], height=self.plot_size[1], tools=self.tools, active_tools=self.active_tools)