Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Chart design starts with a question, unit and visual encoding

Last updated: 7 Oct 20265 min read
tutorial
IntermediateBy AITrove Editorial

A chart is a visual comparison over defined observations; its marks and axes must preserve the quantity the reader is meant to compare.

Write the comparison

A receipt operations report might ask whether the share of reviews completed within 24 hours changed by channel. That is a rate by category and period, not a count of tickets. Record the population, numerator, denominator, time window and update cadence before picking a shape. Metric denominators belong in the chart contract because a change in eligibility can look like a change in performance.

Map quantities to marks

Position on a common scale is useful for comparing rates across channels; a bar chart makes zero a visible reference. Use a line only when adjacent points are connected by an ordered process such as time. A scatter plot asks whether two numeric quantities move together. A decorative shape must not imply a numerical relationship the dataset does not contain.

Preserve context

Show units, sample counts and the period cutoff. A rate can rise when a low-volume channel disappears even if no channel improves. Add a small companion table or labels with denominators when that composition matters. Aggregation grain determines what the visual mark actually represents. Never use a legend to hide a definition required to read the chart.

Specify a review fixture

Create one channel with 34 timely reviews out of 47 receipts and another with 18 out of 23. The second bar is higher despite its lower count. Ask a reviewer to state that distinction from the figure alone, then test an empty channel. Empty is missing evidence, not a zero percent service rate.

Implementation

python
def channel_completion_rate(timely_count, eligible_count):
    if eligible_count < 0 or timely_count < 0 or timely_count > eligible_count:
        raise ValueError("invalid receipt counts")
    return None if eligible_count == 0 else timely_count / eligible_count

channel_rates = {
    "portal": channel_completion_rate(34, 47),
    "email": channel_completion_rate(18, 23),
}

Performance and operating cost

Computing C channel rates is O(C) time and O(C) output space. Rendering cost grows with the number of marks, labels and interaction states; filter or aggregate only under a stated rule so the viewer can recover the denominator.

Common Mistakes

  • Do not substitute counts for rates when channel volumes differ.
  • Do not connect unordered categories with a line.
  • Do not render an empty denominator as a measured zero.

Read next

ai-data
data-visualization
Storage details