Skip to content

Commit

Permalink
cli works
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolaydubina committed Nov 12, 2021
1 parent 39e6e1c commit 2daecef
Show file tree
Hide file tree
Showing 46 changed files with 7,497 additions and 2,246 deletions.
16 changes: 8 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ build:

clean:
-rm jsonl-graph
-rm docs/*.svg docs/*.dot
-rm testdata/*.svg testdata/*.dot

docs: clean build
cat docs/gin.jsonl | ./jsonl-graph > docs/gin_nocolor.dot
cat docs/gin_nocolor.dot | dot -Tsvg > docs/gin_nocolor.svg
cat docs/gin.jsonl | ./jsonl-graph -color-scheme=file://$$PWD/docs/basic-colors.json > docs/gin_color.dot
cat docs/gin_color.dot | dot -Tsvg > docs/gin_color.svg
cat docs/small.jsonl | ./jsonl-graph > docs/small.dot
cat docs/small.dot | dot -Tsvg > docs/small.svg
cat testdata/gin.jsonl | ./jsonl-graph > testdata/gin_nocolor.dot
cat testdata/gin_nocolor.dot | dot -Tsvg > testdata/gin_nocolor.svg
cat testdata/gin.jsonl | ./jsonl-graph -color-scheme=file://$$PWD/testdata/colors.json > testdata/gin_color.dot
cat testdata/gin_color.dot | dot -Tsvg > testdata/gin_color.svg
cat testdata/small.jsonl | ./jsonl-graph > testdata/small.dot
cat testdata/small.dot | dot -Tsvg > testdata/small.svg

test:
go test -race -coverprofile=coverage.out -covermode=atomic ./...
Expand All @@ -23,4 +23,4 @@ web: clean
serve:
cd web; python3 -m http.server 8000

.PHONY: docs clean build
.PHONY: build clean docs test web serve
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,19 @@ This data encoding is a perfect fit for storing graphs:
⏳ Coloring of fields with filters
✅ Layout: Gravity Force
✅ Layout: Spring Force
✅ Layout: Isomap
✅ Layout: Eades
✅ Layout: Isomap
✅ Layout: Eades
⏳ Layout: Magnetic Force, Kozo Sugiyama
✅ Layout: Layers Kozo Sugiyama
✅ Layout: Layers Brandes-Köpf
✅ Layout: Layers Kozo Sugiyama
✅ Layout: Layers Brandes-Köpf
⏳ Metro-style edges
✅ Interactive Web UI with WebAssembly
⏳ Touch for zoom and pan in Web UI
⏳ CLI
✅ 100% Go
✅ 100% offline
✅ 100% offline
✅ No cgo
Self contained (..almost)
Minimal dependencies

TODO: run layers per each connected component stack by opposite direction of layers

Expand All @@ -88,9 +88,9 @@ $ cat '
...
{"from":"github.com/gin-gonic/gin","to":"golang.org/x/tools"}
{"from":"github.com/gin-gonic/gin","to":"github.com/go-playground/validator/v10"}
' | jsonl-graph -color-scheme=file://$PWD/docs/colors.json | dot -Tsvg > colored.svg
' | jsonl-graph -color-scheme=file://$PWD/testdata/colors.json | dot -Tsvg > colored.svg
```
![gin-color](./docs/gin_color.svg)
![gin-color](./testdata/gin_color.svg)

By default, no coloring is applied.
```bash
Expand All @@ -102,7 +102,7 @@ $ cat '
{"from":"github.com/gin-gonic/gin","to":"github.com/go-playground/validator/v10"}
' | jsonl-graph | dot -Tsvg > basic.svg
```
![gin-nocolor](./docs/gin_nocolor.svg)
![gin-nocolor](./testdata/gin_nocolor.svg)

If nodes have less fields, then adjusting graph

Expand All @@ -117,7 +117,7 @@ $ cat '
' | jsonl-graph | dot -Tsvg > small.svg
```

![small](./docs/small.svg)
![small](./testdata/small.svg)

## Wishlist

Expand Down
73 changes: 73 additions & 0 deletions color/color.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package color

import (
"encoding/json"
"image/color"
"strconv"
)

// ColorScale is sequence of colors and numerical anchors between them
type ColorScale struct {
Colors []color.RGBA
Points []float64
}

// ColorMapping of manual match of string value to color
type ColorMapping map[string]color.RGBA

// ColorConfigVal is configuration for single key on how to color its value
type ColorConfigVal struct {
ColorMapping *ColorMapping `json:"ColorMapping"`
ColorScale *ColorScale `json:"ColorScale"`
}

// Color for a given value
func (cv ColorConfigVal) Color(v interface{}) color.Color {
// convert value to string
var key string
if vs, ok := v.(string); ok {
key = vs
} else {
vs, err := json.Marshal(v)
if err != nil {
panic(err)
}
key = string(vs)
}

// first check manual values
if cv.ColorMapping != nil {
if c, ok := (*cv.ColorMapping)[key]; ok {
return c
}
}

// then check scale if present
if cv.ColorScale != nil && len(cv.ColorScale.Points) > 0 && len(cv.ColorScale.Points) == (len(cv.ColorScale.Colors)-1) {
if vs, err := strconv.ParseFloat(key, 64); err == nil {
idx := 0
for idx < len(cv.ColorScale.Points) && cv.ColorScale.Points[idx] <= vs {
idx++
}
if idx >= len(cv.ColorScale.Colors) {
idx = len(cv.ColorScale.Colors) - 1
}
return cv.ColorScale.Colors[idx]
}

}

return color.White
}

// ColorConfig defines how to translate arbitrary values to some color
type ColorConfig map[string]ColorConfigVal

// Color checks if config is found for that key, and computes color based on config
func (c ColorConfig) Color(k string, v interface{}) color.Color {
vc, ok := c[k]
if !ok {
return color.White
}
return vc.Color(v)
}
140 changes: 0 additions & 140 deletions docs/basic-colors.json

This file was deleted.

77 changes: 77 additions & 0 deletions dot/basic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package dot

import (
"fmt"

"github.com/nikolaydubina/jsonl-graph/graph"
)

type Renderable interface {
Render() string
}

// Orientation should match Graphviz allowed values
type Orientation string

const (
LR Orientation = "LR"
TB Orientation = "TB"
)

// BasicGraph renders graph to Dot without colors with simples syntax without HTML.
// TODO: consider adding colors in background https://stackoverflow.com/questions/17765301/-dot-how-to-change-the-colour-of-one-record-in-multi-record-shape
type BasicGraph struct {
orientation Orientation
nodes []Renderable
edges []Renderable
}

// NewBasicGraph creates renderable graph from graph data
func NewBasicGraph(
graph graph.Graph,
orientation Orientation,
) BasicGraph {
nodes := make([]Renderable, 0, len(graph.Nodes))
for _, n := range graph.Nodes {
node := Node{id: n.ID(), shape: RecordShape, label: BasicNodeLabel{n: n}}
nodes = append(nodes, node)
}

edges := make([]Renderable, 0, len(graph.Edges))
for _, e := range graph.Edges {
edges = append(edges, BasicEdge{from: e.From(), to: e.To()})
}

return BasicGraph{
orientation: orientation,
nodes: nodes,
edges: edges,
}
}

func (r BasicGraph) Render() string {
s := "digraph G {\n"
s += "rankdir=" + string(r.orientation) + "\n"

for _, n := range r.nodes {
s += n.Render() + "\n"

}

for _, e := range r.edges {
s += e.Render() + "\n"
}

s += "}\n"

return s
}

type BasicEdge struct {
from string
to string
}

func (r BasicEdge) Render() string {
return fmt.Sprintf(`"%s" -> "%s"`, r.from, r.to)
}
Loading

0 comments on commit 2daecef

Please sign in to comment.