Build a complexity city
The default city is sized by lines of code and member count. To make complexity the thing you see, bind it to the height channel and move size to the footprint.
Before you start: a model.jsonl from an extractor that emits measures. The
Java extractor emits sloc per type and invocable and cyclomatic per
invocable.
Bind the channels
codegraph city model.jsonl --height sum:cyclomatic --footprint loc --serve--serve lays the city out and opens the viewer on port 4177. To keep the
artifact instead:
codegraph city model.jsonl --height sum:cyclomatic --footprint loc \
--internal-only --out complexity-city.jsonTwo metric families are available:
| Form | Reads |
|---|---|
degree, fanIn, fanOut, fields, loc, members, methods, one |
built-ins computed from the graph and the anchors |
attribute:<key> |
the type’s own measure with that key |
sum:<key> |
that measure summed over everything that folded into the building |
Complexity wants sum:. Cyclomatic complexity is measured per invocable and
a building is a type, so attribute:cyclomatic would find nothing on the type
itself while sum:cyclomatic adds up its methods.
An unknown name is refused rather than silently replaced:
codegraph: unknown metric source: complexity. Known sources: loc, members, methods, fields, fanIn, fanOut, degree, one; or attribute:<key> / sum:<key>.Choose the scales
codegraph city model.jsonl --height sum:cyclomatic --height-scale sqrt \
--footprint loc --footprint-scale sqrt --internal-only --out city.json--height-scaledefaults tolinear: a tower twice as tall holds twice the measure. Switch tosqrtorlogwhen one outlier flattens everything else.--footprint-scaledefaults tosqrt, and that default is the one to leave alone: the metric maps onto the side, sosqrtmakes the base area proportional to it, which is what a reader comparing plans assumes.logislog1p, so a measured zero renders as zero rather than at negative infinity.
Whichever you used is recorded in the artifact:
{ "channel": "height", "metric": "sum:cyclomatic", "unit": "cyclomatic",
"scale": "sqrt", "range": { "min": 1, "max": 40 },
"domain": { "min": 1, "max": 12 }, "unmeasured": 0 }Carry the numbers you want to read but not see
--carry measures extra metrics onto every building without binding them to a
channel. They show up in the details panel and in building.metrics.
codegraph city model.jsonl --height sum:cyclomatic --footprint loc \
--carry members,fanIn --internal-only --out city.json"metrics": { "fanIn": 0, "loc": 10, "members": 5, "sum:cyclomatic": 2 }Read the unmeasured warning
A building the metric could not measure is drawn at the channel minimum and counted, never faked to zero:
warning: height is unmeasured on 18 buildings (metric sum:cyclomatic) — those are drawn at the channel minimum, not at zero.If that number is large, then check what the buildings are. Stubs carry no
measures at all, so --internal-only usually removes the whole warning. If it
survives on corpus types, the extractor did not measure them.