Comments (5)
This kind of thing is precisely why I've advocated for several years that people who write loom algorithms should ideally test their algorithms against the ubergraph implementation of loom protocols. Too many loom algorithms inadvertently rely on implementation details of loom's concrete data structure, defeating the purpose of using protocols. A quick check against an alternative implementation is a great way to double-check that you've adhered to the protocols.
That said, this kind of destructuring of edges as vectors is so common place in loom that when developing ubergraph, I made sure that ubergraph's concrete edge implementations would destructure properly as vectors. So as long as you use vectors as your edges, or Ubergraph's edges as your edges, the vector destructuring will work fine. However, it looks like loom also allows you to use plain maps with a :src and :dest as your edges, (note how the Edge protocol is extended to cover maps), which would likely cause problems with vector destructuring.
from loom.
I'm not sure I follow how the maps with :src and :dest could cause problems with vector destructuring. Could you explain that a bit more?
My coworker was making an employee graph to just play around at work and is learning Clojure. I saw that protocol in loom and thought that would be a great way to show him how concise some Clojure could could be.
(def employee_records
(j/query db-conn query :row-fn (fn [row] (Employee. (:first_name row) (:last_name row) (:manager_id row)
(:id row)))))
(extend-protocol g/Edge
Employee
(src [this] this)
(dest [this] (first (filter #(= (:manager this) (:emp_number %)) employee_records))))
(def graph-85 (g/add-edges (g/digraph) employee_records))
I made sure that ubergraph's concrete edge implementations would destructure properly as vectors.
It seems like destructuring from the vector is convenient in defining the algorithms but it only saves two lines of code. But you can easily use them from the consumer side since the vector (the consumer users) will destructure since that protocol was extended. By "would destructure properly as vectors" do you mean that you made your edges implement the methods required for nth
?
from loom.
from loom.
I might be hitting this as well, the fact that the edge protocols exist means that I was just expecting this to work:
(let [graph {:edges [{ :target "mammal" :source "dog" :strength 0.7}
{ :target "mammal" :source "cat" :strength 0.7}
{ :target "mammal" :source "fox" :strength 0.7}
{ :target "mammal" :source "elk" :strength 0.7}
{ :target "insect" :source "ant" :strength 0.7}
{ :target "insect" :source "bee" :strength 0.7}
{ :target "fish" :source "carp" :strength 0.7}
{ :target "fish" :source "pike" :strength 0.7}
{ :target "cat" :source "elk" :strength 0.1}
{ :target "carp" :source "ant" :strength 0.1}
{ :target "elk" :source "bee" :strength 0.1}
{ :target "dog" :source "cat" :strength 0.1}
{ :target "fox" :source "ant" :strength 0.1}
{ :target "pike" :source "cat" :strength 0.1}]
:nodes [{ :id "mammal" :group 0 :label "Mammals" :level 1}
{ :id "dog" :group 0 :label "Dogs" :level 2}
{ :id "cat" :group 0 :label "Cats" :level 2}
{ :id "fox" :group 0 :label "Foxes" :level 2}
{ :id "elk" :group 0 :label "Elk" :level 2}
{ :id "insect" :group 1 :label "Insects" :level 1}
{ :id "ant" :group 1 :label "Ants" :level 2}
{ :id "bee" :group 1 :label "Bees" :level 2}
{ :id "fish" :group 2 :label "Fish" :level 1}
{ :id "carp" :group 2 :label "Carp" :level 2}
{ :id "pike" :group 2 :label "Pikes" :level 2}]}
transform-edges (fn [edges] (map #(clojure.set/rename-keys % {:source :src :target :dest}) edges))]
(-> (loom/digraph)
(loom/add-nodes* (:nodes graph))
(loom/add-edges* (transform-edges (:edges graph)))))
This does give the nth not supported on this type cljs.core/PersistentArrayMap
, as it's clear EditableGraph
's implementation assumes vectors though I can see the protocol definitions above:
:add-edges*
(fn [g edges]
(reduce
(fn [g [n1 n2]]
(-> g
(update-in [:nodeset] conj n1 n2)
(update-in [:adj n1] (fnil conj #{}) n2)
(update-in [:in n2] (fnil conj #{}) n1)))
g edges))
Is this for performance?
PS: Part of the reason for doing this is seeing how hard it would be to pull in a d3 wrapper so that cljs can also visualise graphs :)...
from loom.
Ok, that wasn't the case for me it seems, I just didn't clearly understand how to use loom's graphs. The code below should work for the graph I defined in my prior comment, without the edge transformation.
(require '[loom.graph :as loom])
(require '[loom.attr :as attr])
(defn make-graph [graph-type {:keys [nodes edges] :as graph}]
(let [node-map (into {} (map (fn [node] [(:id node) node])) nodes)
edge-map (into {} (map (fn [edge] [[(:source edge) (:target edge)] edge])) edges)
add-attrs-to-node-or-edge (fn [g node-or-edge-map]
(reduce
(fn [g [n-or-e-id n-or-e-map]]
(reduce (fn [inner-g [k v]]
(attr/add-attr inner-g n-or-e-id k v))
g n-or-e-map))
g node-or-edge-map))]
(-> (apply graph-type (keys edge-map))
(add-attrs-to-node-or-edge node-map)
(add-attrs-to-node-or-edge edge-map))))
(def make-weighted-digraph #(make-graph loom/weighted-digraph %))
It might be helpful to add an illustrative example to the docs? I've only just wrote this, so there may be improvements I can do here, but I thought it best to add the info, hopefully it helps someone in the future.
from loom.
Related Issues (20)
- Loom incompatible with CLJS >= 1.9.854 HOT 3
- Make 1.0.1 release ? HOT 3
- Possible Clojurescript [any Long] issue HOT 2
- Graph visualization in the browser HOT 1
- bipartite-color fails for digraphs with nodes containing no outgoing edges
- java.lang.NoClassDefFoundError: loom/graph/Graph HOT 2
- connected-components should return a seq of (sub)graphs
- Wrong typehint for clojurescript
- maximal-cliques silently breaks on digraphs
- Link to FAQ doesn't work HOT 1
- How does the ancestry cache work?
- Graph transpose does not work correctly in ClojureScript
- loom.io/view logic errors HOT 1
- remove-nodes* for BasicEditableDigraph throws null exception in cljs HOT 1
- Time for a new release? HOT 5
- Building a graph with an empty map throws a nullpointer exception
- hypergraphs using loom?
- Bug in implementation of weight
- Add mincost flow algorithm
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from loom.