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 :ids 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 :ids 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"))