def get_x_and_y_degrees(network: nx.Graph) -> (np.array, np.array): """ For the given network, creates two arrays (x_degrees and y_degrees) of the degrees of "start" and "end" nodes of each edge in the network. For undirected networks, each edge is considered twice. Parameters ---------- network: a NetworkX graph object Returns ------- degree_arrays: a (x_degrees, y_degrees) tuple where x_degrees and y_degrees are NumPy arrays """ edges = network.edges() n_edges = len(edges) x_degrees = np.zeros(2 * n_edges) y_degrees = np.zeros(2 * n_edges) for i, (start, end) in enumerate(network.edges_iter()): x_degrees[2 * i] = network.degree(start) x_degrees[2 * i + 1] = network.degree(end) y_degrees[2 * i] = network.degree(end) y_degrees[2 * i + 1] = network.degree(start) return x_degrees, y_degrees
def edmondskarp(G: nx.Graph, s, t): RG = G.copy() for u,v in G.edges_iter(): G.edge[u][v]['flow'] = 0 path = isthereapath(RG,s,t) while len(path) > 0: path_cp = min([RG.edge[u][v]['capacity'] for u,v in path]) for u,v in path: if G.has_edge(u,v): G.edge[u][v]['flow'] += path_cp RG.edge[u][v]['capacity'] -= path_cp if RG.edge[u][v]['capacity'] == 0: RG.remove_edge(u,v) if RG.has_edge(v,u): RG.edge[v][u]['capacity'] += path_cp else: RG.add_edge(v,u,capacity=path_cp) else: # then this edge is a "cancelling" flow # residue should go up and cancelling "capacity" should go down G.edge[v][u]['flow'] -= path_cp RG.edge[v][u]['capacity'] += path_cp RG.edge[u][v]['capacity'] -= path_cp if RG.edge[u][v]['capacity'] == 0: RG.remove_edge(u,v) path = isthereapath(RG,s,t) return RG
def layout(self, graph: nx.Graph) -> np.ndarray: """ Use OpenOrd to compute a graph layout Remarks: Requires OpenOrd to be installed and available in the $PATH """ tempdir = tempfile.mkdtemp() # Save the graph in .int format rootfile = os.path.join(tempdir, "graph") with open(rootfile + ".int", 'w') as f: for (x, y, w) in graph.edges_iter(data='weight'): f.write("%d\t%d\t%f\n" % (x, y, w)) try: _ = check_output([ os.path.join(self.openord_path, "layout"), "-c", str(self.edge_cutting), rootfile ]) except CalledProcessError as e: shutil.rmtree(tempdir) raise e # Read back the coordinates with open(rootfile + ".icoord", 'r') as f: coords = np.zeros((graph.number_of_nodes(), 2)) for line in f: items = line.split("\t") node = int(items[0]) coords[node] = (float(items[1]), float(items[2])) shutil.rmtree(tempdir) return coords
def edge_branching(graph: nx.Graph, budget: int): nodes = set(graph.nodes_iter()) num_edges = graph.number_of_edges() if budget <= 0 and num_edges: return False, set() elif num_edges == 0: return True, set() else: # budget > 0 and num_edges > 0 cur_edge = utils.first(graph.edges_iter()) u, v = cur_edge for picked in [u, v]: res, vc = edge_branching(graph.subgraph(nodes - {picked}), budget - 1) if res: return True, vc | {picked} return False, set()
def gen_ind_subsets(graph: nx.Graph): m = graph.number_of_edges() if m == 0: # given graph is already ind. so all subsets are ind. for ss in utils.powerset(graph.nodes_iter()): yield set(ss) # at least one edge in graph u, v = utils.first(graph.edges_iter()) stack = [((u, v), 0, set(), set())] while stack: # print("popped", stack[-1], "remaining", stack[:-1]) cur_edge, state, discard, include = stack.pop() if state > 2: # ignore invalid state continue u, v = cur_edge if state == 0: new_discard = discard | set(graph.neighbors_iter(u)) new_include = include | {u} elif state == 1: new_discard = discard | set(graph.neighbors_iter(v)) new_include = include | {v} else: new_discard = discard | {u, v} new_include = include nodes = set(graph.nodes_iter()) # print("checking subgraph on", nodes - new_discard - new_include) new_graph = graph.subgraph(nodes - new_discard - new_include) # print("found", new_graph.number_of_edges(), "edges") stack.append((cur_edge, state + 1, discard, include)) if new_graph.number_of_edges() == 0: # found ind. set # print("yielding", new_include|new_graph.nodes) for subset in utils.powerset(new_graph.nodes_iter()): yield new_include | set(subset) else: new_edge = utils.first(new_graph.edges_iter()) # print("appending", new_edge) stack.append((new_edge, 0, new_discard, new_include))
def make_steiner_tree(G, voi, generator=None): mst = Graph() for v in voi: if not v in G: raise (ValueError, "make_steiner_tree(): Some vertice not in original graph") if len(voi) == 0: return mst if len(voi) == 1: mst.add_node(voi[0]) return mst # Initially, use (a version of) Kruskal's algorithm to extract a minimal spanning tree # from a weighted graph. This algorithm differs in that only a subset of vertices are # going to be present in the final subgraph (which is not truely a MST - must use Prim's # algorithm later. # extract all shortest paths among the voi heapq = [] paths = {} # load all the paths bwteen the Steiner vertices. Store them in a heap queue # and reconstruct the MST of the complete graph using Kruskal's algorithm for i in range(len(voi) - 1): v1 = voi[i] for v2 in voi[i + 1:]: result = bidirectional_dijkstra(G, v1, v2) if result == False: raise ( RuntimeError, "The two vertices given (%s, %s) don't exist on the same connected graph" % (v1, v2)) #print "The two vertices given (%s, %s) don't exist on the same connected graph" % (v1, v2) distance, vertList = result keys = [v1, v2] keys.sort() key = "%s:%s" % tuple(keys) paths[key] = (vertList) heappush(heapq, (distance, v1, v2)) # construct the minimum spanning tree of the complete graph while heapq: w, v1, v2 = heappop(heapq) # if no path exists yet between v1 and v2, add this one if v1 not in mst or v2 not in mst or not has_path(mst, v1, v2): mst.add_edge(v1, v2, weight=w) # check if the graph is tree and correct sTree = set(mst.nodes()) sSteiner = set(voi) if sTree ^ sSteiner: raise (RuntimeError, 'Failed to construct MST spanning tree') # reconstruct subgraph of origGraph using the paths if generator is None: subgraph = Graph() else: subgraph = generator() for edge in mst.edges_iter(data=True): keys = [edge[0], edge[1]] keys.sort() key = "%s:%s" % tuple(keys) vList = paths[key] for i in range(len(vList) - 1): v1 = vList[i] v2 = vList[i + 1] w = G[v1][v2] subgraph.add_edge(v1, v2, w) # get rid of possible loops - result will be a true MST subgraph = make_prim_mst(subgraph, generator) # remove intermediate nodes in paths that are not in list of voi return _trimTree(subgraph, voi)
def edges_iter(self, nbunch=None): for edge in Graph.edges_iter(self, nbunch, data=True): yield edge
def make_steiner_tree(G, voi, generator=None): mst = Graph() for v in voi: if not v in G: raise ValueError, "make_steiner_tree(): Some vertice not in original graph" if len(voi) == 0: return mst if len(voi) == 1: mst.add_node(voi[0]) return mst # Initially, use (a version of) Kruskal's algorithm to extract a minimal spanning tree # from a weighted graph. This algorithm differs in that only a subset of vertices are # going to be present in the final subgraph (which is not truely a MST - must use Prim's # algorithm later. # extract all shortest paths among the voi heapq = [] paths = {} # load all the paths bwteen the Steiner vertices. Store them in a heap queue # and reconstruct the MST of the complete graph using Kruskal's algorithm for i in range(len(voi) - 1): v1 = voi[i] for v2 in voi[i+1:]: result = bidirectional_dijkstra(G, v1, v2) if result == False: raise RuntimeError, "The two vertices given (%s, %s) don't exist on the same connected graph" % (v1, v2) #print "The two vertices given (%s, %s) don't exist on the same connected graph" % (v1, v2) distance, vertList = result keys = [v1, v2] keys.sort() key = "%s:%s" % tuple(keys) paths[key] = (vertList) heappush(heapq, (distance, v1, v2)) # construct the minimum spanning tree of the complete graph while heapq: w, v1, v2 = heappop(heapq) # if no path exists yet between v1 and v2, add this one if v1 not in mst or v2 not in mst or not has_path(mst, v1, v2): mst.add_edge(v1, v2,weight=w) # check if the graph is tree and correct sTree = set(mst.nodes()) sSteiner = set(voi) if sTree ^ sSteiner: raise RuntimeError, 'Failed to construct MST spanning tree' # reconstruct subgraph of origGraph using the paths if generator is None: subgraph = Graph() else: subgraph = generator() for edge in mst.edges_iter(data=True): keys = [edge[0],edge[1]] keys.sort() key = "%s:%s" % tuple(keys) vList = paths[key] for i in range(len(vList) - 1): v1 = vList[i] v2 = vList[i+1] w = G[v1][v2] subgraph.add_edge(v1, v2, w) # get rid of possible loops - result will be a true MST subgraph = make_prim_mst(subgraph, generator) # remove intermediate nodes in paths that are not in list of voi return _trimTree(subgraph, voi)
class Network(HasTraits): """ The implementation of the Connectome Networks """ implements(INetwork) # Network ID, from parsed GraphML the graphid networkid = '' # Network name networkname = Str # network name as seen in the TreeView name = Str # Is it an hierarchical network? hierarchical = CBool(False) # TODO: later, also Hypergraph?! # see: http://www.ploscompbiol.org/article/info%3Adoi%2F10.1371%2Fjournal.pcbi.1000385 hypergraph = CBool(False) # Directionality of the Network, {True: 'directed', False: 'undirected'} directed = CBool(False) # metadata for the network metadata = Dict # NodeKeys from the parsed GraphML # These are Dict of Dict, all having strings nodekeys = {} # Edgekeys, from parsed GraphML edgekeys = {} # A NetworkX AttrGraph containing all the information graph = Any # Surface containers surfaces = List(ISurfaceContainer) # Surface containers loaded surfaces_loaded = List(ISurfaceContainer) # Volume data volumes = List(IVolume) # Track data tracks = List(ITrackfile) # is this network active, and thus a render manager displayed? active = Bool # the render manager of this network rendermanager = Instance(RenderManager) # DatasourceManager Instance of this network datasourcemanager = Instance(DatasourceManager) # private traits ########### # parent cfile this networks belongs to _parentcfile = Any # filezip of cfile _filezip = DelegatesTo('_parentcfile') # edge parameters for visualization _edge_para = Instance(EdgeParameters) # View traits_view = View( Item('networkname', style = 'readonly'), Item('hierarchical', style = 'simple'), Item('hypergraph', style = 'simple'), Item('directed', style = 'simple'), Item('active', style = 'simple'), title = 'A network', ) def __init__(self, name, src = None, directed = '0', pickled_graph = None, \ hierarchical ='0', hypergraph = '0', graph = None): """ Initializes the network and sets the traits. Parameters ---------- name : string the name of the network src : file handle or StringIO object the source text of the network to parse pickled_graph : NetworkX graph reference to a graph object, src should be None directed : bool Is the network directed? hierarchical : bool Is the network hierarchical? (default: '0') Not implemented yet. hypergraph : bool Is the network a hypergraph? (default: '0') Not implemented yet. """ # initialize the traits self.networkname = name self.directed = int(directed) self.hierarchical = int(hierarchical) self.hypergraph = int(hypergraph) if src is None and not pickled_graph is None: self.load_pickled_graphml(pickled_graph) else: if not src is None: # generates NetworkX Graph self.graph = self.parse_network_graphml(src) elif not graph is None: self.graph = graph else: if self.directed: from networkx import DiGraph self.graph = DiGraph() logger.info("Initialize with empty directed Graph") else: from networkx import Graph self.graph = Graph() logger.info("Initialize with empty undirected Graph") # initializes the weight key of the graph # with the first edgekey if len(self.edgekeys) > 0: edgk = self.edgekeys.keys() if not 'weight' in edgk: self.set_weight_key(edgk[0]) else: # try grabbing first edge from the graph if self.graph.number_of_edges() > 0: it = self.graph.edges_iter(data=True) edg = it.next() if len(edg[2]) > 0: # if it has a weigth key, just leave it edgk = edg[2].keys() if not 'weight' in edgk: self.set_weight_key(edgk[0]) else: pass # logger.error('Cannot set weight key for network : ' + self.networkname) def _name_default(self): return self.networkname def _active_default(self): return False def _active_changed(self , value): if value: n = self.name if ' [Active]' not in n: self.name = "%s [Active]" % n # XXX: do refactor with threaded loading of surfaces # and default spring force layout for graph rendering! # see also TraitsUI Demos: Multi thread demo # load the surface containers data # make a deep copy of the already loaded surface containers import copy self.surfaces = copy.deepcopy(self.surfaces_loaded) for surfcont in self.surfaces: surfcont.load_surface_container() if self.rendermanager is None: self._create_datasourcemanager() self._create_renderer() # if there are no surfaces, initialize # network rendering, but only if dn_positions are given if len(self.surfaces) == 0: logger.debug('No surfaces found. Try to render graph view with dn_position information.') self.rendermanager.datasourcemanager._compute_3DLayout(-1, -1) self.rendermanager.visualize_graph() else: logger.debug('SurfaceContainer found. Try to render 3D View using %s.' % self.surfaces[0].name) if len(self.surfaces[0].surfaces) == 0: logger.debug('Rendering not possible because SurfaceContainer contains no surfaces.') else: logger.debug('Using first surface for rendering.') self.surfaces[0].surfaces[0]._layout_3DView() if not self._parentcfile._workbenchwin is None: #from enthought.pyface.timer.api import do_later from enthought.pyface.api import GUI GUI.invoke_later(self._parentcfile._workbenchwin.status_bar_manager.set, message = '') else: self.name = self.name.replace(' [Active]', '') logger.debug('Close RenderManager scenes') self.rendermanager.close_scenes() logger.debug('All scenes closed.') # FIXME: what is happening in the following? # e.g. for instances. e.g. reset traits? # XXX: this is somehow not correct. do i need to use del # or remove/reset traits? self.rendermanager = None self.datasourcemanager = None self.surfaces = [] def _de_activate(self): """ Toggles the internal state of the activation """ if self.active: self.active = False else: self._parentcfile._workbenchwin.status_bar_manager.message = 'Activating network ...' self.active = True def _edge_parameters(self): """ Dialog to change edge attribute and thresholding """ if self._edge_para is None: self._edge_para = EdgeParameters(self, self.rendermanager.attract.point_scalars_name) self._edge_para.configure_traits() def _create_renderer(self): """ Creates the renderer instance if not yet available and opens the scenes in mayavi """ if self.active: if self.rendermanager is None: logger.debug('Create a RenderManager instance') self.rendermanager = RenderManager(network=self) else: logger.debug('RenderManager instance already running. This is an error.') def _create_datasourcemanager(self): """ Creates the datasource manager instance if not yet available """ if self.active: if self.datasourcemanager is None: logger.debug('Create a DatasourceManager instance') self.datasourcemanager = DatasourceManager(network=self) else: logger.debug('DatasourceManager instance already running. This is an error.') def _render_matrix(self): """ Invokes the connectivity matrix viewer """ # assume the network is activated (i.e. data source generated) # we need the edge parameter instance initialized if self._edge_para is None: self._edge_para = EdgeParameters(self, self.rendermanager.attract.point_scalars_name) logger.debug('Invoke Matrix Viewer...') self.rendermanager.invoke_matrix_viewer() def _trackvis_launch(self): """ Generates scene file and launch Trackvis on the selected nodes """ import tempfile logger.debug('Starting TrackVis ...') # extract selected subgraph selectionlist = self.get_selectiongraph_list() if len(selectionlist) == 0: # message from enthought.traits.ui.message import message message(message = 'No nodes selected for ROI creation!', title = 'Infomessage', buttons = [ 'OK' ], parent = None) tmpgraph = self.graph.subgraph(selectionlist) # extract trackfile temporarily if len(self.tracks) == 0: logger.info('No trackfile found to invoke Trackvis.') return else: # load the first trackfile trackfname = self.tracks[0].load_trackfile_to_file() # find the first valid segmentation volume in the self.volumes list for vol in self.volumes: if vol.segmentation: logger.debug('Found a segmentation volume file. Assume labels are corresponding.') volumefname = vol.load_volume_to_file() break # generate the scene file in the temporary folder tmpscenefile=tempfile.mkstemp(prefix='tmp', suffix='.scene') # generate trackfile generate_scene_file(scenefname=tmpscenefile[1], \ trackfname = trackfname, \ volumefname = volumefname, \ selectiongraph = tmpgraph) # execute trackvis in a thread pref = preference_manager.preferences action = ThreadedTrackvis(tvpath = pref.get('cviewer.plugins.ui.trackvispath'), \ fname = tmpscenefile[1], \ trkfname = trackfname,\ volfname = volumefname) action.start() def add_surface_container(self, surfacecontainer): """ Add a surface container to the loaded list Parameters ---------- surfacecontainer : `ISurfaceContainer` instance a surface container object """ surfacecontainer._networkref = self self.surfaces_loaded.append(surfacecontainer) def add_volume(self, volume): """ Adds a volume to the volumes list Parameters ---------- volume : `IVolume` instance a volume object """ self.volumes.append(volume) def add_trackfile(self, trackfile): """ Adds a trackfile to the tracks list Parameters ---------- trackfile : `ITrackfile` instance a trackfile of type ITrackfile """ self.tracks.append(trackfile) def unselect_all(self): """ Unselects every node in the current network """ if self.datasourcemanager is None: raise Exception('No DatasourceManager. You have to first activate the network and render it.') from numpy import array # get all the nodes graphnodes = self.datasourcemanager._srcobj.relabled_graph.nodes() # and unselect all nodes self.rendermanager._select_nodes(selection_node_array = array(graphnodes)) def select_all(self): """ Selects all nodes in the current network """ if self.datasourcemanager is None: raise Exception('No DatasourceManager. You have to first activate the network and render it.') from numpy import array # get all the nodes graphnodes = self.datasourcemanager._srcobj.relabled_graph.nodes() # and select all nodes self.rendermanager._select_nodes(selection_node_array = array(graphnodes), activate = True) def set_selectiongraph(self, sellist, activate = False): """ Sets the selected nodes in the network to active. Parameters ---------- sellist : array_like a list of nodeids conforming to the NetworkX node id activate : boolean set the selectionlist nodes to activated? """ from numpy import array, int16 graphnodes = self.graph.nodes(data=False) if self.rendermanager is None: raise Exception('No RenderManager. You have to first activate the network and render it.') if len(sellist) == 0: self.unselect_all() return from numpy import array, append tmparr = array([]) for node in sellist: # check if it is a valid graph node id if node in graphnodes: # get the node id as integer j = int(node.lstrip('n'))-1 # extend empty array with node id tmparr = append(tmparr, j) self.rendermanager._select_nodes(selection_node_array = array(tmparr, dtype = int16), activate = activate) def get_selectiongraph_list(self): """ Returns a list of the node ids that were selected in the rendered scene. """ if self.datasourcemanager is None: raise Exception('No DatasourceManager. You have to first activate the network and render it.') import numpy as np sel_list = [] if not self.active: return sel_list selnodesarray = self.datasourcemanager._srcobj.selected_nodes # array with indices where the nodes are selected (==1) idx = np.where(selnodesarray == 1)[0] for i in idx: sel_list.append('n' + str(i + 1)) return sel_list def set_weight_key(self, weight_key = None): """ Sets the weight key in the graph representation of the network. Parameters ---------- weight_key : Str Must be a possible existing edge key """ if not weight_key is None: for u,v,d in self.graph.edges(data=True): self.graph[u][v]['weight']=d[weight_key] return True else: return False def get_matrix(self, weight_key = None): """ Returns the connectivity matrix of the network with the nodes ordered according to their id in the GraphML file. Parameters ---------- weight_key : Str Possible key value of the edges Returns ------- matrix : `Numpy.array` instance The connectivity matrix """ nr_nodes = len(self.graph.nodes()) if not weight_key is None: #FIXME: sanity check if weight_key exists # thanks to Aric Hagberg for u,v,d in self.graph.edges(data=True): self.graph[u][v]['weight']=d[weight_key] nodes = [(lambda nmod:'n'+str(nmod))(node) for node in range(1,nr_nodes + 1)] from networkx import to_numpy_matrix return to_numpy_matrix(self.graph, nodelist = nodes) def toggle_surface(self): """ Toggle the surface for the selected network nodes """ if self.rendermanager is None: raise Exception('No RenderManager. You have to first activate the network and render it.') self.rendermanager._toggle_surface() def show_surface(self): """ Shows the surface for the selected network nodes """ if self.rendermanager is None: raise Exception('No RenderManager. You have to first activate the network and render it.') self.rendermanager._show_surface() def load_pickled_graphml(self, graph): """ Loads a pickled GraphML file Parameters ---------- graph : NetworkX Graph instance A graph instance """ # setting the graph self.graph = graph if self.graph.has_node('n0'): if self.graph.node['n0'].has_key('nodekeys'): # extracting the node keys from the first node self.nodekeys = self.graph.node['n0']['nodekeys'] # extracting the edge keys from the first edge (without explanation) if self.graph.node['n0'].has_key('edgekeys'): self.edgekeys = self.graph.node['n0']['edgekeys'] if self.graph.node['n0'].has_key('graphid'): self.networkid = self.graph.node['n0']['graphid'] # remove node self.graph.remove_node('n0') def _return_default_edgevalue(self, edgekeys, key): """ Looks up if there is a default value defined, otherwise return zero """ if edgekeys[key].has_key('default'): return float(edgekeys[key]['default']) else: return 0.0 def parse_network_graphml(self, path): """ Read network in GraphML format from a path. Parameters ---------- path : string path the the GraphML file Returns ------- graph : NetworkX `Graph` """ import networkx as nx from networkx.utils import _get_fh from lxml import etree # Return a file handle for given path. # Path can be a string or a file handle. # Attempt to uncompress/compress files ending in .gz and .bz2. fh=_get_fh(path,mode='r') tree = etree.parse(fh) # get the root node from parsed lxml root = tree.getroot() # Schema Validation # http://codespeak.net/lxml/validation.html#xmlschema # define the namespace prefixes nsprefix = "{%s}" % root.nsmap[None] nsxlink = "{%s}" % root.nsmap['xlink'] nodekeys = {} edgekeys = {} defaultDirected = [True] # Parse the KEYs for child in root.iterchildren(): if child.tag == (nsprefix+'key'): attribs = child.attrib ddkeys = {} for mchildren in child: if mchildren.tag == (nsprefix+'default'): ddkeys['default'] = mchildren.text elif mchildren.tag == (nsprefix+'desc'): ddkeys['desc'] = mchildren.text if child.attrib['for'] == 'node': # Parse all the node keys # Read in the description and the default (if existing) # dict of dicts for nodes: key1: the id; key2: rest: attr.name, attr.type, desc, default nodekeys[attribs['id']] = {'attr.name' : attribs['attr.name'], \ 'attr.type' : attribs['attr.type']} # add default/desc keys if existing nodekeys[attribs['id']] = ddkeys elif child.attrib['for'] == 'edge': # Parse all the edge keys # Read in the description and the default (if existing) # dict of dicts for edges: key1: the id; key2: rest: attr.name, attr.type, desc, default edgekeys[attribs['id']] = {'attr.name' : attribs['attr.name'], \ 'attr.type' : attribs['attr.type']} # add default/desc keys if existing edgekeys[attribs['id']] = ddkeys else: logger.error("The 'for' attribute of key-tag not known, must be either node or edge") elif child.tag == (nsprefix+'graph'): # start parsing the graph into networkx data structure # create graph depending on (either AttrGraph or AttrDiGraph) # directionality: undirected/directed # version of networkx: # contains self-loops # edges have dicts # data per graph/node/edge for attr, value in child.items(): if attr == 'edgedefault' and value == 'undirected': defaultDirected[0] = False elif attr == 'id': graphid = value if defaultDirected[0]: G = nx.DiGraph() else: G = nx.Graph() # add id, nodekeys and edkeys as traits self.networkid = graphid self.nodekeys = nodekeys self.edgekeys = edgekeys # iterate over all nodes and edges for children in child.iterchildren(): if children.tag == (nsprefix+'node'): # parse the node for attr, value in children.items(): if attr == 'id': # add the node with corresponding id G.add_node(value) # keep node id to store attributes nodeid = value elif attr == (nsxlink+'href'): # add xlink to node dictionary G.node[nodeid]['xlink'] = value else: # node attribute not known logger.warning('The following node attribute is not known and thus discarded:'+ attr + ':' + value) # parse node data, add to node dict for data in children.iterchildren(): # read the keylabel, i.e. the data attribute name keylabel = data.attrib['key'] # is the keylabel in the list of allowed keys if nodekeys.has_key(keylabel): if not data.text == '': # add data to the node's dict G.node[nodeid][keylabel] = data.text else: # no data available, check if default value exists if nodekeys[keylabel].has_key('default'): # add default data to the node's dict G.node[nodeid][keylabel] = nodekeys[keylabel]['default'] logger.debug('Added default value '+ keylabel + ':' + nodekeys[keylabel]['default']) else: logger.warning('Nor data nor default value defined for ' + keylabel) # TODO: Work with exceptions! else: logger.warning("Data entry with key " + keylabel + " not defined.") elif children.tag == (nsprefix+'edge'): # parse the edge # parse its attributes for attr, value in children.items(): if attr == 'id': # no usage of edge id # add the edge with corresponding id src = children.attrib['source'] tar = children.attrib['target'] G.add_edge(src, tar) # keep dest and tar id to store attributes srcid = src tarid = tar elif attr == (nsxlink+'href'): # add xlink to edge dictionary G.edge[srcid][tarid]['xlink'] = value # parse data, and add to the edge dict for data in children.iterchildren(): # read the keylabel, i.e. the data attribute name keylabel = data.attrib['key'] # is the keylabel in the list of allowed keys if self.edgekeys.has_key(keylabel): if not data.text == '': # add data to the edge's dict, assume float!! G.edge[srcid][tarid][keylabel] = float(data.text) else: # no data available, check if default value exists G.edge[srcid][tarid][keylabel] = self._return_default_edgevalue(self.edgekeys, keylabel) data_keys = G.edge[srcid][tarid].keys() # check if we missed some edge keys that are available in the header for k, v in self.edgekeys.items(): if not k in data_keys: G.edge[srcid][tarid][k] = self._return_default_edgevalue(self.edgekeys, k) # return the generated network graph return G
class InteractiveWaypointServer(object): def __init__(self): self.server = InteractiveMarkerServer("interactive_waypoint_server") self.waypoint_graph = Graph() self.next_waypoint_id = 0 self.next_edge_id = 0 self.state = STATE_REGULAR self.connect_first_marker = "" self.edge_line_publisher = rospy.Publisher( "/interactive_waypoint_server/edges", MarkerArray, queue_size=10) self.knowledge_service = rospy.ServiceProxy( "/kcl_rosplan/update_knowledge_base_array", KnowledgeUpdateServiceArray) self.message_store = message_store.MessageStoreProxy() # clear the database entries = self.message_store.query(PoseStamped._type, single=False) for entry in entries: id = entry[1]["_id"] self.message_store.delete(str(id)) def insertMarkerCallback(self, pos): rospy.logdebug( "(Interactive_Waypoint_Server) Inserting new waypoint at position ({0},{1},{2})." .format(pos.point.x, pos.point.y, pos.point.z)) self.insertMarker(pos.point) def clearAllMarkers(self): edges = MarkerArray() marker = Marker() marker.header.stamp = rospy.Time.now() marker.header.frame_id = "map" marker.ns = "waypoint_edges" marker.id = 0 marker.action = Marker.DELETEALL edges.markers.append(marker) self.edge_line_publisher.publish(edges) # clear databases for node, data in self.waypoint_graph.nodes_iter(data=True): self.message_store.delete(data["id"]) self.knowledge_service( update_type=self.knowledge_service.request_class. REMOVE_KNOWLEDGE, knowledge=[ KnowledgeItem(knowledge_type=KnowledgeItem.INSTANCE, instance_type="waypoint", instance_name=node) ]) def _makeMarker(self, msg): marker = Marker() marker.type = Marker.SPHERE marker.scale.x = msg.scale * 0.45 marker.scale.y = msg.scale * 0.45 marker.scale.z = msg.scale * 0.45 marker.color.r = 0 marker.color.g = 1 marker.color.b = 0 marker.color.a = 1.0 return marker def _makeEdge(self, scale, begin, end): marker = Marker() marker.header.frame_id = "map" marker.header.stamp = rospy.Time.now() marker.ns = "waypoint_edges" marker.id = self.next_edge_id self.next_edge_id += 1 marker.type = Marker.LINE_LIST marker.action = Marker.ADD marker.scale.x = scale * 0.45 marker.scale.y = scale * 0.45 marker.scale.z = scale * 0.45 marker.color.r = 0 marker.color.g = 0 marker.color.b = 1 marker.color.a = 1.0 marker.points.append(begin) marker.points.append(end) return marker def _removeMarker(self, name): if self.knowledge_service( update_type=self.knowledge_service.request_class. REMOVE_KNOWLEDGE, knowledge=[ KnowledgeItem(knowledge_type=KnowledgeItem.INSTANCE, instance_type="waypoint", instance_name=name) ]): self._clearMarker(name) # id = self.message_store.insert_named(int_marker.name, pstamped) worked = self.message_store.delete( self.waypoint_graph.node[name]["id"]) self.waypoint_graph.remove_node(name) self.server.erase(name) self.server.applyChanges() else: rospy.logerr( "(Interactive_Waypoint_Server) Failed to remove waypoint {0}. Knowledge database service call returned error." .format(name)) def _clearMarker(self, name): # remove all edges to a waypoint edges = MarkerArray() to_remove = [] for u, v, data in self.waypoint_graph.edges(name, data=True): marker = data["marker"] marker.action = Marker.DELETE to_remove.append((u, v, marker)) # update knowledge database to remove all edges knowledgelist = [] for u, v, marker in to_remove: knowledgelist.extend( self._removeEdgefromKnowledgeBase(u, v, ret_knowledge_only=True)) if self.knowledge_service(update_type=self.knowledge_service. request_class.REMOVE_KNOWLEDGE, knowledge=knowledgelist): for u, v, marker in to_remove: edges.markers.append(marker) self.waypoint_graph.remove_edge(u, v) self.edge_line_publisher.publish(edges) # publish deletion def _addEdgeToKnowledgeBase(self, first, second): firstpos = self.server.get(first).pose.position secondpos = self.server.get(second).pose.position dist = euclidean_distance(firstpos, secondpos) return self.knowledge_service( update_type=self.knowledge_service.request_class.ADD_KNOWLEDGE, knowledge=[ KnowledgeItem( knowledge_type=KnowledgeItem.FACT, # first -> second attribute_name="connected", values=[ KeyValue(key="from", value=first), KeyValue(key="to", value=second) ]), KnowledgeItem( knowledge_type=KnowledgeItem.FACT, # second -> first attribute_name="connected", values=[ KeyValue(key="from", value=second), KeyValue(key="to", value=first) ]), KnowledgeItem( knowledge_type=KnowledgeItem.FUNCTION, # second -> first attribute_name="distance", values=[ KeyValue(key="from", value=first), KeyValue(key="to", value=second) ], function_value=dist), KnowledgeItem( knowledge_type=KnowledgeItem.FUNCTION, # second -> first attribute_name="distance", values=[ KeyValue(key="from", value=second), KeyValue(key="to", value=first) ], function_value=dist) ]) def _removeEdgefromKnowledgeBase(self, first, second, ret_knowledge_only=False): knowledge = [ KnowledgeItem( knowledge_type=KnowledgeItem.FACT, # first -> second attribute_name="connected", values=[ KeyValue(key="from", value=first), KeyValue(key="to", value=second) ]), KnowledgeItem( knowledge_type=KnowledgeItem.FACT, # second -> first attribute_name="connected", values=[ KeyValue(key="from", value=second), KeyValue(key="to", value=first) ]), KnowledgeItem( knowledge_type=KnowledgeItem.FUNCTION, # second -> first attribute_name="distance", values=[ KeyValue(key="from", value=first), KeyValue(key="to", value=second) ], function_value=0), KnowledgeItem( knowledge_type=KnowledgeItem.FUNCTION, # second -> first attribute_name="distance", values=[ KeyValue(key="from", value=second), KeyValue(key="to", value=first) ], function_value=0) ] if ret_knowledge_only: return knowledge else: return self.knowledge_service(update_type=self.knowledge_service. request_class.REMOVE_KNOWLEDGE, knowledge=knowledge) def removeConnectionServiceCall(self, request): first = request.first second = request.second if self.waypoint_graph.has_edge(first, second): self._connectMarkers(first, second) return RemoveConnectionResponse() def _connectMarkers(self, first, second): if self.waypoint_graph.has_edge(first, second): # update knowledge base to remove edge if self._removeEdgefromKnowledgeBase(first, second): # delete edge edges = MarkerArray() marker = self.waypoint_graph.get_edge_data(first, second)["marker"] marker.action = Marker.DELETE edges.markers.append(marker) self.waypoint_graph.remove_edge(first, second) self.edge_line_publisher.publish(edges) # publish deletion else: rospy.logerr( "(Interactive_Waypoint_Server) Failed to remove edge between {0} and {1}. Knowledge database service call returned error." .format(first, second)) else: firstpos = self.server.get(first).pose.position secondpos = self.server.get(second).pose.position # update knowledge base to insert edge if self._addEdgeToKnowledgeBase(first, second): marker = self._makeEdge(0.2, firstpos, secondpos) # insert edge into graph self.waypoint_graph.add_edge(first, second, { "first": first, "marker": marker }) self.updateEdges() else: rospy.logerr( "(Interactive_Waypoint_Server) Failed to insert edge between {0} and {1}. Knowledge database service call returned error." .format(first, second)) def updateEdges(self): edges = MarkerArray() for u, v, data in self.waypoint_graph.edges_iter(data=True): edges.markers.append(data["marker"]) self.edge_line_publisher.publish(edges) def processFeedback(self, feedback): if feedback.event_type == InteractiveMarkerFeedback.MENU_SELECT: handle = feedback.menu_entry_id if handle == MENU_CONNECT: self.state = STATE_CONNECT self.connect_first_marker = feedback.marker_name elif handle == MENU_CLEAR: self._clearMarker(feedback.marker_name) elif handle == MENU_REMOVE: self._removeMarker(feedback.marker_name) elif feedback.event_type == InteractiveMarkerFeedback.MOUSE_UP: if self.state == STATE_CONNECT: self.state = STATE_NONE self._connectMarkers(self.connect_first_marker, feedback.marker_name) elif self.state == STATE_NONE: pass #ignore else: pos = feedback.pose.position rospy.logdebug( "(Interactive_Waypoint_Server) Updateing pose of marker {3} to ({0},{1},{2})" .format(pos.x, pos.y, pos.z, feedback.marker_name)) # update database # push to scene database pstamped = PoseStamped() pstamped.header.frame_id = "map" pstamped.pose = feedback.pose self.message_store.update_named(feedback.marker_name, pstamped) elif feedback.event_type == InteractiveMarkerFeedback.MOUSE_DOWN: if self.state == STATE_NONE: self.state = STATE_REGULAR self.server.applyChanges() def moveFeedback(self, feedback): pose = feedback.pose self.server.setPose(feedback.marker_name, pose) # correct all edges for u, v, data in self.waypoint_graph.edges([feedback.marker_name], data=True): if feedback.marker_name == data["first"]: data["marker"].points[0] = pose.position else: data["marker"].points[1] = pose.position self.updateEdges() self.server.applyChanges() def insertMarker(self, position, name=None, frame_id="map"): if name is None: name = "wp{0}".format(self.next_waypoint_id) self.next_waypoint_id += 1 # update rosplan knowledge base and insert waypoint if successful if self.knowledge_service( update_type=self.knowledge_service.request_class.ADD_KNOWLEDGE, knowledge=[ KnowledgeItem(knowledge_type=KnowledgeItem.INSTANCE, instance_type="waypoint", instance_name=name) ]): int_marker = InteractiveMarker() int_marker.header.frame_id = frame_id int_marker.pose.position = position int_marker.scale = 0.5 int_marker.name = name int_marker.description = "Waypoint: {0}".format(name) # markers a moveable in the plane control = InteractiveMarkerControl() control.orientation.w = 1 control.orientation.x = 0 control.orientation.y = 1 control.orientation.z = 0 control.interaction_mode = InteractiveMarkerControl.MOVE_PLANE menu_handler = MenuHandler() menu_handler.insert("Connect/Disconnect", callback=self.processFeedback) menu_handler.insert("Clear", callback=self.processFeedback) menu_handler.insert("Remove", callback=self.processFeedback) # make a box which also moves in the plane control.markers.append(self._makeMarker(int_marker)) control.always_visible = True int_marker.controls.append(control) # we want to use our special callback function self.server.insert(int_marker, self.processFeedback) menu_handler.apply(self.server, int_marker.name) # set different callback for POSE_UPDATE feedback self.server.setCallback(int_marker.name, self.moveFeedback, InteractiveMarkerFeedback.POSE_UPDATE) self.server.applyChanges() # push to scene database pstamped = PoseStamped() pstamped.header.frame_id = frame_id pstamped.pose = self.server.get(int_marker.name).pose pstamped.pose.orientation.w = 1.0 # otherwise movebase will reject the quaternion id = self.message_store.insert_named(int_marker.name, pstamped) # insert into graph self.waypoint_graph.add_node(int_marker.name, {"id": id}) else: rospy.logerr( "(Interactive_Waypoint_Server) Failed to insert waypoint {0}. Knowledge database service call returned error." .format(name)) def saveWaypointsServicecall(self, request): filename = request.file_name self._saveWaypointsToFile(filename) rospy.loginfo( "(Interactive_Waypoint_Server) Saved waypoints to {0}".format( filename)) return SaveWaypointsResponse() def _saveWaypointsToFile(self, filename): data = {"waypoints": {}, "edges": []} for node in self.waypoint_graph.nodes_iter(): pos = self.server.get(node).pose.position data["waypoints"].update( {node: { "x": pos.x, "y": pos.y, "z": pos.z }}) for u, v in self.waypoint_graph.edges_iter(): data["edges"].append([u, v]) with open(filename, 'w') as f: yaml.dump(data, f, default_flow_style=False) def loadWaypointsFromFile(self, filename): with open(filename, 'r') as f: data = yaml.load(f) for name, pos in data["waypoints"].items(): point = Point(pos["x"], pos["y"], pos["z"]) self.insertMarker(point, name) for edge in data["edges"]: self._connectMarkers(edge[0], edge[1])
class ClusterNetwork(object): def __init__(self, reps): self.g = Graph() self.N = len(reps.keys()) nodes = [] self.lookup = {} self.attributes = None for i, r in enumerate(sorted(reps.keys())): self.lookup[r] = i if self.attributes is None: self.attributes = list(reps[r].attributes.keys()) nodes.append((i, {'rep': reps[r]})) self.g.add_nodes_from(nodes) self.clusters = None def __iter__(self): for i, d in self.g.nodes_iter(data=True): yield d def __len__(self): return self.N def __getitem__(self, key): if isinstance(key, str): return self.g.node[self.lookup[key]] elif isinstance(key, tuple): return self.simMat[key] return self.g.node[key] def cluster(self, scores, cluster_method, oneCluster): #Clear any edges self.g.remove_edges_from(list(self.g.edges_iter(data=False))) if cluster_method is None: return if scores is not None: self.simMat = zeros((self.N, self.N)) for k, v in scores.items(): indOne = self.lookup[k[0]] indTwo = self.lookup[k[1]] self.simMat[indOne, indTwo] = v self.simMat[indTwo, indOne] = v self.simMat = -1 * self.simMat if cluster_method == 'affinity': true_labels = array( [self[i]['rep']._true_label for i in range(self.N)]) self.clusters = affinity_cluster(self.simMat, true_labels, oneCluster) edges = [] for k, v in self.clusters.items(): for v2 in v: if v2[0] == k: continue edges.append((k, v2[0], v2[1])) elif cluster_method == 'complete': edges = [] for i in range(self.N): for j in range(i + 1, self.N): edges.append((i, j, self.simMat[i, j])) self.g.add_weighted_edges_from(edges) seed = RandomState(seed=3) mds = manifold.MDS(n_components=2, max_iter=3000, eps=1e-9, random_state=seed, dissimilarity="precomputed", n_jobs=4) pos = mds.fit(-1 * self.simMat).embedding_ clf = PCA(n_components=2) pos = clf.fit_transform(pos) for i, p in enumerate(pos): self.g.node[i]['pos'] = p def calc_reduction(self): if self.clusters is None: return means = {} reverse_mapping = {} for k, v in self.clusters.items(): s = 0 for ind in v: reverse_mapping[ind[0]] = k s += ind[1] means[k] = s / len(v) for i in self.g.nodes_iter(): clust_center = reverse_mapping[i] if i == clust_center: self.g.node[i]['HyperHypoMeasure'] = 0 continue dist = self.g[i][clust_center]['weight'] norm_dist = abs(dist - means[clust_center]) len_diff = self[clust_center]['representation'].shape[0] - self[i][ 'representation'].shape[0] if len_diff < 0: norm_dist *= -1 self.g.node[i]['HyperHypoMeasure'] = norm_dist if 'HyperHypoMeasure' not in self.attributes: self.attributes.append('HyperHypoMeasure') def get_edges(self): return array(self.g.edges(data=False)) def labels(self): labels = list(range(len(self.g))) for k, v in self.clusters.items(): for v2 in v: labels[v2[0]] = k true_labels = list() for i in range(len(labels)): true_labels.append(self[i]['rep']._true_label) levels = {x: i for i, x in enumerate(set(true_labels))} for i in range(len(true_labels)): true_labels[i] = levels[true_labels[i]] return array(labels), array(true_labels) def silhouette_coefficient(self): labels, true_labels = self.labels() return metrics.silhouette_score(self.simMat, labels, metric='precomputed') def homogeneity(self): labels, true_labels = self.labels() return metrics.homogeneity_score(true_labels, labels) def completeness(self): labels, true_labels = self.labels() return metrics.completeness_score(true_labels, labels) def v_score(self): labels, true_labels = self.labels() return metrics.v_measure_score(true_labels, labels) def adjusted_mutual_information(self): labels, true_labels = self.labels() return metrics.adjusted_mutual_info_score(true_labels, labels) def adjusted_rand_score(self): labels, true_labels = self.labels() return metrics.adjusted_rand_score(true_labels, labels)
def buildJSON_sansfa2(self, graph, coordsRAW=None): inst = CountryConverter("", "", "", "") ISO = inst.getCountries("countries_ISO3166.txt") Alternatives = inst.getCountries("countries_alternatives.txt") inst.createInvertedDicts(ISO, Alternatives) nodesA = 0 nodesB = 0 edgesA = 0 edgesB = 0 edgesAB = 0 # print("printing in buildJSON_sansfa2()") nodes = {} edges = {} if coordsRAW: xy = coordsRAW #For FA2.java: loads(coordsRAW) #print(xy) coords = {} for i in xy: coords[i['sID']] = {} coords[i['sID']]['x'] = i['x'] coords[i['sID']]['y'] = i['y'] #print(coords) for idNode in graph.nodes_iter(): if idNode[0] == "N": #If it is NGram numID = int(idNode.split("::")[1]) # print("DBG terms_array:", self.terms_array) try: nodeLabel = self.terms_array[numID]['term'].replace( "&", " and ") colorg = max(0, 180 - (100 * self.terms_colors[numID])) term_occ = self.terms_array[numID]['occurrences'] except KeyError: print("WARN: couldn't find label and meta for term " + str(numID)) nodeLabel = "UNKNOWN" colorg = 0 term_occ = 1 node = {} node["type"] = "NGram" node["label"] = nodeLabel node["color"] = "19," + str(colorg) + ",244" node["term_occ"] = term_occ if coordsRAW: node["x"] = str(coords[idNode]['x']) if coordsRAW: node["y"] = str(coords[idNode]['y']) nodes[idNode] = node # print("NGR","\t",idNode,"\t",nodeLabel,"\t",term_occ) nodesB += 1 if idNode[0] == 'D': #If it is Document nodeLabel = self.scholars[idNode][ 'title'] + " " + self.scholars[idNode][ 'first_name'] + " " + self.scholars[idNode][ 'initials'] + " " + self.scholars[idNode][ 'last_name'] color = "" if self.scholars_colors[self.scholars[idNode]['login']] == 1: color = '243,183,19' elif self.scholars[idNode]['job_market'] == "Yes": color = '139,28,28' else: color = '78,193,127' content = "" photo_url = self.scholars[idNode]['photo_url'] if photo_url != "": content += '<img src=http://main.csregistry.org/' + photo_url + ' width=' + str( self.imsize) + 'px style=float:left;margin:5px>' else: if len(self.scholars) < 2000: im_id = int(floor(randint(0, 11))) content += '<img src=http://communityexplorer.org/img/' + str( im_id) + '.png width=' + str( self.imsize ) + 'px style=float:left;margin:5px>' content += '<b>Country: </b>' + self.scholars[idNode][ 'country'] + '</br>' if self.scholars[idNode]['position'] != "": content += '<b>Position: </b>' + self.scholars[idNode][ 'position'].replace("&", " and ") + '</br>' affiliation = "" if self.scholars[idNode]['lab'] != "": affiliation += self.scholars[idNode]['lab'] + ',' if self.scholars[idNode]['affiliation'] != "": affiliation += self.scholars[idNode]['affiliation'] if self.scholars[idNode]['affiliation'] != "" or self.scholars[ idNode]['lab'] != "": content += '<b>Affiliation: </b>' + affiliation.replace( "&", " and ") + '</br>' if len(self.scholars[idNode]['keywords']) > 3: content += '<b>Keywords: </b>' + self.scholars[idNode][ 'keywords'][:-2].replace(",", ", ") + '.</br>' if self.scholars[idNode]['homepage'][0:3] == "www": content += '[ <a href=http://' + self.scholars[idNode][ 'homepage'].replace( "&", " and " ) + ' target=blank > View homepage </a ><br/>]' elif self.scholars[idNode]['homepage'][0:4] == "http": content += '[ <a href=' + self.scholars[idNode][ 'homepage'].replace( "&", " and " ) + ' target=blank > View homepage </a >]<br/>' node = {} node["type"] = "Document" node["label"] = nodeLabel node["color"] = color dacountry = self.scholars[idNode]["country"] code = inst.searchCode(dacountry) # country code if code: node["CC"] = code else: node["CC"] = "-" # Affiliation node["ACR"] = self.scholars[idNode]["ACR"] if node["ACR"] == "": node["ACR"] = "-" node["term_occ"] = "12" if coordsRAW: node["x"] = str(coords[idNode]['x']) if coordsRAW: node["y"] = str(coords[idNode]['y']) node["content"] = str(self.toHTML(content)) nodes[idNode] = node # print("SCH","\t",idNode,"\t",nodeLabel) nodesA += 1 GG = Graph() for n in self.Graph.edges_iter(): s = n[0] t = n[1] w = float(self.Graph[n[0]][n[1]]['weight']) tp = self.Graph[n[0]][n[1]]['type'] if GG.has_edge(s, t): oldw = GG[s][t]['weight'] avgw = (oldw + w) / 2 GG[s][t]['weight'] = avgw else: GG.add_edge(s, t, {"weight": w, "type": tp}) e = 0 for n in GG.edges_iter(): #Memory, what's wrong with you? wr = 0.0 origw = GG[n[0]][n[1]]['weight'] for i in range(2, 10): wr = round(origw, i) if wr > 0.0: break edge = {} edge["s"] = n[0] edge["t"] = n[1] edge["w"] = str(wr) # edge["type"] = GG[n[0]][n[1]]['type'] if GG[n[0]][n[1]]['type'] == "nodes1": edgesA += 1 if GG[n[0]][n[1]]['type'] == "nodes2": edgesB += 1 if GG[n[0]][n[1]]['type'] == "bipartite": edgesAB += 1 # print(edge["type"],"\t",nodes[n[0]]["label"],"\t",nodes[n[1]]["label"],"\t",edge["w"]) # if edge["type"]=="nodes1": print(wr) edges[str(e)] = edge e += 1 #if e%1000 == 0: # print(e) # for n in GG.nodes_iter(): # if nodes[n]["type"]=="NGram": # concepto = nodes[n]["label"] # nodes2 = [] # neigh = GG.neighbors(n) # for i in neigh: # if nodes[i]["type"]=="NGram": # nodes2.append(nodes[i]["label"]) # print(concepto,"\t",", ".join(nodes2)) graph = {} graph["nodes"] = nodes graph["links"] = edges graph["stats"] = { "sch": nodesA, "kw": nodesB, "n1": edgesA, "n2": edgesB, "nbi": edgesAB, } graph["ID"] = self.unique_id pprint(graph["stats"]) # print("scholars",nodesA) # print("concepts",nodesB) # print("nodes1",edgesA) # print("nodes2",edgesB) # print("bipartite",edgesAB) return graph