Chart Library: Building Birst's Visualization System from Scratch
Designing a complete chart library for an enterprise BI platform, from the minimum data requirements of each chart type through the math of how charts render, configure, and degrade at scale.
Role: Lead chart designer at Birst throughout my tenure
Timeline: From my earliest days at the company through 2025, scaling as Birst transitioned from licensed charting engines to a fully in-house rendering system
Team: Primary designer across nearly every chart type; partnered closely with chart rendering engineers, PMs, and my manager; later taught the process to another designer who contributed a couple of charts
Scope: Chart concepts, minimum data requirements, sizing and spacing formulas, configuration panels, edge-case behavior, and degraded states
Status: Every chart type I designed is still live in the product today, and the library was extended into Infor's chart builder based on Birst's Visualizer
The Problem
When I joined Birst, the charting library was in its early days. The basics were covered, including bar, line, pie, and scatter, but there was significant room to grow, and customer expectations for enterprise BI were already running ahead of what we could deliver. I still remember when my manager designed the bubble chart, and the addition of a size measure felt like a meaningful step forward. That was the starting point.
Over the next decade, the library expanded significantly. Roughly three-quarters of the chart types Birst ships today didn't exist when I started. They were added one at a time, and I designed nearly all of them, from the familiar (bar, column, line, area) to the specialized (gauge, waterfall, heat map, geomap, histogram, funnel, pyramid, tree map, doughnut).
A few forces drove the expansion:
Competitive parity. Tableau, Power BI, and others had mature chart libraries. If a specific chart type wasn't in Birst's library, every deal got harder.
Customer requests accumulated over time, including waterfall for financial analysis, geomap for logistics, funnel for conversion tracking, heat map for density analysis, and gauge for KPI-centered dashboards.
Moving off licensed charting engines. Birst started with licensed third-party chart libraries. The decision to build a fully in-house rendering engine meant a slow phase-out where every chart had to be re-evaluated, re-designed, and re-shipped under the new system. A multi-year project running in parallel with ongoing feature work.
Extending into Infor. Later in my tenure, Birst's charts were adapted into Infor's broader chart builder, which meant redesigning the configuration flows to fit a different product context while preserving what made them powerful in Birst.
My Process
Early on, my manager and I developed a process for how each new chart moved from blank page to shipped product. I later taught it to another designer who contributed a couple of charts to the library. Each step below also produced specific artifacts that engineering needed to build the chart correctly.
Step 1 - Minimum viable chart: Start with one attribute and one measure and design what the chart looks like at its bare minimum. For pie with months and profit, that's twelve colored slices. This step produced the minimum data requirements, expressed in the UI through "Add attribute" or "Add measure" prompts on the data buckets.
Step 2 - Bucket behavior: Which of Birst's Visualizer buckets (attributes, measures, color, trellis, filter, sort) apply to each chart, and what happens when users add things to each? For pie, adding a color attribute doesn't make sense because the chart already colors itself, so the color bucket gets hidden entirely. For bar, dropping something into color turns the bars from default-blue to category-colored.
Step 3 - Complexity, one dimension at a time: Multiple measures? Multiple attributes? For pie, multiple measures weren't allowed, so I documented that the option should be disabled. For bar, multiple measures produced grouped or stacked variations. I'd work through every bucket and specify each interaction. Charts with complex options (histogram bin controls, doughnut hole sliders, gauge segment definitions) also needed their own dedicated configuration panels, designed at this stage.
Step 4 - Extreme stress tests: Push the chart until it broke. Every bucket filled with as many columns as possible. Hundreds of data points. The goal was finding the limits where the chart stopped being legible, then designing the guardrails that kept users from getting there. Those limits became disabled-bucket rules that told users when they'd hit a maximum. This step also produced failure-state notifications, which appeared at the top of charts that couldn't render with guidance for what to change.
Step 5 - Render-time details: Once the chart worked at its extremes, I'd specify the render-time behavior: where labels went when they fit inside elements versus when they needed leader lines, and how the four degraded states (standard, reduced, basic, minimal) stripped elements progressively as users chose to simplify. Minimal was nearly an abstract silhouette of the chart.
Step 6 - Specify the render math: The final step was crossing into formula territory, which I'll get into in the next section.
Most charts took about two weeks of mockups plus a few weeks of engineering to build. Gauge, because of its configuration complexity, took me closer to two months of design and engineering months beyond that.
Working with engineering: the math of a chart
Designing a chart library at depth means specifying the math of how charts render, or engineers will make those decisions themselves, and when engineers make those decisions, charts stop feeling designed.
Examples of what I specified with engineering:
Bar width as a function of available canvas space and gap ratios, scaled for grouped and stacked variants
Line and dot sizing (lines one unit thick, dots two units), shrinking proportionally as density increased so users could still see each line
Legend and tick positioning standardized across the library so that switching chart types didn't feel like landing in a different product
Axis behavior with multiple display modes (angled, stepped, every-other, and others) selected automatically based on label length and available width
These decisions are documented on an internal wiki that has been the golden standard for how Birst charts render from the beginning of the library's development.
The gauge segment-boundary decision
Gauges need segmented ranges. For a profit gauge, segments like "Problem," "Below Target," "Close to Target," "Target Hit," and "Bonuses for Everyone." The question is how users define those ranges.
The obvious approach, which everyone initially assumed I'd use, is to ask users how wide each segment should be. I chose a different approach. The inputs for each segment sat directly on the dividing lines between segments, so each number represented the endpoint of one segment and the starting point of the next. Users defined boundaries, not sizes.
PMs and my manager pushed back at first, but once the team saw why it mattered, the room collectively clicked. Two reasons it worked: gauges that go negative work correctly (you can't express negative values with size-based inputs), and the math stays clean for users (no mental addition, you just place a boundary at a value you care about).
The feature shipped, and gauge went on to be one of the most popular chart types in the library.
Deep dives - two charts worth featuring
Gauge: configurability without overwhelm
Gauge had the most configuration options of any chart in the library because it was the most semantically flexible. The same gauge could track anything from a CEO-facing revenue target to a warehouse's inventory levels.
Configurations included angular span (full-circle to fan-shaped, selectable from preset angles), hole size, segment boundaries (the input model above), an optional overflow segment for when values exceeded the user-defined max, label positioning (center, above, below, left, right) with logic for when a small hole size forced labels to reposition automatically, and display value toggles. When overflow wasn't toggled on, the final segment scaled up infinitely as values grew past the target, so the gauge kept showing the right information at a glance.
Configuration happened through a well-organized side panel, giving users full control over a genuinely flexible chart type.
Doughnut: the "Other" slice
Doughnut had a subtle design problem. Too many slices made it illegible. For a category with 30+ values, a doughnut became a messy ring of tiny slivers that told no story.
The solution was an "Other" slice. Users could specify how many slices they wanted displayed at full detail, and everything beyond that count automatically folded into a single "Other" slice with a hover tooltip that displayed everything inside it. No data was hidden, just summarized. The pattern later applied to pie charts too.
Designing for edge cases
Enterprise BI data is messy, and a chart library lives or dies based on how it handles edge cases.
Missing data became dotted lines in time-series charts, so users could see gaps rather than assume zero values. Layer ordering was solved with a simple layer-order control after we discovered that area could hide lines in combo charts. Predictive indicators let users forecast future values based on trend analysis, with the forecasted segment rendered visually differently from historical data. Failure-state notifications appeared at the top of charts that couldn't render, explaining why and suggesting what to change. No silent failures.
One stress test worth mentioning, I explored whether gauges could support multiple measures at once. The mockups got interesting, but a gauge is semantically a single-value display. Forcing multi-measure undermined its core purpose. The right answer was "don't add the feature," which is its own kind of design decision.
Outcome
Every chart type I designed is still live in the product today.
Gauge became a favorite among executive and logistics users, used to track revenue targets, inventory levels, customer-satisfaction metrics, and more.
Charts were extended into Infor's chart builder with redesigned configuration flows fit to the new product context while preserving the underlying chart logic. The library now reaches a much wider user base than Birst alone.
Sizing and rendering rules became company standard. My mockups are documented on Birst's internal wiki as the reference for how charts should render, and every new chart added after I stopped being the primary designer followed the patterns I established.
Reflection
Designing a chart library changed how I read data. After spending years designing charts, I see the design decisions inside every chart I encounter, from articles that use a chart type that's wrong for their data to dashboards that would tell a clearer story with a different visualization.
Chart design also taught me the difference between design craft and design specification. On a one-off screen, you can iterate until it feels right. On a chart library, you have to specify behavior that will apply thousands of times across inputs you'll never see directly. The formulas have to work at the extremes. The configuration options have to make sense for users who know far more about their data than you ever will.