Data PreparationJune 27, 20269 min readDataViz Pro Team

    Working with JSON Data Structures for Visualization

    JSONdata preparationparsingvalidationnested data
    CSV has one shape: rows and columns. JSON has as many shapes as there are developers, and that flexibility is the reason a JSON file often takes longer to prepare for visualization than a spreadsheet ten times its size.
    Charting libraries want something specific: a flat list of records, or a list of labels paired with lists of numbers. Getting from an arbitrary API response to that shape is the real work. This article covers the transformations you will need most often, and the traps that quietly corrupt data along the way.

    Why JSON Needs More Preparation Than CSV

    A CSV parser can make strong assumptions. The first row is probably a header, every subsequent row has the same fields, and every value is a string until you decide otherwise. Those constraints are limiting but they make the output predictable.
    JSON offers no such guarantees. Values can be nested to arbitrary depth. Two records in the same array can have different keys. A field can be a number in one record and a string in the next. Arrays can hold objects, primitives, or more arrays. An empty result might be an empty array, a null, or an omitted key entirely.
    None of this is a flaw in JSON. It is a consequence of JSON being a general serialization format rather than a tabular one. It simply means the shaping step is yours to write.

    The Target Shape: A Flat Array of Records

    The most useful intermediate form is an array of flat objects, where every object has the same keys and every value is a primitive. From that shape, deriving chart data is mechanical: pick one field as your label axis, pick one or more numeric fields as your series, and map over the array.
    This is worth stating explicitly because it changes how you approach an unfamiliar payload. You are not asking "how do I chart this JSON," you are asking "how do I get this JSON into a flat array of records." The second question has a small number of standard answers.

    Handling the Common Wrappers

    Most APIs do not return a bare array. They wrap it: a data key, a results key, an items key, a records key, or a nested combination such as response then rows. Some return a single object when there is one result and an array when there are several.
    Write your ingestion step to normalize all of these into an array before doing anything else. Check for an array at the top level, then look inside the common wrapper keys, then fall back to treating a lone object as a single-element array. This one function eliminates a whole category of confusing failures where a chart renders empty because the data was one level deeper than expected.

    Flattening Nested Objects

    Nested objects are the most common obstacle. A record describing a sale might contain a customer object with name and region inside it, and a totals object with gross and net.
    The standard fix is path flattening: walk the object recursively and produce keys that join the path with a separator, so customer then region becomes a single field. Two details matter. First, choose a separator that will not appear in your real keys, and be consistent about it, because those flattened names become your column labels and your users will select them from a dropdown. Second, decide what to do when a nested value is itself an array, since that cannot be flattened into a single column without either joining it into a string or expanding the record into several rows.
    Depth is worth limiting. Flattening five levels deep produces column names nobody can read. In practice, two or three levels covers almost every real payload, and anything deeper usually signals that you want a different part of the document.

    Arrays of Arrays and Coordinate Pairs

    Some data arrives as arrays of primitives rather than objects. A scatter series is often a list of two-element arrays, and a heatmap cell is often a three-element array of column index, row index, and value.
    These are already close to what charting libraries want, so resist the urge to convert them into objects and back. What you do need is validation: confirm that every inner array has the expected length, that the values are numbers rather than numeric strings, and that indices fall within the bounds of your axis categories. A single malformed pair can throw off an entire heatmap or silently drop a point.
    Geographic data deserves special care here. Different sources order coordinate pairs differently, with some using latitude then longitude and others the reverse. Getting this backwards produces a map where every point lands in the wrong hemisphere, which is at least obvious. More insidious is a dataset where most points are valid and a handful have swapped order, producing a few outliers that look like real anomalies.

    Hierarchical Data for Treemaps and Sunbursts

    Treemaps and sunburst charts are the exception to the flat-array rule. They consume nested structures directly, typically a node with a name, an optional value, and an optional array of children.
    If your source data is already hierarchical, you may only need to rename keys. If it is flat with a parent reference or a path string, you will need to build the tree: group records by their parent key, then recursively attach children, or split path strings on a separator and insert each record at the appropriate depth.
    Two rules prevent most problems with hierarchies. Leaf nodes should carry values and parent nodes should not, because most libraries sum children automatically and a parent with its own value will be double counted. And every node needs a name that is unique among its siblings, since duplicate sibling names collapse into one wedge.

    Type Coercion Traps

    This is where data silently changes meaning. A few specific cases account for most incidents.
    Numeric strings are the most common. A field arriving as a quoted number will sort lexicographically rather than numerically, placing one hundred before ninety. Coerce numeric columns explicitly rather than relying on the charting library.
    Empty values are the most dangerous. Converting an empty string or a null to zero turns "we did not measure this" into "the value was nothing," which changes every average and every total. Keep missing values missing, and let the chart render a gap.
    Large integers exceeding the safe range for double-precision floats lose precision silently. Identifiers and timestamps in nanoseconds are the usual victims. Keep these as strings unless you need to do arithmetic on them.
    Booleans and dates each have their own hazard. A boolean coerced to a number is fine if intentional and confusing if accidental. A date string without timezone information will be interpreted according to the runtime's local zone, which means the same file produces different charts on different machines.

    Working With Large Files in the Browser

    A privacy-first tool parses data locally, which means the browser's memory is your budget. A file that is comfortable on a server can freeze a tab.
    Parse incrementally where the format allows it, so you can show progress and abort cleanly rather than blocking the main thread. Keep only what you need: if a payload has forty fields and the chart uses three, project down early and let the rest be garbage collected. Downsample for display, because a chart with fifty thousand points on a thousand-pixel axis is drawing dozens of points per pixel and none of them are visible. Aggregate to the resolution the viewer can actually perceive, and keep the full dataset available for export.
    For anything genuinely large, move parsing into a worker so the interface stays responsive. The complexity cost is real, but a frozen tab reads as a broken application.

    Validating Before You Chart

    The cheapest bug to fix is the one caught at ingestion. A short validation pass before rendering pays for itself immediately.
    Confirm the payload produced a non-empty array. Confirm every record shares the same key set, and report the ones that do not rather than silently rendering partial data. For each field the user selected as numeric, count how many values failed to parse and surface that count instead of hiding it. Check that your label field has no duplicates, because duplicate labels merge or overwrite depending on the library. Verify that coordinates fall within valid latitude and longitude ranges.
    Report these findings to the user in plain language. "Loaded 4,812 rows; 37 values in the revenue column could not be read as numbers" is far more useful than a chart with an unexplained dip. Users trust a tool that tells them what it could not do far more than one that quietly guesses.