Skip to content

Commit

Permalink
feat: moved graph weighting and coloring to backend
Browse files Browse the repository at this point in the history
  • Loading branch information
ptdewey committed Nov 24, 2024
1 parent 4843dfc commit 8b64c4e
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 67 deletions.
2 changes: 1 addition & 1 deletion examples/oolong.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ plugin_paths = [
[graph]
min_node_weight = 8.0
max_node_weight = 80.0
min_link_weight = 2.0
min_link_weight = 0.1
46 changes: 1 addition & 45 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,6 @@

<body>
<div id="3d-graph"></div>

<script type="importmap">{ "imports": { "three": "//unpkg.com/three/build/three.module.js" }}</script>
<script type="module">
import SpriteText from "//unpkg.com/three-spritetext/dist/three-spritetext.mjs";

const normalizeValue = (val, min, max) => (val - min) / (max - min);

const minWeight = 0.00

// CHANGE: move handling of color to backend where calculations are faster
function mapValueToColor(value) {
const clampedValue = Math.max(minWeight, Math.min(value, 1));
// interpolate color between dark gray (#333333 -- 51) and white (#ffffff 255)
// const grayScale = Math.round(51 + (204 * clampedValue));
const grayScale = Math.round(1 + (204 * clampedValue)) * 1.5;
return `rgb(${grayScale}, ${grayScale}, ${grayScale})`;
}

fetch("http://localhost:11975/graph").then(res => res.json())
// fetch("./graph.json").then(res => res.json())
.then(data => {
const Graph = ForceGraph3D()
(document.getElementById('3d-graph'))
// .jsonUrl('./graph.json')
.graphData(data)
.nodeAutoColorBy('group')
.nodeThreeObject(node => {
const splitname = node.id.split("/") // CHANGE: add new field on daemon side for split name
const sprite = new SpriteText(splitname[splitname.length - 1]);
sprite.material.depthWrite = false;
sprite.color = node.color;
sprite.textHeight = 8;
return sprite;
})
.linkOpacity(.8) // NOTE: baseline opacity can be adjusted, but keep high
.linkColor(link => {
const value = link.strength !== undefined ? link.strength : minWeight;
return mapValueToColor(value);
});

// Spread nodes a little wider
Graph.d3Force('charge').strength(-120);
})

// TODO: line weight can be set here, use documentWeight to do this
</script>
<script type="module" src="index.js"> </script>
</body>
20 changes: 20 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import SpriteText from "//unpkg.com/three-spritetext/dist/three-spritetext.mjs";

fetch("http://localhost:11975/graph")
.then((res) => res.json())
.then((data) => {
const Graph = ForceGraph3D()(document.getElementById("3d-graph"))
.graphData(data)
.nodeAutoColorBy("group")
.nodeThreeObject((node) => {
const sprite = new SpriteText(node.name);
sprite.material.depthWrite = false;
sprite.color = node.color;
sprite.textHeight = 8;
return sprite;
})
.linkOpacity(0.8) // NOTE: baseline opacity can be adjusted, but keep high
.linkColor((link) => link.color);
// Spread nodes a little wider
Graph.d3Force("charge").strength(-120);
});
3 changes: 2 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ type OolongGraphConfig struct {
MinNodeWeight float64 `toml:"min_node_weight"`
MaxNodeWeight float64 `toml:"max_node_weight"`
MinLinkWeight float64 `toml:"min_link_weight"`
// TODO: max link weight (call it a cap?)
}

func Config() *OolongConfig { return &cfg }
Expand Down Expand Up @@ -69,6 +68,8 @@ func Setup(configPath string) error {
cfg.NotesDirPaths[i] = d
}

// TODO: set default values for thresholds if not set

return nil
}

Expand Down
31 changes: 22 additions & 9 deletions internal/graph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package graph

import (
"encoding/json"
"fmt"
"math"
"path/filepath"

"github.com/oolong-sh/oolong/internal/config"
Expand All @@ -10,15 +12,17 @@ import (
)

type NodeJSON struct {
ID string `json:"id"`
Name string `json:"name"`
Val float64 `json:"val"`
ID string `json:"id"`
Name string `json:"name"`
Group string `json:"group"`
Val float64 `json:"val"`
}

type LinkJSON struct {
Source string `json:"source"`
Target string `json:"target"`
Value float64 `json:"strength"`
Color string `json:"color"`
}

type Graph struct {
Expand Down Expand Up @@ -46,14 +50,16 @@ func SerializeGraph(keywordMap map[string]keywords.Keyword, notes []notes.Note)
nodes := []NodeJSON{}
links := []LinkJSON{}

// TODO: node groups
for _, keyword := range keywordMap {
// Only add nodes above the minimum threshold
if keyword.Weight >= minThresh {
clampedWeight := clamp(keyword.Weight, minThresh, upperBound)
nodes = append(nodes, NodeJSON{
ID: keyword.Keyword,
Name: keyword.Keyword,
Val: clampedWeight,
ID: keyword.Keyword,
Name: keyword.Keyword,
Group: "keyword",
Val: clampedWeight,
})
}
}
Expand All @@ -63,9 +69,10 @@ func SerializeGraph(keywordMap map[string]keywords.Keyword, notes []notes.Note)
noteID := note.Path
noteName := filepath.Base(note.Path)
nodes = append(nodes, NodeJSON{
ID: noteID,
Name: noteName,
Val: NOTE_NODE_VAL,
ID: noteID,
Name: noteName,
Group: "note",
Val: NOTE_NODE_VAL,
})

// Link notes to keywords
Expand All @@ -76,6 +83,7 @@ func SerializeGraph(keywordMap map[string]keywords.Keyword, notes []notes.Note)
Source: noteID,
Target: keyword.Keyword,
Value: wgt,
Color: weightToColor(wgt),
})
}
}
Expand All @@ -94,3 +102,8 @@ func SerializeGraph(keywordMap map[string]keywords.Keyword, notes []notes.Note)
// return graph, nil
return jsonData, nil
}

func weightToColor(v float64) string {
c := int(math.Round((1 + 204*math.Min(v, 1)) * 1.5))
return fmt.Sprintf("rgb(%d, %d, %d)", c, c, c)
}
16 changes: 5 additions & 11 deletions internal/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,20 @@ func (s *StateManager) updateState(docs []*documents.Document) {
// if err := os.WriteFile("./meaningful-ngrams.csv", b, 0666); err != nil {
// panic(err)
// }
//
// TEST: remove later
//

// TODO: add threshold filtering params to these functions (use config)
// // TODO: add threshold filtering params to these functions (use config)
// kw := keywords.NGramsToKeywordsMap(s.state.NGrams)
// notes := notes.DocumentsToNotes(s.state.Documents)

// REFACTOR: store graph json in state field to make it available on request earlier?
// - this is probably a good idea
//
// dat, err := graph.SerializeGraph(kw, notes, 0.1, 80)
// if err != nil {
// panic(err)
// }

// TEST: remove json output later
//
// if err := os.WriteFile("graph.json", dat, 0644); err != nil {
// panic(err)
// }
//
// TEST: remove later
//

log.Println("State update complete.")
}

0 comments on commit 8b64c4e

Please sign in to comment.