:- module(edm_graph, [ edm_context_graph/3, % +URI, -Graph, +Options edm_node_shape/3 % +URI, -Shape, +Options ]). :- use_module(cliopatria(hooks)). :- use_module(library(uri)). :- use_module(library(semweb/rdf_db)). :- use_module(library(semweb/rdfs)). :- use_module(library(semweb/rdf_abstract)). :- use_module(library(http/page_info)). :- use_module(library(http/html_write)). :- use_module(library(lists)). :- use_module(components(label)). :- use_module(library(settings)). :- use_module(library(count)). /** EDM Context graphs This module customises context graphs, both in how they are computed and in the rendering of the EDM classes. @see cliopatria(hooks) for a description of the hooks. */ % Use SVG context graphs, so we can include images. :- set_setting_default(graphviz:format, svg). %% edm_context_graph(+URI, -Graph, +Options) % % Compute the EDM context graph. This is currently defined to do a % two-step breadth-first expansion of the graph from URI using the % known EDM properties. Branching from a single node is limited to % 20 and the total graph is not expanded beyond 100 nodes. :- rdf_meta edm_relation(?, r), edm_class(r). edm_context_graph(R, RDF, Options) :- option(style(Style), Options), ( ground(Style) -> Style = edm(_), IsEDM = true ; IsEDM = maybe ), Style = edm(EDMStyle), bf_graph(R, EDMStyle, 2, 100, 20, RDF0), minimise_graph(RDF0, RDF1), % remove inverse/symmetric/... bagify_graph(RDF1, RDF2, Bags, []), % Create bags of similar resources append(RDF2, Bags, RDF), graph_resources(RDF, Resources, _Preds, _Types), ( IsEDM == true -> true ; include(edm_resource, Resources, EDMResources), EDMResources = [_,_|_] ). %% bf_graph(+Start, +MaxDist, +MaxEdges, +MaxBranch, -Graph) bf_graph(Start, Style, MaxDist, MaxEdges, MaxBranch, Graph) :- bf_graph_2([0-Start], Style, MaxDist, MaxEdges, MaxBranch, [], Graph). bf_graph_2([], _, _, _, _, G, G) :- !. bf_graph_2([D-_|_], _, MaxDist, _, _, G, G) :- D >= MaxDist, !. bf_graph_2(AG0, Style, MaxDist, MaxEdges, MaxBranch, G0, G) :- bf_expand(AG0, AG, Style, MaxBranch, G1), ( G1 == [] -> bf_graph_2(AG, Style, MaxDist, MaxEdges, MaxBranch, G0, G) ; append(G1, G0, G2), sort(G2, G3), length(G3, Edges), ( Edges >= MaxEdges -> G = G0 ; bf_graph_2(AG, Style, MaxDist, MaxEdges, MaxBranch, G3, G) ) ). bf_expand([D-F|AG0], AG, Style, MaxBranch, Triples) :- D1 is D + 1, Key = D1-Dst, answer_set(Key-Triple, related(Style, F, Dst, Triple), MaxBranch, Pairs), pairs_keys_values(Pairs, Dsts, Triples), append(AG0, Dsts, AG). related(Style, S, O, rdf(S,P,O)) :- edm_relation(Style, Rel), rdf_has(S, Rel, O0, P), real_object(Style, O0, O). related(Style, O, S, rdf(S,P,O)) :- edm_relation(Style, Rel), rdf_has(S0, Rel, O, P), real_object(Style, S0, S). % is this ever meaningful? real_object(user, O0, O) :- rdf_is_bnode(O0), rdf_has(O0, rdf:value, O), !. real_object(_, O, O). edm_relation(edm, ore:aggregates). edm_relation(edm, ore:proxyFor). edm_relation(edm, ore:proxyIn). edm_relation(edm, ens:aggregatedCHO). edm_relation(edm, ens:hasThumbnail). edm_relation(edm, dcterms:hasPart). edm_relation(edm, ens:isNextInSequence). edm_relation(edm, ens:object). % this is *always* a thumbnail edm_relation(edm, ens:hasView). edm_relation(_, dcterms:relation). edm_relation(user, dcterms:creator). edm_resource(R) :- edm_class(Class), rdfs_individual_of(R, Class), !. edm_class(ens:'WebResource'). edm_class(ore:'Aggregation'). edm_class(ore:'Proxy'). edm_class(ens:'PhysicalThing'). edm_class(ens:'Agent'). %% edm_node_shape(+URI, -Shape, +Options) % % Realise EDM-specific vizualisation of nodes in the % context-graph. edm_node_shape(URI, Shape, Options) :- option(style(edm(Style)), Options), node_shape(URI, Style, Shape, Options). node_shape(URI, _, Shape, Options) :- memberchk(start(URI), Options), Shape = [shape(tripleoctagon),style(filled),fillcolor('#ff85fd')]. node_shape(URI, _, Shape, _Options) :- rdf_has(URI, rdf:type, ens:'WebResource'), page_content_type(URI, Type), sub_atom(Type, 0, _, _, 'image/'), Shape = [img([src(URI)])]. node_shape(URI, _, Shape, _Options) :- rdf_has(URI, rdf:type, ore:'Aggregation'), Shape = [shape(box3d),style(filled),fillcolor('#85fff7')]. node_shape(URI, _, Shape, _Options) :- rdf_has(URI, rdf:type, ore:'Proxy'), Shape = [shape(diamond),style('rounded,filled'),fillcolor('#ffb785')]. node_shape(URI, _, Shape, _Options) :- rdf_has(URI, rdf:type, ens:'PhysicalThing'), Shape = [shape(house),style('filled'),fillcolor('#ff8585')]. node_shape(URI, _, Shape, _Options) :- rdfs_individual_of(URI, ens:'Agent') -> Shape = [img([src(icons('ad_secret_agent.png'))])].