| name | Visualize any data |
| description | Learn how to visualize data in a sustainable, accurate, and theme aware way. |
Whenever Claude is asked to visualize data, you must follow the steps below.
- Chart components live in the
src/components/Charts directory
- If you need a new core component type, create it in the
src/components/Charts directory. Inspect the existing components to see how to create a new one. Seperation of concerns is important. Make storybook stories for the new component.
echarts and echarts-for-react are the only libraries you can use to visualize data, and you must use them in the src/components/Charts directory.
- If you think the chart can be reusable, create it within the
src/components/* directory. For example, src/components/Ethereum/AttestationsByEntity.
Step 1: What Are You Trying to Show?
| Goal |
Best Chart Types |
Use When |
| Trend over time |
Line, Step, Area |
X-axis is temporal (time, slot, epoch, block) |
| Compare categories |
Bar, Column, Dot plot |
Comparing distinct groups |
| Show distribution |
Histogram, Box plot, Violin |
Understanding spread/shape of data |
| Show relationship |
Scatter, Bubble |
Correlation between two+ variables |
| Show composition |
Stacked bar, Pie, Treemap |
Parts of a whole |
| Show single value |
Number card, Gauge |
Key metric snapshot |
Step 2: Time-Series Data Patterns
Data Type Detection → Interpolation Method
| Data Characteristics |
Chart Config |
Example Metrics |
| Integer values only, non-negative |
Step chart: step: 'middle' |
blob count, transaction count, user count |
| Values hold between updates (state changes) |
Step chart: step: 'start' |
validator status, network state, config value |
| Continuous decimals, volatile |
Line: smooth: false |
gas price, latency, response time |
| Continuous decimals, trend focus |
Line: smooth: true |
moving averages, smoothed rates |
| Categorical states |
Step chart: step: 'start' + colors |
validator status, network state |
| Sparse/irregular events |
Scatter plot |
slashing events, errors, alerts |
Quick Decision Tree for Time-Series
Is data always integers?
├─ YES → Can you have 3.5 of this thing?
│ ├─ NO → Step chart (step: 'middle')
│ └─ YES → It's rounded data → Line chart
│
└─ NO → Does value stay constant between measurements?
├─ YES → Step chart (step: 'start')
└─ NO → Line chart (linear or smooth)
Step 3: Non-Temporal Data Patterns
Comparison Charts
| Scenario |
Chart Type |
Configuration Notes |
| Compare 3-10 categories |
Bar chart (horizontal if labels long) |
Start axis at zero |
| Compare 10+ categories |
Dot plot or Horizontal bar |
Easier to read labels |
| Compare across 2 dimensions |
Grouped bar |
Limit to 2-4 groups per category |
| Compare ratios/percentages |
Bar chart |
NOT pie chart |
| Compare ranges |
Box plot |
Shows min/max/quartiles |
Distribution Charts
| Data Type |
Chart Type |
Use When |
| Single continuous variable |
Histogram |
Show frequency distribution |
| Multiple distributions to compare |
Box plot or Violin plot |
Compare shapes across groups |
| Small dataset (<50 points) |
Dot plot or Strip plot |
Show individual points |
| Check for outliers |
Box plot |
Visualize quartiles and extremes |
Relationship Charts
| Scenario |
Chart Type |
Notes |
| Two continuous variables |
Scatter plot |
Look for correlation |
| Three variables (2 continuous + 1 size) |
Bubble chart |
Size = third dimension |
| Many overlapping points |
Hex bin or 2D histogram |
Shows density |
| Categorical + continuous |
Box plot or Violin |
Distribution per category |
Composition Charts
| Scenario |
Chart Type |
Use When |
| Parts of whole (2-5 parts) |
Donut chart |
Simple proportions |
| Parts of whole (6+ parts) |
Bar chart (NOT pie) |
Too many slices are unreadable |
| Hierarchical composition |
Treemap or Sunburst |
Nested categories |
| Composition over time |
Stacked area |
Show how parts change |
| 100% composition |
Stacked bar (100%) |
Compare proportions across groups |
Step 4: Universal Rules
Always Do:
| Rule |
Why |
How |
| Start Y-axis at zero for bars |
Human eyes judge area; starting elsewhere misleads |
Set yAxis: { min: 0 } |
| Use consistent colors |
Same metric = same color across charts |
Define color palette |
| Label axes clearly |
Include units (gwei, %, count, etc.) |
name: 'Gas Price (gwei)' |
| Limit colors per chart |
Too many colors = cognitive overload |
Max 5-7 distinct colors |
| Show data directly when <20 points |
Let users see actual values |
Add data labels or table |
| Use integers for count data |
Fractional counts don't exist |
yAxis: { minInterval: 1 } |
| Use filled step chart for count data |
Step chart is the most accurate way to represent count data |
step: 'middle', showArea: true, areaOpacity: 0.3, lineWidth: 2 |
| Disable forced max label |
Prevents awkward tick spacing (e.g., 1, 6, 11, 16, 21, 26, 31, 32) |
axisLabel: { showMaxLabel: false } in x-axis config |
Never Do:
| Mistake |
Why It's Bad |
Correct Approach |
| Smooth lines for count data |
Implies fractional values exist (e.g., 3.5 transactions) |
Use step chart |
| Pie charts with >5 slices |
Impossible to compare similar-sized slices |
Use bar chart |
| 3D charts |
Distorts perception, harder to read |
Use 2D always |
| Dual-axis with unrelated scales |
Can manipulate perception |
Only if truly related metrics |
| Too many series on one chart |
Becomes unreadable |
Split into multiple charts |
| Define your own color palette |
Use the useThemeColors hook to get the current theme colors |
const themeColors = useThemeColors(); |
Step 5: Common Metric Patterns
Pattern Library (Generic)
| Metric Type |
Example |
Chart |
Settings |
| Event count per period |
"transactions per block" |
Step |
step: 'middle', minInterval: 1 |
| Total/cumulative |
"total users", "cumulative revenue" |
Area or Line |
smooth: false or filled area |
| Rate/percentage |
"success rate", "utilization %" |
Line |
smooth: false, range 0-100 |
| Price/fee |
"gas price", "transaction fee" |
Line or Step |
Step if updates discrete, Line if continuous |
| Average |
"average latency", "mean value" |
Line |
smooth: true for trends |
| Status/state |
"server status", "order state" |
Step |
step: 'start', use colors |
| Distribution |
"transaction sizes" |
Histogram |
Bin count = √n as starting point |
| Comparison |
"revenue by product" |
Bar |
Horizontal if many categories |
| Correlation |
"price vs volume" |
Scatter |
Add trendline if useful |
Step 6: Data Volume Guidelines
| Data Points |
Approach |
Reasoning |
| < 20 points |
Show all detail, consider data labels |
Every point is visible |
| 20-100 points |
Show all, use tooltips |
Still manageable |
| 100-1,000 points |
Show all with interaction (zoom/pan) |
Need exploration tools |
| 1,000-10,000 points |
Aggregate OR downsample |
Too dense for individual points |
| > 10,000 points |
Must aggregate or use density visualization |
Line chart becomes solid blob |
Step 7: Interpolation Quick Reference
Step Chart: When to Use Which Direction
| Direction |
When to Use |
Example |
step: 'middle' |
Value REPRESENTS THE ENTIRE PERIOD |
Blob count in slot N, transactions in block N, gas used in epoch N |
step: 'start' |
Value HOLDS FROM this point until next change |
Validator status changed at slot N, config updated at block N |
step: 'end' |
Rarely used - value measured at end of period |
Uncommon - consider step: 'middle' instead |
Step Chart Visual Styling (IMPORTANT)
Always use light fills with visible lines for better readability and visual hierarchy:
{
step: 'middle',
showArea: true,
areaOpacity: 0.3, // Light 30% fill - NOT solid (1.0)
lineWidth: 2, // Visible 2px line - NOT hidden (0)
showSymbol: false,
}
Why this pattern:
- ❌ Heavy style (
areaOpacity: 1, lineWidth: 0) looks blocky, too visually dominant
- ✅ Light style (
areaOpacity: 0.3, lineWidth: 2) maintains data visibility while being easier to read
- The visible line helps trace values, while the light fill provides context without overwhelming
Smooth vs Linear for Continuous Data
| Use Case |
Setting |
When |
| Show volatility/precision |
smooth: false |
Raw measurements, user needs exact values |
| Show overall trend |
smooth: true |
Filtered/averaged data, focus on pattern |
| Moving average |
smooth: true |
Already smoothed data |
| Real-time fluctuations |
smooth: false |
Price tickers, live monitoring |
Step 8: Validation Checklist
Before finalizing any chart, ask:
Quick Decision Matrix
| I Have... |
I Want To... |
Use This |
| Counts over time |
Show exact counts per period |
Step chart with filled area (step: 'middle', showArea: true, areaOpacity: 0.3, lineWidth: 2) |
| Measurements over time |
Show trend |
Line (smooth) |
| Measurements over time |
Show volatility |
Line (linear) |
| Values that update occasionally |
Show when changes occur |
Step chart with filled area (step: 'start', showArea: true, areaOpacity: 0.3, lineWidth: 2) |
| Categories to compare |
Compare values |
Bar chart (horizontal if labels long) |
| Parts of a whole |
Show composition |
Donut (if ≤5) or Bar chart |
| Two variables |
Find correlation |
Scatter plot |
| One variable distribution |
Understand spread |
Histogram or Box plot (small dataset (<50 points) use Dot plot or Strip plot) |
| States over time |
Show transitions |
Step chart with filled area (step: 'start', showArea: true, areaOpacity: 0.3, lineWidth: 2) + colors |
Key Principles to Remember
- Match visualization to data nature - Don't force continuous interpolation on discrete data
- Simpler is better - Use the simplest chart that answers the question
- Context matters - Same data may need different viz for different questions
- Always label clearly - Include units, axis names, and legends
- Test readability - Can someone understand it in 5 seconds?