Documentation ¶
Overview ¶
Package treemap implements functions and structs for building treemaps
TreeMaps are an alternative way to display properties of structured layered data (such as filesystems). Every data point can contain up to 4 different dimmensions: 3 numericals and a color encoded one.
Consider the folowing description of a simple, hypotetical code analyzer report. In this case the dimm1 is the number of lines of code contained by the node, dimm2 is the number of types, dimm3, the number of functions and the color is encoding the complexity of the node (CCN-like mesure)
{ "name": "mypackage", "dimm1": 1, "dimm2": 2, "dimm3": 3, "color": "0xff00ff", "children": [ { "name": "mypackage/subpackage0", "dimm1": 5, "dimm2": 6, "dimm3": 7, "color": "0x00ffff" }, { "name": "mypackage/subpackage1", "dimm1": 10, "dimm2": 8, "dimm3": 3, "color": "0x00ff00", "children": [ { "name": "mypackage/subpackage1/subpackage0", "dimm1": 1, "dimm2": 4, "dimm3": 3, "color": "0xffff00" } ] } ] }
treemap generates an extended version of the tree description, adding spatial coordinates and dimmensions for every package (block) in the tree.
In this extended version, dimm1 will affect the width of the block; dimm2, its depth and dimm3 its height.
The tiling algorithm is based in:
- https://github.com/rodrigo-brito/gocity/blob/master/model/position.go
- https://www.codeproject.com/Articles/210979/Fast-optimizing-rectangle-packing-algorithm-for-bu
- http://www.cs.umd.edu/hcil/treemap-history/index.shtml
Example ¶
tree := TreeInfo{ BlockInfo: BlockInfo{ Name: "root", Dimm1: 1, Dimm2: 2, Dimm3: 3, Color: "0xff00ff", }, Children: []*TreeInfo{ { BlockInfo: BlockInfo{ Name: "root #0", Dimm1: 5, Dimm2: 6, Dimm3: 7, Color: "0x00ffff", }, Children: []*TreeInfo{}, }, { BlockInfo: BlockInfo{ Name: "root #1", Dimm1: 10, Dimm2: 8, Dimm3: 3, Color: "0x00ff00", }, Children: []*TreeInfo{ { BlockInfo: BlockInfo{ Name: "root #1 #1", Dimm1: 1, Dimm2: 4, Dimm3: 3, Color: "0xffff00", }, Children: []*TreeInfo{}, }}, }, }, } fmt.Println(tree.Tree(context.Background()).String())
Output: { "depth": 35, "height": 6, "width": 21, "position": { "x": 0, "y": 0 }, "name": "root", "dimm1": 1, "dimm2": 2, "dimm3": 3, "color": "0xff00ff", "children": [ { "depth": 9, "height": 10, "width": 8, "position": { "x": -4.5, "y": -10.5, "z": 6 }, "name": "root #0", "dimm1": 5, "dimm2": 6, "dimm3": 7, "color": "0x00ffff" }, { "depth": 18, "height": 6, "width": 17, "position": { "x": 0, "y": 6, "z": 6 }, "name": "root #1", "dimm1": 10, "dimm2": 8, "dimm3": 3, "color": "0x00ff00", "children": [ { "depth": 7, "height": 6, "width": 4, "position": { "x": 0, "y": 0, "z": 12 }, "name": "root #1 #1", "dimm1": 1, "dimm2": 4, "dimm3": 3, "color": "0xffff00" } ] } ] }
Example (FromJSONDefinition) ¶
jsonDefinition := `{ "name": "root", "dimm1": 1, "dimm2": 2, "dimm3": 3, "color": "0xff00ff", "children": [ { "name": "root #0", "dimm1": 5, "dimm2": 6, "dimm3": 7, "color": "0x00ffff" }, { "name": "root #1", "dimm1": 10, "dimm2": 8, "dimm3": 3, "color": "0x00ff00", "children": [ { "name": "root #1 #1", "dimm1": 1, "dimm2": 4, "dimm3": 3, "color": "0xffff00" } ] } ] }` tree := TreeInfo{} json.Unmarshal([]byte(jsonDefinition), &tree) fmt.Println("Get the Block") fmt.Println(tree.Block().String()) fmt.Println("Get the Tree") fmt.Println(tree.Tree(context.Background()).String())
Output: Get the Block { "depth": 0, "height": 0, "width": 0, "position": { "x": 0, "y": 0 }, "name": "root", "dimm1": 1, "dimm2": 2, "dimm3": 3, "color": "0xff00ff", "children": [ { "depth": 0, "height": 0, "width": 0, "position": { "x": 0, "y": 0 }, "name": "root #0", "dimm1": 5, "dimm2": 6, "dimm3": 7, "color": "0x00ffff" }, { "depth": 0, "height": 0, "width": 0, "position": { "x": 0, "y": 0 }, "name": "root #1", "dimm1": 10, "dimm2": 8, "dimm3": 3, "color": "0x00ff00", "children": [ { "depth": 0, "height": 0, "width": 0, "position": { "x": 0, "y": 0 }, "name": "root #1 #1", "dimm1": 1, "dimm2": 4, "dimm3": 3, "color": "0xffff00" } ] } ] } Get the Tree { "depth": 35, "height": 6, "width": 21, "position": { "x": 0, "y": 0 }, "name": "root", "dimm1": 1, "dimm2": 2, "dimm3": 3, "color": "0xff00ff", "children": [ { "depth": 9, "height": 10, "width": 8, "position": { "x": -4.5, "y": -10.5, "z": 6 }, "name": "root #0", "dimm1": 5, "dimm2": 6, "dimm3": 7, "color": "0x00ffff" }, { "depth": 18, "height": 6, "width": 17, "position": { "x": 0, "y": 6, "z": 6 }, "name": "root #1", "dimm1": 10, "dimm2": 8, "dimm3": 3, "color": "0x00ff00", "children": [ { "depth": 7, "height": 6, "width": 4, "position": { "x": 0, "y": 0, "z": 12 }, "name": "root #1 #1", "dimm1": 1, "dimm2": 4, "dimm3": 3, "color": "0xffff00" } ] } ] }
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Walk ¶
Walk walks the block tree rooted at root depth-first, calling walkFn for each Block in the tree
Example ¶
root := generateTree(rand.New(rand.NewSource(0)), 5) if err := Walk(root, func(b *Block) error { fmt.Println(b.Name) return nil }); err != nil { fmt.Println(err.Error()) }
Output: root root #0 root #0 #0 root #0 #0 #0 root #0 #0 #0 #0 root #0 #0 #0 #0 #0 root #0 #0 #1 root #0 #0 #1 #0 root #0 #0 #1 #0 #0 root #0 #0 #1 #1 root #0 #0 #1 #1 #0 root #0 #3 root #0 #3 #0 root #0 #3 #0 #1 root #0 #3 #1 root #0 #3 #1 #0 root #0 #3 #2 root #0 #3 #2 #0 root #0 #3 #2 #0 #0 root #0 #3 #2 #1 root #1 root #1 #0 root #1 #0 #0 root #1 #0 #0 #0 root #1 #0 #1 root #1 #0 #2 root #1 #0 #2 #0 root #1 #0 #2 #0 #0 root #1 #1 root #1 #1 #0 root #1 #1 #0 #0 root #1 #1 #0 #0 #0 root #1 #1 #0 #1 root #1 #1 #0 #1 #0 root #1 #1 #1 root #1 #1 #1 #1 root #1 #1 #1 #1 #0 root #1 #1 #2 root #1 #1 #2 #0 root #1 #2 root #1 #2 #0 root #1 #2 #0 #0 root #1 #2 #0 #1 root #1 #2 #2 root #1 #2 #2 #0 root #1 #2 #2 #0 #0 root #1 #3 root #1 #3 #0 root #1 #3 #0 #1 root #1 #3 #1 root #1 #3 #1 #1 root #1 #3 #1 #1 #0 root #1 #3 #2 root #2 root #2 #0 root #2 #0 #0 root #2 #0 #0 #0 root #2 #0 #0 #0 #0 root #2 #0 #2 root #2 #0 #2 #0 root #2 #0 #2 #1 root #2 #0 #2 #1 #0 root #2 #1 root #2 #1 #0 root #2 #1 #0 #0 root #2 #1 #0 #0 #0 root #2 #1 #1 root #2 #1 #1 #0 root #2 #1 #1 #0 #0 root #2 #1 #1 #1 root #2 #1 #1 #1 #0 root #2 #1 #2 root #2 #1 #2 #1 root #2 #1 #2 #1 #0 root #2 #2 root #2 #2 #0 root #2 #2 #0 #1 root #2 #2 #1 root #2 #2 #1 #0 root #2 #2 #1 #0 #0 root #2 #3 root #2 #3 #0 root #2 #3 #0 #1 root #2 #3 #0 #1 #0 root #2 #3 #2 root #3 root #3 #1 root #3 #1 #0 root #3 #1 #0 #0 root #3 #1 #0 #0 #0 root #3 #1 #0 #1 root #3 #1 #0 #1 #0 root #3 #2 root #3 #2 #2 root #3 #2 #2 #1 root #3 #3 root #3 #3 #0 root #3 #3 #0 #0 root #3 #3 #0 #0 #0 root #3 #3 #0 #1 root #3 #3 #0 #1 #0 root #3 #3 #1 root #3 #3 #1 #0 root #3 #3 #1 #0 #0 root #3 #3 #2 root #3 #3 #2 #0 root #3 #3 #2 #0 #0 root #3 #3 #2 #1 root #3 #3 #2 #1 #0
Example (ContextCanceled) ¶
root := generateTree(rand.New(rand.NewSource(0)), 5) ok := WalkFunc(func(b *Block) error { fmt.Println(b.Name) return nil }) ko := WalkFunc(func(b *Block) error { fmt.Println("the walk function should not been called for", b.Name) return nil }) if err := Walk(root, ok.WithContext(context.Background())); err != nil { fmt.Println(err.Error()) } fmt.Println("canceled context?") ctx, cancel := context.WithCancel(context.Background()) cancel() fmt.Println(Walk(root, ko.WithContext(ctx)))
Output: root root #0 root #0 #0 root #0 #0 #0 root #0 #0 #0 #0 root #0 #0 #0 #0 #0 root #0 #0 #1 root #0 #0 #1 #0 root #0 #0 #1 #0 #0 root #0 #0 #1 #1 root #0 #0 #1 #1 #0 root #0 #3 root #0 #3 #0 root #0 #3 #0 #1 root #0 #3 #1 root #0 #3 #1 #0 root #0 #3 #2 root #0 #3 #2 #0 root #0 #3 #2 #0 #0 root #0 #3 #2 #1 root #1 root #1 #0 root #1 #0 #0 root #1 #0 #0 #0 root #1 #0 #1 root #1 #0 #2 root #1 #0 #2 #0 root #1 #0 #2 #0 #0 root #1 #1 root #1 #1 #0 root #1 #1 #0 #0 root #1 #1 #0 #0 #0 root #1 #1 #0 #1 root #1 #1 #0 #1 #0 root #1 #1 #1 root #1 #1 #1 #1 root #1 #1 #1 #1 #0 root #1 #1 #2 root #1 #1 #2 #0 root #1 #2 root #1 #2 #0 root #1 #2 #0 #0 root #1 #2 #0 #1 root #1 #2 #2 root #1 #2 #2 #0 root #1 #2 #2 #0 #0 root #1 #3 root #1 #3 #0 root #1 #3 #0 #1 root #1 #3 #1 root #1 #3 #1 #1 root #1 #3 #1 #1 #0 root #1 #3 #2 root #2 root #2 #0 root #2 #0 #0 root #2 #0 #0 #0 root #2 #0 #0 #0 #0 root #2 #0 #2 root #2 #0 #2 #0 root #2 #0 #2 #1 root #2 #0 #2 #1 #0 root #2 #1 root #2 #1 #0 root #2 #1 #0 #0 root #2 #1 #0 #0 #0 root #2 #1 #1 root #2 #1 #1 #0 root #2 #1 #1 #0 #0 root #2 #1 #1 #1 root #2 #1 #1 #1 #0 root #2 #1 #2 root #2 #1 #2 #1 root #2 #1 #2 #1 #0 root #2 #2 root #2 #2 #0 root #2 #2 #0 #1 root #2 #2 #1 root #2 #2 #1 #0 root #2 #2 #1 #0 #0 root #2 #3 root #2 #3 #0 root #2 #3 #0 #1 root #2 #3 #0 #1 #0 root #2 #3 #2 root #3 root #3 #1 root #3 #1 #0 root #3 #1 #0 #0 root #3 #1 #0 #0 #0 root #3 #1 #0 #1 root #3 #1 #0 #1 #0 root #3 #2 root #3 #2 #2 root #3 #2 #2 #1 root #3 #3 root #3 #3 #0 root #3 #3 #0 #0 root #3 #3 #0 #0 #0 root #3 #3 #0 #1 root #3 #3 #0 #1 #0 root #3 #3 #1 root #3 #3 #1 #0 root #3 #3 #1 #0 #0 root #3 #3 #2 root #3 #3 #2 #0 root #3 #3 #2 #0 #0 root #3 #3 #2 #1 root #3 #3 #2 #1 #0 canceled context? context canceled
Example (Errored) ¶
root := generateTree(rand.New(rand.NewSource(0)), 5) expectedErr := errors.New("wait for me") var counter int if err := Walk(root, func(b *Block) error { counter++ if counter == 3 { return expectedErr } if counter > 3 { fmt.Println("walk funct called after throwing an error") } fmt.Println(b.Name) return nil }); err != nil { fmt.Println("got error:", err.Error()) } fmt.Println("total calls to the walk func:", counter)
Output: root root #0 got error: wait for me total calls to the walk func: 3
Types ¶
type Block ¶
Block is a tree of blocks. Every Block contains a list of children, a BlockInfo with the input values and a BlockNode with all the information regardind the block position and its dimensions
func NewBlock ¶
NewBlock returns a Block with the received info, containing the injected children but without setting the node details. This function is intended to be used when programmatically building all the nodes to be placed in a tree but the root.
Example ¶
b1 := NewBlock(BlockInfo{ Name: "b1", Dimm1: 1, Dimm2: 10, Dimm3: 5, Color: "0x00ff00", }) b2 := NewBlock(BlockInfo{ Name: "b2", Dimm1: 10, Dimm2: 1, Dimm3: 2, Color: "0xff0000", }) b := NewBlock(BlockInfo{ Name: "root", Dimm1: 5, Dimm2: 5, Dimm3: 10, Color: "0x0000ff", }, b1, b2) fmt.Println(b.String())
Output: { "depth": 0, "height": 0, "width": 0, "position": { "x": 0, "y": 0 }, "name": "root", "dimm1": 5, "dimm2": 5, "dimm3": 10, "color": "0x0000ff", "children": [ { "depth": 0, "height": 0, "width": 0, "position": { "x": 0, "y": 0 }, "name": "b1", "dimm1": 1, "dimm2": 10, "dimm3": 5, "color": "0x00ff00" }, { "depth": 0, "height": 0, "width": 0, "position": { "x": 0, "y": 0 }, "name": "b2", "dimm1": 10, "dimm2": 1, "dimm3": 2, "color": "0xff0000" } ] }
func NewTree ¶
NewTree returns a Block with the received info with all the injected children already positioned and sized. This function is intended to be used when programmatically building the root node of a tree, but it is safe to be called more than once. The returned Block can also be used as part of a bigger treemap.
Example ¶
b1 := NewBlock(BlockInfo{ Name: "b1", Dimm1: 1, Dimm2: 10, Dimm3: 5, Color: "0x00ff00", }) b2 := NewBlock(BlockInfo{ Name: "b2", Dimm1: 10, Dimm2: 1, Dimm3: 2, Color: "0xff0000", }) b := NewTree(context.Background(), BlockInfo{ Name: "root", Dimm1: 5, Dimm2: 5, Dimm3: 10, Color: "0x0000ff", }, b1, b2) fmt.Println(b.String())
Output: { "depth": 28, "height": 13, "width": 21, "position": { "x": 0, "y": 0 }, "name": "root", "dimm1": 5, "dimm2": 5, "dimm3": 10, "color": "0x0000ff", "children": [ { "depth": 13, "height": 8, "width": 4, "position": { "x": -4.5, "y": -3.5, "z": 13 }, "name": "b1", "dimm1": 1, "dimm2": 10, "dimm3": 5, "color": "0x00ff00" }, { "depth": 4, "height": 5, "width": 13, "position": { "x": 0, "y": 8, "z": 13 }, "name": "b2", "dimm1": 10, "dimm2": 1, "dimm3": 2, "color": "0xff0000" } ] }
func (*Block) Generate ¶
Generate implements the quick.Generator interface (https://golang.org/pkg/testing/quick/#Generator)
type BlockInfo ¶
type BlockInfo struct { Name string `json:"name"` Dimm1 int `json:"dimm1"` Dimm2 int `json:"dimm2"` Dimm3 int `json:"dimm3"` Color Color `json:"color,omitempty"` }
BlockInfo contains all the user defined details of every Block in the tree map
type BlockNode ¶
type BlockNode struct { Depth float64 `json:"depth"` Height float64 `json:"height"` Width float64 `json:"width"` Position Position `json:"position"` }
BlockNode contains information regarding the size and position of every Block in the tree map
type Color ¶
type Color string
Color is a wrapper over a string, useful for string to color conversions and quick serialization. The expected format is "0xff00ff"
func (Color) Decode ¶
Decode returns the color described as hex at c
Example ¶
for _, tc := range []string{ "0xff00ff", "0x", "0x00ff", "0xffff", "0x00ffff", "0xzzzzzz", } { c, err := Color(tc).Decode() if err != nil { fmt.Printf("!!! %s: %s\n", tc, err.Error()) continue } r, g, b, a := c.RGBA() fmt.Printf("%s: {%d, %d, %d, %d}\n", tc, r, g, b, a) }
Output: 0xff00ff: {65535, 0, 65535, 65535} 0x: {0, 0, 0, 65535} 0x00ff: {0, 65535, 0, 65535} 0xffff: {65535, 65535, 0, 65535} 0x00ffff: {0, 65535, 65535, 65535} !!! 0xzzzzzz: encoding/hex: invalid byte: U+007A 'z'
type Tiler ¶
type Tiler struct {
// contains filtered or unexported fields
}
Tiler is a quick implementation of a solution for the tiling problem. It takes an amount of tiles to place in one plane starting at {0, 0} and identifies where a tile should be placed and what is the smaller rectangle containing all the passed tiles.
func NewTilerWithMargin ¶
NewTilerWithMargin returns a tiler expecting to place totalTiles with the injected margin
func (*Tiler) GetBounds ¶
GetBounds returns the size of the rectangle containing all the tiles placed so far
func (*Tiler) NextPosition ¶
NextPosition calculates where a tile of the passed dimensions should be placed
type TreeInfo ¶
TreeInfo is a tree of BlockInfo structs describing a treemap
func (*TreeInfo) Block ¶
Block returns the tree described by t without initializing the positions of the blocks
func (*TreeInfo) Generate ¶
Generate implements the quick.Generator interface (https://golang.org/pkg/testing/quick/#Generator)
Directories ¶
Path | Synopsis |
---|---|
cmd
|
|
treemap
Treemap converts the tree definition into a treemap, exporting it as a JSON or as an image
|
Treemap converts the tree definition into a treemap, exporting it as a JSON or as an image |
Package plain exposes functions for rendering vertical projections of treemaps
|
Package plain exposes functions for rendering vertical projections of treemaps |
Package volume exposes functions for rendering 3D views of treemaps
|
Package volume exposes functions for rendering 3D views of treemaps |