diff --git a/viziphant/patterns.py b/viziphant/patterns.py index 2854b9a..926beee 100644 --- a/viziphant/patterns.py +++ b/viziphant/patterns.py @@ -399,8 +399,8 @@ def plot_patterns(spiketrains, patterns, circle_sizes=(3, 50, 70), axes.yaxis.set_label_coords(-0.01, 0.5) return axes -def plot_patterns_hypergraph(patterns, node_size=3, pattern_size=None, num_neurons=None,\ - highlight_patterns=None, mark_neuron=None, node_color='white'): +def plot_patterns_hypergraph(patterns, pattern_size=None, num_neurons=None,\ + must_involve_neuron=None, node_size=3, node_color='white', node_linewidth=1): """ Hypergraph visualization of spike patterns. @@ -432,17 +432,21 @@ def plot_patterns_hypergraph(patterns, node_size=3, pattern_size=None, num_neuro pattern detectors. node_size (optional): int Change the size of the drawen nodes - pattern_size (optional): tuple or int + pattern_size (optional): range Only draw patterns that are in range of pattern_size num_neurons: None or int If None, only the neurons that are part of a pattern are shown. If an integer is passed, it identifies the total number of recorded neurons including non-pattern neurons to be additionally shown in the graph. Default: None - highlight_patterns (optional) : int + must_involve_neuron (optional) : int Highlight pattern which includes neuron x node_color (optional) : String change the color of the nodes + + node_linewidth (optional) : int + change the line width of the nodes + Returns ------- A handle to a matplotlib figure containing the hypergraph. @@ -500,33 +504,18 @@ def plot_patterns_hypergraph(patterns, node_size=3, pattern_size=None, num_neuro # Create one hypergraph per dataset hyperedges = [] - - # Create "range" of pattern_size - if (isinstance(pattern_size, int)): pattern_size=(pattern_size, pattern_size) - # Create one hyperedge from every pattern for pattern in patterns: # A hyperedge is the set of neurons of a pattern - if pattern_size is None: - hyperedges.append(pattern['neurons']) - # check if hyperedge(pattern) is greater or equal to min_pattern_size - elif len(pattern['neurons']) >= pattern_size[0] and len(pattern['neurons']) <= pattern_size[1] or highlight_patterns in pattern['neurons']: + if pattern_size is None or len(pattern['neurons']) in pattern_size: hyperedges.append(pattern['neurons']) - # check if neuron to highlight is in hyperedge - temp_hyperedges = [] - if highlight_patterns is not None: - if isinstance(highlight_patterns, int): - for edge in hyperedges: - if highlight_patterns in edge: - temp_hyperedges.append(edge) - hyperedges = temp_hyperedges - - # TODO: highlight_patterns as a list - - if (len(hyperedges) == 0): - raise Exception('Could not find any hyperedges that match the given parameters') + if must_involve_neuron is not None and isinstance(must_involve_neuron, int): + hyperedges = [edge for edge in hyperedges if must_involve_neuron in edge] + elif must_involve_neuron is not None and isinstance(must_involve_neuron, list): + hyperedges = [edge for edge in hyperedges if any(elem in edge for elem in must_involve_neuron)] + # Currently, all hyperedges receive the same weights weights = [weight] * len(hyperedges) @@ -536,7 +525,8 @@ def plot_patterns_hypergraph(patterns, node_size=3, pattern_size=None, num_neuro weights=weights, repulse=repulsive) hypergraphs.append(hg) - view = View(hypergraphs, node_size, mark_neuron, node_color) + view = View(hypergraphs=hypergraphs, node_size=node_size, + node_color=node_color, node_linewidth=node_linewidth) fig = view.show(subset_style=VisualizationStyle.COLOR, triangulation_style=VisualizationStyle.INVISIBLE) diff --git a/viziphant/patterns_src/hypergraph.py b/viziphant/patterns_src/hypergraph.py index 6a2a0fe..9e00cb1 100644 --- a/viziphant/patterns_src/hypergraph.py +++ b/viziphant/patterns_src/hypergraph.py @@ -104,15 +104,23 @@ def complete_and_star_associated_graph(self): edges = [] weights = [] graph_vertices = list(self.vertices.copy()) + if isinstance(self.vertices[0], int): + max_vertex = max(max(hyperedge) for hyperedge in self.hyperedges) + else: + max_vertex = 0 + if isinstance(max_vertex, str): + max_vertex = 0 for i, hyperedge in enumerate(self.hyperedges): # Pseudo-vertex corresponding to hyperedge - graph_vertices.append(-i - 1) + pseudo_vertex = max_vertex + i + 1 + graph_vertices.append(pseudo_vertex) + for j, vertex in enumerate(hyperedge): # Every vertex of a hyperedge is adjacent to the pseudo-vertex # corresponding to the hyperedge - edges.append([-i - 1, vertex]) - # Weight is equal to the weight of the hyperedge (if - # applicable) + edges.append([pseudo_vertex, vertex]) + + # Weight is equal to the weight of the hyperedge (if applicable) if self.weights: weights.append(self.weights[i]) # Unique unordered combinations of vertices of this hyperedge diff --git a/viziphant/patterns_src/view.py b/viziphant/patterns_src/view.py index b340600..f9e5358 100644 --- a/viziphant/patterns_src/view.py +++ b/viziphant/patterns_src/view.py @@ -34,8 +34,7 @@ class View: In summary, this class represents an interactive tool for the visualization of hypergraphs. """ - - def __init__(self, hypergraphs, node_size=3, mark_neuron=None, node_color='white', title=None): + def __init__(self, hypergraphs, node_size=3, node_color='white', node_linewidth=1, title=None): """ Constructs a View object that handles the visualization of the given hypergraphs. @@ -49,11 +48,11 @@ def __init__(self, hypergraphs, node_size=3, mark_neuron=None, node_color='white node_size (optional) : int Size of the nodes in the Hypergraphs - mark_neuron (optional) : int - Neuron with given number will be highlighted - node_color (optional) : String change the color of the nodes + + node_linewidth (optional) : int + change the line width of the nodes """ # Hyperedge drawings @@ -71,12 +70,12 @@ def __init__(self, hypergraphs, node_size=3, mark_neuron=None, node_color='white # Color of the nodes self.node_color = node_color + # Width of the Node lines + self.node_linewidth = node_linewidth + # Selected title of the figure self.title = title - # Marked node will be in a different color - self.mark_neuron = mark_neuron - # If no data was provided, fill in dummy data if hypergraphs: self.hypergraphs = hypergraphs @@ -125,7 +124,7 @@ def _setup_graph_visualization(self): # The hv.Graph visualization is used for displaying the data # hv.Graph displays the nodes (and optionally binary edges) of a graph dynamic_map = hv.DynamicMap(hv.Graph, streams=[pipe]) - + # Define options for visualization dynamic_map.opts( # Some space around the Graph in order to avoid nodes being on the @@ -142,7 +141,7 @@ def _setup_graph_visualization(self): # All in black cmap=['#ffffff', '#ffffff'] * 50, # Size of the nodes - node_size=self.node_size, node_color=self.node_color, show_legend=True)) + node_size=self.node_size, node_color=self.node_color, node_linewidth=self.node_linewidth, show_legend=True)) return dynamic_map, pipe def _setup_hyperedge_drawing(self):