A chart is a visual comparison over defined observations; its marks and axes must preserve the quantity the reader is meant to compare.
Chart design starts with a question, unit and visual encoding
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
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.
