Commit e5e92c94 authored by Yannick Chudy's avatar Yannick Chudy

fix +10 explore

parent c0b5f373
...@@ -22,7 +22,7 @@ def empty_graph(gid, headers, **kwargs): ...@@ -22,7 +22,7 @@ def empty_graph(gid, headers, **kwargs):
botapad.parse_csvrows( headers, separator='auto', debug=False) botapad.parse_csvrows( headers, separator='auto', debug=False)
graph = bot.get_igraph(weight_prop="weight") graph = bot.get_igraph(weight_prop="weight")
graph = prepare_graph(graph) graph = prepare_graph(gid, graph)
graph['starred'] = [] graph['starred'] = []
graph['queries'] = [] graph['queries'] = []
graph['meta'] = { graph['meta'] = {
...@@ -34,7 +34,6 @@ def empty_graph(gid, headers, **kwargs): ...@@ -34,7 +34,6 @@ def empty_graph(gid, headers, **kwargs):
'star_count': len( graph['starred'] ), 'star_count': len( graph['starred'] ),
'stats' : {} 'stats' : {}
} }
#graph['meta']['pedigree'] = pedigree.compute(graph)
return graph return graph
...@@ -72,19 +71,19 @@ def merge(gid, graph, g, index=None, vid=None, **kwargs): ...@@ -72,19 +71,19 @@ def merge(gid, graph, g, index=None, vid=None, **kwargs):
for v in g.vs: for v in g.vs:
_vid = vid(gid,v) _vid = vid(gid,v)
if _vid not in idx: if _vid not in idx:
uuid = "%s" % graph.vcount() uuid = "%s" % graph.vcount()
attrs = v.attributes() attrs = v.attributes()
attrs['uuid'] = uuid attrs['uuid'] = uuid
nodetype = nodetypes[attrs['nodetype']] nodetype = nodetypes[attrs['nodetype']]
properties = nodetype['properties'] properties = nodetype['properties']
for k in properties: for k in properties:
if k not in attrs['properties']: if k not in attrs['properties']:
attrs['properties'][k] = properties[k]['default'] attrs['properties'][k] = properties[k]['default']
graph.add_vertex( **attrs ) graph.add_vertex( **attrs )
idx[ _vid ] = graph.vs[graph.vcount()-1] idx[ _vid ] = graph.vs[graph.vcount()-1]
edgetypes = [ e['name'] for e in graph['edgetypes'] ] edgetypes = [ e['name'] for e in graph['edgetypes'] ]
for k in g['edgetypes']: for k in g['edgetypes']:
...@@ -151,29 +150,93 @@ def graph_stats(graph, **kwargs): ...@@ -151,29 +150,93 @@ def graph_stats(graph, **kwargs):
@Composable @Composable
def prepare_graph(graph): def prepare_graph(gid, graph):
if not 'starred' in graph.attributes():
graph['starred'] = []
if not 'meta' in graph.attributes(): if not 'meta' in graph.attributes():
graph['meta'] = { 'edge_count':0,'node_count':0, } graph['meta'] = {
if 'nodetype' not in graph.vs.attribute_names(): 'node_count': graph.vcount(),
graph.vs['nodetype'] = [ "T" for e in graph.vs ] 'edge_count': graph.ecount(),
if 'uuid' not in graph.vs.attribute_names(): 'owner': "-",
graph.vs['uuid'] = range(len(graph.vs)) 'star_count': len( graph['starred'] ),
if 'properties' not in graph.vs.attribute_names(): 'upvotes': 0,
'votes': 0
}
if 'properties' not in graph.attributes():
graph['properties'] = {}
v_attrs = graph.vs.attribute_names()
if 'nodetypes' not in graph.attributes():
graph['nodetypes'] = [{
"_uniq_key": "_%s_T" % gid,
"uuid": "_%s_T" % gid,
"description": "T",
"name": "T",
'count': graph.vcount(),
"properties": {
k : {
"choices": None,
"default": None,
"encoding": "utf8",
"help": "",
"multi": False,
"type": "Text",
"uniq": False,
"vtype": "unicode"
} for k in v_attrs
}
}]
if 'nodetype' not in v_attrs:
graph.vs['nodetype'] = [ "_%s_T" % gid for e in graph.vs ]
if 'uuid' not in v_attrs:
if 'id' in v_attrs:
graph.vs['uuid'] = [ "%s" % int(e) for e in graph.vs['id'] ]
else :
graph.vs['uuid'] = [ "%s" % e for e in range(len(graph.vs)) ]
if 'properties' not in v_attrs:
props = [ { } for i in range(len(graph.vs))] props = [ { } for i in range(len(graph.vs))]
attrs = graph.vs.attribute_names()
for p,v in zip(props, graph.vs): for p,v in zip(props, graph.vs):
for e in attrs: for e in v_attrs:
if e not in ['nodetype', 'uuid', 'properties' ] : if e not in ( 'nodetype', 'uuid', 'properties' ) :
p[e] = v[e] p[e] = v[e]
if 'label' not in attrs: if 'label' not in v_attrs:
p['label'] = v.index p['label'] = v.index
graph.vs['properties'] = props graph.vs['properties'] = props
for k in v_attrs:
if k not in ( 'nodetype', 'uuid', 'properties' ) :
del graph.vs[k]
e_attrs = graph.es.attribute_names()
{"choices": None, "default": None, "encoding": "utf8", "help": "", "multi": False, "type": "Text", "uniq": False, "vtype": "unicode" }
if 'edgetypes' not in graph.attributes():
graph['edgetypes'] = [{
'count': graph.ecount(),
'description': "E",
'name': "E",
'properties': {
'label': {"choices": None, "default": None, "encoding": "utf8", "help": "",
"multi": False, "type": "Text", "uniq": False, "vtype": "unicode" },
'weight': {"choices": None, "default": None, "encoding": "utf8", "help": "",
"multi": False, "type": "Numeric", "uniq": False, "vtype": "float" }
},
'type_attributes' : {},
'uuid' : "_%s_E" % gid,
'_uniq_key' : "_%s_E" % gid,
} ]
if 'edgetype' not in graph.es.attribute_names(): if 'edgetype' not in graph.es.attribute_names():
graph.es['edgetype'] = [ "T" for e in graph.es ] graph.es['edgetype'] = [ "_%s_E" % gid for e in graph.es ]
if 'uuid' not in graph.es.attribute_names(): if 'uuid' not in graph.es.attribute_names():
graph.es['uuid'] = range(len(graph.es)) graph.es['uuid'] = range(len(graph.es))
if 'properties' not in graph.es.attribute_names(): if 'properties' not in graph.es.attribute_names():
...@@ -181,13 +244,16 @@ def prepare_graph(graph): ...@@ -181,13 +244,16 @@ def prepare_graph(graph):
attrs = graph.es.attribute_names() attrs = graph.es.attribute_names()
for p,v in zip(props, graph.es): for p,v in zip(props, graph.es):
for e in attrs: for e in e_attrs:
if e not in ['edgetype', 'uuid', 'properties' ] : if e not in ['edgetype', 'uuid', 'properties' ]:
p[e] = v[e] p[e] = v[e]
if 'label' not in attrs: if 'label' not in e_attrs:
p['label'] = v.index p['label'] = v.index
graph.es['properties'] = props graph.es['properties'] = props
for k in e_attrs:
if k not in ( 'edgetype', 'uuid', 'properties', 'weight' ) :
del graph.es[k]
if 'weight' not in graph.es.attribute_names(): if 'weight' not in graph.es.attribute_names():
graph.es['weight'] = [1. for e in graph.es ] graph.es['weight'] = [1. for e in graph.es ]
...@@ -263,4 +329,4 @@ def igraph2dict(graph, exclude_gattrs=[], exclude_vattrs=[], exclude_eattrs=[], ...@@ -263,4 +329,4 @@ def igraph2dict(graph, exclude_gattrs=[], exclude_vattrs=[], exclude_eattrs=[],
def export_graph(graph, exclude_gattrs=[], exclude_vattrs=[], exclude_eattrs=[], id_attribute=None): def export_graph(graph, exclude_gattrs=[], exclude_vattrs=[], exclude_eattrs=[], id_attribute=None):
return igraph2dict(graph, exclude_gattrs, exclude_vattrs, exclude_eattrs, id_attribute) return igraph2dict(graph, exclude_gattrs, exclude_vattrs, exclude_eattrs, id_attribute)
\ No newline at end of file
...@@ -5,6 +5,7 @@ from flask import request, jsonify ...@@ -5,6 +5,7 @@ from flask import request, jsonify
from flask import Response, make_response from flask import Response, make_response
import igraph import igraph
from igraph.utils import named_temporary_file
import pickle import pickle
import json import json
...@@ -23,7 +24,7 @@ from cello.clustering import export_clustering ...@@ -23,7 +24,7 @@ from cello.clustering import export_clustering
from pdgapi.explor import ComplexQuery, AdditiveNodes, NodeExpandQuery, layout_api, clustering_api from pdgapi.explor import ComplexQuery, AdditiveNodes, NodeExpandQuery, layout_api, clustering_api
from botapad.utils import export_graph from botapad.utils import export_graph, prepare_graph
from botapad import Botapad, BotapadError, BotapadParseError, BotapadURLError, BotapadCsvError, BotapadPostError from botapad import Botapad, BotapadError, BotapadParseError, BotapadURLError, BotapadCsvError, BotapadPostError
from botapi import BotApiError, Botagraph, BotaIgraph, BotLoginError from botapi import BotApiError, Botagraph, BotaIgraph, BotLoginError
...@@ -40,9 +41,9 @@ def pad2pdg(gid, url, host, key, delete, debug=False): ...@@ -40,9 +41,9 @@ def pad2pdg(gid, url, host, key, delete, debug=False):
botapad = Botapad(bot, gid, description, delete=delete) botapad = Botapad(bot, gid, description, delete=delete)
return botapad.parse(url, separator='auto', debug=debug) return botapad.parse(url, separator='auto', debug=debug)
AVAILABLE_FORMATS = ('pickle', 'graphml', 'graphmlz', 'gml', 'pajek')
def pad2igraph(gid, url, format, delete=False, debug=False, store="/pads/"): def pad2igraph(gid, url, format, delete=False, store="/pads/", debug=True):
print ("format", gid, url, format ) print ("format", gid, url, format )
...@@ -60,7 +61,7 @@ def pad2igraph(gid, url, format, delete=False, debug=False, store="/pads/"): ...@@ -60,7 +61,7 @@ def pad2igraph(gid, url, format, delete=False, debug=False, store="/pads/"):
if graph.vcount() == 0 : if graph.vcount() == 0 :
raise BotapadParseError(url, "Botapad can't create a graph without nodes.", None ) raise BotapadParseError(url, "Botapad can't create a graph without nodes.", None )
return graph return prepare_graph(gid, graph)
except BotapadParseError as e : except BotapadParseError as e :
log = botapad.get_log() log = botapad.get_log()
...@@ -72,38 +73,38 @@ def pad2igraph(gid, url, format, delete=False, debug=False, store="/pads/"): ...@@ -72,38 +73,38 @@ def pad2igraph(gid, url, format, delete=False, debug=False, store="/pads/"):
elif format in ('pickle', 'graphml', 'graphmlz', 'gml', 'pajek'): elif format in AVAILABLE_FORMATS:
content = None content = None
if url[0:4] == 'http': if url[0:4] == 'http':
try : try :
url = convert_url(path) url = convert_url(path)
if format in ( 'pickle', 'picklez'): if format in ( 'pickle', 'picklez'):
raise ValueError('no pickle from HTTP : %s ' % url ) raise ValueError('no pickle from HTTP : %s ' % url )
log( " * Downloading %s %s\n" % (url, separator)) print( " === Downloading %s %s\n" % (url, separator))
content = requests.get(url).text content = requests.get(url).text
except : except :
raise BotapadURLError("Can't download %s" % url, url) raise BotapadURLError("Can't download %s" % url, url)
elif DEBUG : else :
try : try :
content = open("%s/%s.%s" % (LOCAL_PADS_STORE, url, format) , 'rb').read() print (" === reading %s/%s.%s" % (store, url, format) )
content = open("%s/%s.%s" % (store, url, format) , 'r').read()
except Exception as err : except Exception as err :
raise BotapadURLError("Can't open file %s: %s" % (url, err.message ), url) raise BotapadURLError("Can't open file %s: %s" % (url, err), url)
print (" === reading %s/%s.%s" % (LOCAL_PADS_STORE, url, format) )
try : try :
with named_temporary_file(text=False) as tmpf: with named_temporary_file(text=False) as tmpf:
outf = open(tmpf, "wt") outf = open(tmpf, "wt")
outf.write(content) outf.write(content)
outf.close() outf.close()
graph = igraph.read(tmpf, format=format) graph = igraph.read(tmpf, format=format)
return graph return prepare_graph(gid, graph)
except Exception as err : except Exception as err :
raise BotapadError('%s : cannot read %s file at %s : %s' % ( gid, format, url, err.message )) raise
raise BotapadError('%s : cannot read %s file at %s : %s' % ( gid, format, url, err))
else : else :
raise BotapadError('%s : Unsupported format %s file at %s ' % ( gid, format, url )) raise BotapadError('%s : Unsupported format %s file at %s ' % ( gid, format, url ))
...@@ -146,7 +147,7 @@ def explore_engine(graphdb): ...@@ -146,7 +147,7 @@ def explore_engine(graphdb):
return db_graph(graphdb, query) return db_graph(graphdb, query)
@Composable @Composable
def subgraph(query, cut=100, weighted=True, length=7, mode=ALL, add_loops=False, ): def subgraph(query, cut=100, weighted=True, length=7, mode=ALL, add_loops=False, **kwargs ):
graph = db_graph(graphdb, query) graph = db_graph(graphdb, query)
...@@ -166,6 +167,17 @@ def explore_engine(graphdb): ...@@ -166,6 +167,17 @@ def explore_engine(graphdb):
return graph.subgraph(vs) return graph.subgraph(vs)
@Composable
def filtering(graph, single_filtered=False, **kwargs):
if single_filtered :
to_del = []
for v in graph.vs:
if not len(v.neighbors()):
to_del.add(v.index)
graph.vs.delete(to_del)
return graph
from cello.graphs.transform import VtxAttr from cello.graphs.transform import VtxAttr
searchs = [] searchs = []
...@@ -211,7 +223,7 @@ def expand_prox_engine(graphdb): ...@@ -211,7 +223,7 @@ def expand_prox_engine(graphdb):
engine.scores.setup(in_name="request", out_name="scores") engine.scores.setup(in_name="request", out_name="scores")
## Search ## Search
def expand(query, length=3, cut=100, nodes=False, weightings=None): def expand(query, length=3, cut=300, nodes=False, weightings=None):
graph = db_graph(graphdb, query) graph = db_graph(graphdb, query)
gid = query.get("graph") gid = query.get("graph")
...@@ -223,17 +235,19 @@ def expand_prox_engine(graphdb): ...@@ -223,17 +235,19 @@ def expand_prox_engine(graphdb):
pz.update( { uuids[p] : 1./len(_nodes) for p in qnodes } ) pz.update( { uuids[p] : 1./len(_nodes) for p in qnodes } )
pz.update( { uuids[p] : 1. for p in qexpand }) pz.update( { uuids[p] : 1. for p in qexpand })
weightings = ["1"] if weightings == None else weightings print( "expand >>> %s" % pz )
weightings = ["1"] if weightings in ([], None) else weightings
wneighbors = _weights(weightings) wneighbors = _weights(weightings)
vs = pure_prox(graph, pz, length, wneighbors) vs = pure_prox(graph, pz, length, wneighbors)
vs = sortcut(vs, cut) vs = sortcut(vs, cut)
vs = [ (graph.vs[v[0]]['uuid'], v[1]) for v in vs ]
return dict(vs) return dict(vs)
scores = Optionable("scores") scores = Optionable("scores")
scores._func = Composable(expand) scores._func = Composable(expand)
scores.add_option("length", Numeric( vtype=int, default=3)) scores.add_option("length", Numeric( vtype=int, default=3))
scores.add_option("cut", Numeric( vtype=int, default=50, max=100)) scores.add_option("cut", Numeric( vtype=int, default=50, max=300))
scores.add_option("nodes", Boolean( default=True)) scores.add_option("nodes", Boolean( default=True))
scores.add_option("weighting", Text(choices=[ u"0", u"1", u"weight" ], multi=True, default=u"1", help="ponderation")) scores.add_option("weighting", Text(choices=[ u"0", u"1", u"weight" ], multi=True, default=u"1", help="ponderation"))
......
...@@ -58,7 +58,7 @@ except: ...@@ -58,7 +58,7 @@ except:
# delete before import # delete before import
# app # app
print( " == Botapad %s %s ==" % ("DEBUG" if DEBUG else "", "DELETE" if DELETE else "") ) print( " == Botapad %s %s ==" % ("DEBUG" if DEBUG else "INFO", "DELETE" if DELETE else "") )
print( " == Running with gunicorn : %s==" % (RUN_GUNICORN) ) print( " == Running with gunicorn : %s==" % (RUN_GUNICORN) )
print( " == engines:%s static:%s padagraph:%s==" % (ENGINES_HOST, STATIC_HOST, PADAGRAPH_HOST) ) print( " == engines:%s static:%s padagraph:%s==" % (ENGINES_HOST, STATIC_HOST, PADAGRAPH_HOST) )
print( " == REDIS STORAGE : %s == " % REDIS_STORAGE ) print( " == REDIS STORAGE : %s == " % REDIS_STORAGE )
...@@ -375,10 +375,21 @@ from reliure.pipeline import Optionable, Composable ...@@ -375,10 +375,21 @@ from reliure.pipeline import Optionable, Composable
@Composable @Composable
def _pad2igraph(gid, url, format="csv"): def _pad2igraph(gid, url, format="csv"):
graph = pad2igraph(gid, url, format, delete=True,debug=DEBUG, store=LOCAL_PADS_STORE) graph = pad2igraph(gid, url, format, delete=True, store=LOCAL_PADS_STORE)
if not 'meta' in graph.attributes() : graph['meta'] = {}
graph['meta']['gid'] = gid
graph['meta']['graph'] = gid
graph['properties']= {
"description": "%s imported from %s [%s]" % (gid, url, format) ,
"image": "",
"name": gid,
"tags": [
"Botapad", format
]
}
graph['meta']['owner'] = None graph['meta']['owner'] = None
graph['meta']['date'] = datetime.datetime.now().strftime("%Y-%m-%d %Hh%M") graph['meta']['date'] = datetime.datetime.now().strftime("%Y-%m-%d %Hh%M")
return graph return prepare_graph(gid, graph)
import traceback import traceback
...@@ -479,7 +490,7 @@ def botimport(repo, padurl, gid, content_type): ...@@ -479,7 +490,7 @@ def botimport(repo, padurl, gid, content_type):
else : else :
builder = _pad2igraph | prepare_graph | compute_pedigree | graph_stats builder = _pad2igraph | compute_pedigree | graph_stats
graph = builder( gid, padurl, reader ) graph = builder( gid, padurl, reader )
graphdb.set_graph(gid, graph) graphdb.set_graph(gid, graph)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment