Last active
May 29, 2019 03:42
-
-
Save ajstarks/6b1128976479f98dde59bf2b78b9d76b to your computer and use it in GitHub Desktop.
visualize go modules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// modviz: visualize go modules | |
// go mod graph | sed -Ee 's/@[^[:blank:]]+//g' | sort | uniq | | |
// awk '{print $1}' | sort | uniq -c | sort -nr | awk '{print $2 "\t" $1}' | modviz > f.svg | |
package main | |
import ( | |
"bufio" | |
"flag" | |
"fmt" | |
"io" | |
"math" | |
"os" | |
"strconv" | |
"strings" | |
"github.com/ajstarks/svgo/float" | |
) | |
const ( | |
fullcircle = math.Pi * 2 | |
topclock = -(math.Pi / 2) | |
smallest = -math.MaxFloat64 | |
largest = math.MaxFloat64 | |
stylefmt = "font-size:%.1fpx;font-family:sans-serif;text-anchor:middle;fill:%s" | |
cfmt = "fill:%s;fill-opacity:%.2f" | |
tfmt = "font-size:200%;baseline-shift:-33%" | |
lfmt = "stroke-opacity:.25;stroke-width:1;stroke:" | |
) | |
type deps struct { | |
name string | |
ndeps int | |
} | |
// vmap maps one range into another | |
func vmap(value, low1, high1, low2, high2 float64) float64 { | |
return low2 + (high2-low2)*(value-low1)/(high1-low1) | |
} | |
// polar converts polar to Cartesian coordinates | |
func polar(cx, cy, r, t float64) (float64, float64) { | |
return cx + r*math.Cos(t), cy + r*math.Sin(t) | |
} | |
// readata reads name, value pairs, and returns the min and max values | |
func readata(r io.Reader) ([]deps, float64, float64) { | |
var data []deps | |
var d deps | |
max := smallest | |
min := largest | |
scanner := bufio.NewScanner(r) | |
for scanner.Scan() { | |
t := scanner.Text() | |
fields := strings.Split(t, "\t") | |
if len(fields) < 2 { | |
continue | |
} | |
d.name = fields[0] | |
v, err := strconv.ParseFloat(fields[1], 64) | |
if err != nil { | |
d.ndeps = 0 | |
} | |
if v > max { | |
max = v | |
} | |
if v < min { | |
min = v | |
} | |
d.ndeps = int(v) | |
data = append(data, d) | |
} | |
return data, min, max | |
} | |
func main() { | |
var width, height float64 | |
var cmin, cmax, rpct, bop, fs float64 | |
var bg, fg, color, title string | |
flag.Float64Var(&width, "width", 1000, "canvas width") | |
flag.Float64Var(&height, "height", 1000, "canvas height") | |
flag.Float64Var(&cmin, "bmin", 7.0, "bubble min") | |
flag.Float64Var(&cmax, "bmax", 70.0, "bubble max") | |
flag.Float64Var(&rpct, "r", 30, "radius percentage") | |
flag.Float64Var(&bop, "op", 40, "opacity percentage") | |
flag.Float64Var(&fs, "fs", 10, "font size") | |
flag.StringVar(&bg, "bg", "white", "background color") | |
flag.StringVar(&fg, "fg", "black", "text color") | |
flag.StringVar(&color, "color", "lightsteelblue", "bubble color") | |
flag.StringVar(&title, "title", "", "title") | |
flag.Parse() | |
data, dmin, dmax := readata(os.Stdin) | |
midx, midy := width/2, height/2 | |
r := width * (rpct / 100) | |
t := topclock | |
step := fullcircle / float64(len(data)) | |
canvas := svg.New(os.Stdout) | |
canvas.Start(width, height) | |
canvas.Rect(0, 0, width, height, "fill:"+bg) | |
canvas.Gstyle(fmt.Sprintf(stylefmt, fs, fg)) | |
for _, d := range data { | |
cr := vmap(float64(d.ndeps), dmin, dmax, cmin, cmax) | |
cx, cy := polar(midx, midy, r, t) | |
tx, ty := polar(midx, midy, r+cmax+(fs*2.5), t) | |
canvas.Circle(cx, cy, cr, fmt.Sprintf(cfmt, color, bop/100)) | |
canvas.Text(tx, ty, d.name) | |
canvas.Text(cx, cy, fmt.Sprintf("%d", d.ndeps), tfmt) | |
canvas.Line(cx, cy, tx, ty, lfmt+fg) | |
t += step | |
} | |
canvas.Circle(midx, midy, r, "fill-opacity:.2;fill:"+color) | |
if len(title) > 0 { | |
canvas.Text(midx, midy, title, "font-size:300%") | |
} | |
canvas.Gend() | |
canvas.End() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment