Last active
August 30, 2022 02:53
-
-
Save pebbie/5aafdbb14921cadbad53011ef5f61165 to your computer and use it in GitHub Desktop.
visualize BGP triples in SPARQL query
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import os.path as path | |
from rdflib import Namespace, XSD, RDF, RDFS, OWL | |
from rdflib.term import Variable, URIRef, BNode, Literal | |
from rdflib.plugins.sparql.parser import parseQuery | |
from rdflib.plugins.sparql.parserutils import prettify_parsetree | |
from rdflib.plugins.sparql import prepareQuery | |
from rdflib.paths import Path | |
import pprint | |
import pygraphviz as pgv | |
import argparse | |
BLANKNODES = [] | |
def get_values(alg, vals): | |
for obj in alg: | |
k = list(obj.keys())[0] | |
v = obj[k] | |
lname = str(k) | |
if lname in vals: | |
vals[lname].append(v) | |
else: | |
vals[lname] = [v] | |
def find_triples(alg, vals): | |
# TODO: parse based on name attribute of the current parse tree node (alg) | |
# print(type(alg)) | |
result = [] | |
if isinstance(alg, list): | |
akg = alg | |
else: | |
akg = [alg] | |
for al in akg: | |
# pprint.pprint(al) | |
if hasattr(al, 'name'): | |
# print(al.name) | |
# pprint.pprint(al) | |
pass | |
ak = dict(al).keys() | |
for key in ak: | |
if key in ['PV', 'var', '_vars', 'datasetClause', 'expr', 'op', 'A', 'lazy', 'service_string']: | |
continue | |
elif key == 'res' and isinstance(al[key], list): | |
# values() | |
get_values(al[key], vals) | |
continue | |
elif key == 'value': | |
# pprint.pprint(al) | |
# print(al[key]) | |
for var in al['var']: | |
vals[str(var)] = [] | |
for value in al[key]: | |
if isinstance(value, list): | |
for var in al['var']: | |
tmpval = value.pop(0) | |
vals[str(var)].append(tmpval) | |
else: | |
vals[str(var)].append(value) | |
continue | |
elif key == 'term': | |
#print(type(al), al.name) | |
# print(al) | |
continue | |
elif key == 'triples': | |
# yield alg.triples | |
result += [al.triples] | |
continue | |
#print(f'opening {key}') | |
result += find_triples(al[key], vals) | |
return result | |
def get_prefix(NS, uri): | |
for k, v in sorted(NS.items(), key=lambda x: len(x[1]), reverse=True): | |
if uri.startswith(str(v)): | |
return k | |
return None | |
def get_local_name(NS, uri): | |
pref = get_prefix(NS, uri) | |
return pref+':'+str(uri).replace(NS[pref], '') if pref is not None else str(uri) | |
def get_label(NS, term): | |
tname = str(term) | |
if isinstance(term, Variable): | |
tname = '?' + tname | |
elif isinstance(term, URIRef): | |
tname = get_local_name(NS, term) | |
elif isinstance(term, BNode): | |
if tname not in BLANKNODES: | |
BLANKNODES.append(tname) | |
tname = '_:bn' + str(BLANKNODES.index(tname)+1) | |
elif isinstance(term, Path): | |
# print(term.n3()) | |
if hasattr(term, 'arg'): | |
aname = get_local_name(NS, str(term.arg)) | |
tname = tname.replace(str(term.arg), aname) | |
elif hasattr(term, 'args'): | |
for arg in term.args: | |
tname = tname.replace(str(arg), get_local_name(NS, arg)) | |
elif hasattr(term, 'path'): | |
aname = get_local_name(NS, str(term.path)) | |
tname = tname.replace(str(term.path), aname) | |
tname = tname[5:-1] | |
return tname | |
def set_node_attr(viz, term, termlabel): | |
n = viz.get_node(termlabel) | |
if isinstance(term, Variable): | |
n.attr['style'] = 'dashed' | |
elif isinstance(term, BNode): | |
n.attr['style'] = 'dotted' | |
elif isinstance(term, Literal): | |
n.attr['shape'] = 'box' | |
return n | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser.add_argument( | |
'-infile', help="text file containing SPARQL query (.rq)", required=True) | |
parser.add_argument( | |
'-outfile', help="image file containing the visualized BGP (.png)") | |
parser.add_argument( | |
'-dot', action='store_true', | |
help="when set, additionally create the dot file") | |
parser.add_argument( | |
'-ns', nargs='*', | |
help="namespace prefix definition in the format of <prefix>=<prefixURI> or a filename of a text file containing this format for each line", | |
default=[]) | |
parser.add_argument( | |
'-verbose', action='store_true', | |
help="print out intemediate debug info") | |
parser.add_argument( | |
'-layout', help="layout prog to pass on graphviz", | |
default='dot', | |
choices=['dot', 'neato', 'circo', 'fdp', 'sfdp', 'twopi']) | |
parser.add_argument( | |
'-colorscheme', default='accent8', | |
help="default graphviz color scheme" | |
) | |
args = parser.parse_args() | |
if not path.exists(args.infile): | |
print(f"{args.infile} does not exists. exiting..") | |
sys.exit(1) | |
if args.outfile is None: | |
base, ext = path.splitext(args.infile) | |
args.outfile = base + '.png' | |
print(f"opening {args.infile}...") | |
with open(args.infile) as fq: | |
q = fq.read() | |
NS = {"rdf": str(RDF), "rdfs": str( | |
RDFS), "owl": str(OWL), "xsd": str(XSD)} | |
for nsdef in args.ns: | |
if path.exists(nsdef): | |
with open(nsdef) as fns: | |
for line in fns: | |
if line.startswith('#'): | |
# ignore comment | |
continue | |
prefix, nsURI = tuple(line.strip().split('=')) | |
if prefix not in NS: | |
NS[prefix] = nsURI | |
else: | |
prefix, nsURI = tuple(nsdef.strip().split('=')) | |
if prefix not in NS: | |
NS[prefix] = nsURI | |
pq = prepareQuery( | |
q, initNs=NS) | |
# pprint.pprint(pq.algebra) | |
# print(prettify_parsetree(pq.algebra)) | |
for prefix, nsURI in [n for n in pq.prologue.namespace_manager.namespaces()]: | |
if prefix not in NS: | |
NS[prefix] = str(nsURI) | |
if args.verbose: | |
pprint.pprint(pq.algebra) | |
G = pgv.AGraph(directed=True) | |
G.node_attr.update(colorscheme=args.colorscheme) | |
G.edge_attr.update(colorscheme=args.colorscheme) | |
values = {} | |
tris = find_triples(pq.algebra, values) | |
# pprint.pprint(tris) | |
# exit() | |
if tris is not None: | |
for gid, trisgrp in enumerate(tris): | |
for s, p, o in trisgrp: | |
if args.verbose: | |
print(repr(s), repr(p), repr(o)) | |
if not isinstance(p, URIRef): | |
print(type(p)) | |
# get term labels | |
sname = get_label(NS, s) | |
pname = get_label(NS, p) | |
oname = get_label(NS, o) | |
# add triple | |
G.add_edge(sname, oname) | |
# customize edge attribute | |
edge = G.get_edge(sname, oname) | |
if 'color' not in dict(edge.attr).keys(): | |
edge.attr['color'] = gid+1 | |
edge.attr['label'] = pname | |
if isinstance(p, Variable): | |
edge.attr['style'] = 'dashed' | |
# customize node attribute | |
snode = set_node_attr(G, s, sname) | |
onode = set_node_attr(G, o, oname) | |
#print(sname, oname, gid+1) | |
if 'color' not in dict(snode.attr).keys(): | |
snode.attr['color'] = gid+1 | |
if 'color' not in dict(onode.attr): | |
onode.attr['color'] = gid+1 | |
if len(values.keys()) > 0: | |
for var in values: | |
lname = str(var) | |
varname = '?' + lname | |
for value in values[lname]: | |
valname = get_label(NS, value) | |
G.add_edge(valname, varname) | |
edge = G.get_edge(valname, varname) | |
node = G.get_node(valname) | |
node.attr['shape'] = 'box' | |
edge.attr['style'] = 'dashed' | |
edge.attr['dir'] = 'none' | |
G.layout(prog=args.layout) | |
if args.dot: | |
base, ext = path.splitext(args.outfile) | |
dotfile = base + '.dot' | |
G.write(dotfile) | |
print(f"writing {dotfile}...") | |
print(f"writing {args.outfile}...") | |
G.draw(args.outfile) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Dear Peb Ruswono Aryan,
We have completed the review phase of ISWC 2020 Posters and Demos Track. On behalf of the ISWC 2020 Posters and Demos Track program committee, we regret to inform you that your submission
569: Peb Ruswono Aryan, Fajar J. Ekaputra, SPARQLGPViz: SPARQL Graph Pattern Visualization
could not be accepted for presentation.
This year, we received a high number of submissions for presentation at the conference. The competition was particularly tough due to the quality of submissions. For borderline papers, we have held discussions but sometimes had to make difficult decisions.
We know this is disappointing news and we understand that all authors have devoted a significant amount of effort to their work. So, we sincerely thank you for your effort.
We have included the reviews at the bottom of this email and we hope that the reviews can help you to further improve your work.
We look forward to seeing you at the virtual ISWC 2020 in November. You may register here:
https://iswc2020.semanticweb.org/attending/registration/. Information on student grants (not necessarily requiring paper acceptance) and a student mentoring session can be found at https://iswc2020.semanticweb.org/attending/student-grants/ and https://iswc2020.semanticweb.org/program/student-engagement-and-mentoring-session/
Thank you for submitting your work to ISWC.
Sincerely,
Kerry Taylor
Rafael Goncalves
SUBMISSION: 569
TITLE: SPARQLGPViz: SPARQL Graph Pattern Visualization
----------------------- REVIEW 1 ---------------------
SUBMISSION: 569
TITLE: SPARQLGPViz: SPARQL Graph Pattern Visualization
AUTHORS: Peb Ruswono Aryan and Fajar J. Ekaputra
----------- Reviewer's confidence -----------
SCORE: 4 ((high))
----------- Appropriateness -----------
SCORE: 2 (excellent)
----------- Outrageous -----------
SCORE: 0 (somewhat novel)
----------- Related work -----------
SCORE: 0 (fair)
----------- Novelty -----------
SCORE: 0 (fair)
----------- Uptake -----------
SCORE: 2 (poor)
----------- Impact -----------
SCORE: 0 (fair)
----------- Technical quality and depth -----------
SCORE: 0 (fair)
----------- Reusability -----------
SCORE: 1 (good)
----------- Reproducibility -----------
SCORE: 0 (fair)
----------- Design quality -----------
SCORE: 0 (fair)
----------- Justified Sem. Web use -----------
SCORE: 3 (fair)
----------- Availability and sustainability -----------
SCORE: 1 (good)
----------- Clarity and quality of writing -----------
SCORE: 0 (fair)
----------- Semantic technologies -----------
SCORE: 1 (good)
----------- Summary review -----------
The paper presents "SPARQLGPViz", a didactic tool to teach SPARQL queries constructs to non-technical users via visualization of their graph patterns. It describes the visual representation of basic SPARQL graph patterns that include URI nodes, variable type nodes, blank nodes, and literals. It's a preliminary work that could be useful in various use cases beyond SPARQL learning.
----------- Overall evaluation -----------
SCORE: 0 (borderline paper)
----- TEXT:
Positive remarks:
Negative remarks:
The authors should also mention as related work, RDF Explorer: A Visual Query Builder for Semantic Web Knowledge Graphs:
http://aidanhogan.com/docs/rdf_explorer_demo.pdf
http://videolectures.net/iswc2019_vargas_rdf_explorer/
The research contribution is weak.
Minor corrections:
Pag. 1 / Sec. 1: "for teaching SPARQL to these users is by introducing the its features..." | remove the before "its"
Pag. 1 / Sec. 1: "query builder tool [1,2,?,4]" | fix reference
----------------------- REVIEW 2 ---------------------
SUBMISSION: 569
TITLE: SPARQLGPViz: SPARQL Graph Pattern Visualization
AUTHORS: Peb Ruswono Aryan and Fajar J. Ekaputra
----------- Reviewer's confidence -----------
SCORE: 4 ((high))
----------- Appropriateness -----------
SCORE: -2 (very poor)
----------- Outrageous -----------
SCORE: -2 (nothing new)
----------- Related work -----------
SCORE: -1 (poor)
----------- Novelty -----------
SCORE: -2 (very poor)
----------- Uptake -----------
SCORE: 1 (very poor)
----------- Impact -----------
SCORE: -2 (very poor)
----------- Technical quality and depth -----------
SCORE: -2 (very poor)
----------- Reusability -----------
SCORE: -1 (poor)
----------- Reproducibility -----------
SCORE: -1 (poor)
----------- Design quality -----------
SCORE: -2 (very poor)
----------- Justified Sem. Web use -----------
SCORE: 2 (poor)
----------- Availability and sustainability -----------
SCORE: -2 (very poor)
----------- Clarity and quality of writing -----------
SCORE: -2 (very poor)
----------- Semantic technologies -----------
SCORE: 0 (fair)
----------- Summary review -----------
The contribution is too low to be accepted.
----------- Overall evaluation -----------
SCORE: -3 (strong reject)
----- TEXT:
This seems like an interesting demo for the ISWC audience.
----------------------- REVIEW 3 ---------------------
SUBMISSION: 569
TITLE: SPARQLGPViz: SPARQL Graph Pattern Visualization
AUTHORS: Peb Ruswono Aryan and Fajar J. Ekaputra
----------- Reviewer's confidence -----------
SCORE: 5 ((expert))
----------- Appropriateness -----------
SCORE: 2 (excellent)
----------- Outrageous -----------
SCORE: -2 (nothing new)
----------- Related work -----------
SCORE: 0 (fair)
----------- Novelty -----------
SCORE: -2 (very poor)
----------- Uptake -----------
SCORE: 3 (fair)
----------- Impact -----------
SCORE: 0 (fair)
----------- Technical quality and depth -----------
SCORE: 0 (fair)
----------- Reusability -----------
SCORE: 2 (excellent)
----------- Reproducibility -----------
SCORE: 2 (excellent)
----------- Design quality -----------
SCORE: -1 (poor)
----------- Justified Sem. Web use -----------
SCORE: 5 (excellent)
----------- Availability and sustainability -----------
SCORE: 1 (good)
----------- Clarity and quality of writing -----------
SCORE: 1 (good)
----------- Semantic technologies -----------
SCORE: 2 (excellent)
----------- Summary review -----------
The tool described is potentially useful and publicly sharing the code much appreciated,
but, in my opinion, this contribution is on itself of very limited research value, lacking any novelty.
----------- Overall evaluation -----------
SCORE: -2 (reject)
----- TEXT:
The authors describe a way of visualising graph patterns in SPARQL queries and a
tool that generates the visualisation for a given query.
This kind of visualisation is pretty typical and has been used in SPARQL visual
query builders. It is not clear if there is anything novel in the specific
visualisation proposed by the authors.
The tool is potentially useful and publicly sharing the code much appreciated,
but, in my opinion, this contribution is on itself of very limited research value.