Changeset 7853:aefc3f7ef085 in orange


Ignore:
Timestamp:
04/18/11 09:19:32 (3 years ago)
Author:
matija <matija.polajnar@…>
Branch:
default
Convert:
40ccbc41099ce9ed3b970083cc8341db5f877724
Message:

Orange.network: improve buggy networkx's Pajek support, add support for Pajek projects (sets of networks).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • orange/Orange/network/readwrite.py

    r7843 r7853  
    1 import network 
     1import networkx as nx 
    22import networkx.readwrite as rw 
     3from networkx.utils import _get_fh 
    34import warnings 
     5import itertools 
     6import Orange.network 
    47 
    58__all__ = ['generate_pajek', 'write_pajek', 'read_pajek', 'parse_pajek'] 
    69 
    7 try: 
    8     generate_pajek = rw.generate_pajek 
    9 except: 
    10     warnings.warn("Warning: your version of networkx does not contain the "+ 
    11                   "generate_pajek method; you may encounter problems when "+ 
    12                   "using the Orange.network module.") 
    13      
    1410write_pajek = rw.write_pajek 
    1511 
     12def _wrap(g): 
     13    for base, new in [(nx.DiGraph, Orange.network.DiGraph), 
     14                      (nx.MultiGraph, Orange.network.MultiGraph), 
     15                      (nx.MultiDiGraph, Orange.network.MultiDiGraph), 
     16                      (nx.Graph, Orange.network.Graph)]: 
     17        if isinstance(g, base): 
     18            return g if isinstance(g, new) else new(g, name=g.name) 
     19    return g 
     20 
    1621def read_pajek(path,encoding='UTF-8'): 
    17     return rw.read_pajek(path, encoding) 
     22    """ 
     23    A copy&paste of networkx's function. Calls the local parse_pajek(). 
     24    """ 
     25    fh=_get_fh(path, 'rb') 
     26    lines = (line.decode(encoding) for line in fh) 
     27    return parse_pajek(lines) 
    1828 
    1929def parse_pajek(lines): 
    20     G = rw.parse_pajek(lines) 
    21      
     30    """ 
     31    A copy&paste of networkx's function with some bugs fixed: 
     32      - make it a Graph or DiGraph if there is no reason to have a Multi*, 
     33      - do not lose graph's name during its conversion. 
     34    """ 
     35    import shlex 
     36    from networkx.utils import is_string_like 
     37    multigraph=False 
     38    if is_string_like(lines): lines=iter(lines.split('\n')) 
     39    lines = iter([line.rstrip('\n') for line in lines]) 
     40    G=nx.MultiDiGraph() # are multiedges allowed in Pajek? assume yes 
     41    directed=True # assume this is a directed network for now 
     42    while lines: 
     43        try: 
     44            l=next(lines) 
     45        except: #EOF 
     46            break 
     47        if l.lower().startswith("*network"): 
     48            label,name=l.split(None, 1) 
     49            G.name=name 
     50        if l.lower().startswith("*vertices"): 
     51            nodelabels={} 
     52            l,nnodes=l.split() 
     53            for i in range(int(nnodes)): 
     54                splitline=shlex.split(str(next(lines))) 
     55                id,label=splitline[0:2] 
     56                G.add_node(label) 
     57                nodelabels[id]=label 
     58                G.node[label]={'id':id} 
     59                try:  
     60                    x,y,shape=splitline[2:5] 
     61                    G.node[label].update({'x':float(x), 
     62                                          'y':float(y), 
     63                                          'shape':shape}) 
     64                except: 
     65                    pass 
     66                extra_attr=zip(splitline[5::2],splitline[6::2]) 
     67                G.node[label].update(extra_attr) 
     68        if l.lower().startswith("*edges") or l.lower().startswith("*arcs"): 
     69            if l.lower().startswith("*edge"): 
     70               # switch from multi digraph to multi graph 
     71                G=nx.MultiGraph(G, name=G.name) 
     72            for l in lines: 
     73                splitline=shlex.split(str(l)) 
     74                ui,vi=splitline[0:2] 
     75                u=nodelabels.get(ui,ui) 
     76                v=nodelabels.get(vi,vi) 
     77                # parse the data attached to this edge and put in a dictionary  
     78                edge_data={} 
     79                try: 
     80                    # there should always be a single value on the edge? 
     81                    w=splitline[2:3] 
     82                    edge_data.update({'weight':float(w[0])}) 
     83                except: 
     84                    pass 
     85                    # if there isn't, just assign a 1 
     86#                    edge_data.update({'value':1}) 
     87                extra_attr=zip(splitline[3::2],splitline[4::2]) 
     88                edge_data.update(extra_attr) 
     89                if G.has_edge(u,v): 
     90                    multigraph=True 
     91                G.add_edge(u,v,**edge_data) 
     92 
     93    if not multigraph: # use Graph/DiGraph if no parallel edges 
     94        if G.is_directed(): 
     95            G=nx.DiGraph(G, name=G.name) 
     96        else: 
     97            G=nx.Graph(G, name=G.name) 
     98    return _wrap(G) 
     99 
     100def generate_pajek(G): 
     101    """ 
     102    A copy&paste of networkx's function with some bugs fixed: 
     103     - generate one line per object (vertex, edge, arc); do not add one per 
     104       entry in data dictionary. 
     105    """ 
     106    from networkx.utils import make_str, is_string_like 
     107 
     108    if G.name=='':  
     109        name='NetworkX' 
     110    else: 
     111        name=G.name 
     112    yield '*network %s'%name 
     113 
     114    # write nodes with attributes 
     115    yield '*vertices %s'%(G.order()) 
     116    nodes = G.nodes() 
     117    # make dictionary mapping nodes to integers 
     118    nodenumber=dict(zip(nodes,range(1,len(nodes)+1)))  
     119    for n in nodes: 
     120        na=G.node.get(n,{}) 
     121        x=na.get('x',0.0) 
     122        y=na.get('y',0.0) 
     123        id=int(na.get('id',nodenumber[n])) 
     124        nodenumber[n]=id 
     125        shape=na.get('shape','ellipse') 
     126        s = ' '.join(map(make_str,(id,n,x,y,shape))) 
     127        for k,v in na.items(): 
     128            s += ' %s %s'%(k,v) 
     129        yield s 
     130 
     131    # write edges with attributes          
    22132    if G.is_directed(): 
    23         G = network.DiGraph(G) 
     133        yield '*arcs' 
    24134    else: 
    25         G = network.Graph(G) 
     135        yield '*edges' 
     136    for u,v,edgedata in G.edges(data=True): 
     137        d=edgedata.copy() 
     138        value=d.pop('weight',1.0) # use 1 as default edge value 
     139        s = ' '.join(map(make_str,(nodenumber[u],nodenumber[v],value))) 
     140        for k,v in d.items(): 
     141            if is_string_like(v): 
     142                # add quotes to any values with a blank space 
     143                if " " in v:  
     144                    v="\"%s\""%v 
     145            s += ' %s %s'%(k,v) 
     146        yield s 
    26147         
    27     return G 
     148def write_pajek(G, path, encoding='UTF-8'): 
     149    """ 
     150    A copy&paste of networkx's function with some bugs fixed: 
     151     - call the new generate_pajek. 
     152    """ 
     153    fh=_get_fh(path, 'wb') 
     154    for line in generate_pajek(G): 
     155        line+='\n' 
     156        fh.write(line.encode(encoding)) 
     157 
     158def parse_pajek_project(lines): 
     159    network_lines = [] 
     160    result = [] 
     161    for i, line in enumerate(itertools.chain(lines, ["*"])): 
     162        line_low = line.strip().lower() 
     163        if not line_low: 
     164            continue 
     165        if line_low[0] == "*" and not any(line_low.startswith(x) 
     166                                          for x in ["*vertices", "*arcs", "*edges"]): 
     167            if network_lines != []: 
     168                result.append(parse_pajek(network_lines)) 
     169                network_lines = [] 
     170        if line_low.startswith("*network") or network_lines != []: 
     171            network_lines.append(line) 
     172    return result 
     173 
     174def read_pajek_project(path, encoding='UTF-8'): 
     175    fh = _get_fh(path, 'rb') 
     176    lines = (line.decode(encoding) for line in fh) 
     177    return parse_pajek_project(lines) 
    28178 
    29179read_pajek.__doc__ = rw.read_pajek.__doc__ 
Note: See TracChangeset for help on using the changeset viewer.