Brief Reminder: We are building Vizstack: a stack of programming tools that make code visual, simplifying complexity by rendering any data structure from any program in any language. Consider the last time you encountered an unfamilar codebase or had to debug a nasty algorithm. We believe that this code complexity can be tamed with better developer tools. We believe the time is right to reinvent the programming experience, so that developers can build bigger, faster, safer, and more intricate software.
To learn more, visit the home page.
After getting our core visualization integrated to the vz-logger
app, we were able to play around and gather lessons for the second iteration. The first iteration worked and was interactive, but wasn't very good looking:
- There were too many borders, creating a "pyramid of doom" aesthetic that complicated even simple data structures.
- The padding created many parallel lines, which causes you to lose your sense of context.
- The motifs (e.g. "[" and "]" at the start and end of lists) were out of place. They went against the information hierarchy, and made the viewers too tall.
- In general, the visualizations weren't very compact. Programmers have gotten used to seeing very compact (albeit limited) textual print statements in the terminal. We needed to match that as much as possible.
So we decided to do a redesign. We made the borders collapse on each other, and placed the motifs in more natural spots. All together, we made many small tweaks that we hope will add up to a more appealing display:
We'll be improving them in further iterations, as we receive more user feedback!
Demo: https://vizstack.github.io/nodal/docs/
There are a lot more features shown in the Storybook demo now, including edge orientation and alignment constraints. The big thing we worked on was improving the layout algorithm for large, long graphs -- the kind that's crucial for displaying computational graphs in machine learning, distributed systems, and software architecture. We tackled the "limp noodle" problem, and have a better graph now (right) compared to last week (left):
One super exciting thing we're tackling in nodal
-- our modular graph layout engine -- is different node shapes. (Check out our list of features for a full overview of why nodal
will be different from all the other major open-source graph layout libraries).
Shapes are hard! Game developers that work with low-level graphics and physics engines will know just how tricky it is to get different shapes to interact and constrain each other. For most graph applications, we think that convex shapes are pretty good, so have designed a Shape
API that's works for things like rectangles, circles, ellipses, diamonds, parallelograms, and trapezoids.
There's too many details to cover here, but if you're interested, check out this tutorial on video game physics which we found super useful.
We designed a minimal but powerful API for convex shapes that allow collision detection and containment constraints:
Simple nodes of different shapes just need to not overlap with each other. But compound nodes (nodes with children) need to be able to contain their children. (Check out this example of compound nodes with rectangular shapes.)
To do this, requires doing a bit of geometry:
After deriving the appropriate mathematical relations in our notebook, we implemented them in code for the Rectangle
and Circle
subclasses.
"Orthogonal Connector Routing," Wybrow et al., 2009: For vizstack
, we need our graphs to be visually appealing in order to effectively communicate complex information. (There's a reason that subway maps look the way they do!) One feature of good graphs are orthogonal edges that route around obstacles on their way from source to target. We want to integrate an edge routing post processing step into nodal
so have been reading up on how to to it. This paper discusses a 3 stage layout process that involves: (1) constructing an orthogonal visibility graph by intersecting horizonal and vertical lines eminating from port points on nodes, (2) finding the optimal connector routes using A* with a weighting that biases for more appealing aesthetics, and (3) nudging and spacing lines that are routed through the same segments.