Emacs generic graph store.
A lot of the things I've been interested in building in emacs lately have been pretty graph-y, so I thought it would be nice to have a standard data store for them in emacs instead of having to use external data stores. It makes things a lot easier to augment with other packages, add additional functionality etc.. This is the start of an attempt at that. The data structure may be a bit unconventional for a graph, but it's working out ok so far.
Consider this alpha currently, it's very much in progress. Functions documented here should work, and should have test coverage, but things could change and there are still a lot of features I would like to add. I think most of the primitives are here though. It's a start... To get an idea of how it works take a look at the tests
.
Graphs are stored in memory and optionally backed up to disk. Convenience is preferred over space, so consider that before adding millions of nodes/edges, but even up to a million or so seems to be fine (although very little testing has been done on large graphs).
Graph can be the name of a graph or the actual graph structure itself.
netz-make-graph
(name &optional path save)
netz-save-graph
(graph)
netz-load-graph
(path)
netz-reload-graph
(graph)
netz-get-graph
(name)
netz-copy-graph
(graph new-name &optional new-path)
netz-filtered-graph
(filter graph new-graph)
netz-add-node
(node graph)
netz-get-node
(node-id graph)
netz-get-nodes
(graph)
netz-delete-node
(node graph)
netz-add-edge
(edge graph)
netz-get-edge
(edge-id graph)
netz-get-edges
(graph)
netz-delete-edge
(edge graph)
netz-connect-nodes
(source target edge-params graph)
-- probably just make this netz-add-edge?netz-get-node-hood
(id graph &optional new-graph edge-filter directed)
netz-bfs-shortest-path
(source target graph &optional directed)
netz-get-related-by
(node graph &key by new-name directed)
Functions for dealing with a graph object.
Create and return a new graph with name
. Optionally provide a system path
of the location for the save file. If save
is non-nil the graph will be immediately written to the file path
.
Default path
is (user-emacs-directory)/.netz-graph/(name)
.
Create graph named :test
in memory. Graphs can be named with keywords.
(netz-make-graph :test)
Create graph named test
and save it to provided path. Graphs can be named with strings.
(netz-make-graph "test" "/home/toshism/graphs/test-graph" t)
Save graph
to disk. graph
can be the name or the full graph structure.
Save graph
named :test
(netz-save-graph :test)
Save provided graph
.
(setq test-graph (make-graph :test))
(netz-save-graph test-graph)
Load graph from provided file path
.
(netz-load-graph "/home/toshism/.emacs.d/.netz-graph/test")
(setq test-graph (make-graph :test))
(netz-load-graph (plist-get test-graph :path))
Reload and return graph
from disk.
(netz-reload-graph :test)
Return graph with name
.
(netz-get-graph :test)
Create and return new graph
named new-name
with optional new-path
.
(netz-copy-graph :test :new-test)
Create and return a graph
with name new-graph
filtered by filter
.
(netz-filtered-graph (:edges (:or (:match :type "LINKS_TO")
(:match :type "TAGGED")))
:test :linked-graph)
Filters can be for either :edges
or :nodes
but currently only one or the other.
Nodes are a plist with a single mandatory unique property named :id
.
Example:
'(:id 1 :label "Tag" :name "emacs")
Nodes also store a record of connected edges in the :edges
property. This is automatically maintained by netz when relationships are managed through the provided functions.
Add node
to graph
. If node already exists it will be merged with the existing node. New values take precedence. See netz-merge-plists
for details. Returns the updated graph
.
Add a node with :id
of 1 and a :label
of "Note" to :test
graph.
(netz-add-node '(:id 1 :label "Note") :test)
If we then call
(netz-add-node '(:id 1 :label "Tag" :name "test") :test)
Node with id 1 will be equal to (:id 1 :label "Tag" :name "test")
Return node with node-id
from graph
.
(netz-get-node 1 :test)
Return a hash table of all nodes from graph
with node :id
s as the keys.
(netz-get-nodes :test)
Delete node
from graph
.
(netz-delete-node '(:id 1) :test)
Edges are a plist with a single mandatory unique proprty named :id
which is a list of node ids. :id
is a list of source and target ids.
Example:
'(:id (1 2) :type "TAGGED")
Add edge
to graph
.
(netz-add-edge '(:id (1 2) :type "TAGGED") :test)
Get edge with edge-id
from graph
.
(netz-get-edge '(1 2) :test)
Return a hash table of all edges from graph
with edge :id
s as the keys.
(netz-get-edges :test)
Delete edge
from graph
.
(netz-delete-edge '(:id (1 2) :type "TAGGED") :test)
Connect source
to target
with edge having edge-params
in graph
.
(setq one (netz-get-node 1 :test)
(setq two (netz-get-node 2 :test)
(netz-connect-nodes one two '(:type "LINKS_TO") :test)
Get the neighborhood for node with id
in graph
.
optional
If new-graph
is nil modify graph in place, if it is non-nil return a new graph named new-graph
.
edge-filter
limits the neighborhood by properties of the edges.
directed
is a boolean value to specify if the neighborhood should consider edge direction in a directed graph.
(netz-get-node-hood 1 :test)
Return a new graph named "hood" for node id 1 and connected nodes through a "RELATED" property.
(netz-get-node-hood 1 :test :hood (:match :type "RELATED"))
See filtering
for more details on filtering syntax.
Return the shortest path, as a list of node ids, between source
and target
in graph
.
optional
If directed
is nil ignore direction.
(setq start (netz-get-node 1 :test))
(setq end (netz-get-node 2 :test))
(netz-bfs-shortest-path start end :test)
Return a graph named new-name
that contains nodes related to node
with edges properties by
in graph
, optionally directed
.
Sounds confusing but it's similar to neighborhood.
(netz-get-related-by (netz-get-node 1 :test) :test (:match :type "LINKS_TO") :links-to t)
Filtering functions are used as arguments for any functions that accept filter parameters. They can be combined and nested.
See netz-filtered-graph
for an example.
:match
is used to select a node or edge by the value
of a property
. Equality is checked with equal
.
The following will match a node or edge with the :label
value of Note
.
(:match :label "Note")
:and
can be used to combine :match
statements with logical and.
(:and (:match :label "Note")
(:match :type "A"))
:or
can be used to combine :match
statements with logical or.
(:or (:match :label "Note")
(:match :type "A"))