external/ag-shared/prompts/skills/example/ag-charts/features/axes.md
Apply: 6 minutes, Impact: VERY HIGH β STRONGLY RECOMMENDED
// Add visual depth with alternating background bands
axes: {
y: {
type: 'number', // β οΈ REQUIRED - axes.*.type must always be specified
position: 'left',
gridLine: {
style: [
{
// Don't set stroke/fill colors - theme handles them
strokeWidth: 1,
lineDash: [2, 2],
},
{
// Alternating bands - theme provides appropriate colors
strokeWidth: 0, // No grid line
},
],
},
},
};
Apply: 4 minutes, Impact: HIGH β RECOMMENDED
// Add interactive hover highlighting to axis bands
axes: {
x: {
type: 'category', // β οΈ REQUIRED - always specify axes.*.type
position: 'bottom',
bandHighlight: {
enabled: true,
// Don't set fill - theme provides appropriate highlight color
},
},
};
Apply: 5 minutes, Impact: High
// Define formatters once at the root level
const options = {
formatter: {
y: ({ value }) => `$${(value / 1000).toFixed(0)}K`, // Applied to all y-values
x: ({ value }) =>
value.toLocaleDateString('en-US', {
month: 'short',
year: 'numeric',
}), // Applied to all x-values (dates)
},
axes: {
y: {
type: 'number', // β οΈ REQUIRED field
position: 'left',
// Automatically uses root formatter.y
},
x: {
type: 'time', // β οΈ REQUIRED field
position: 'bottom',
// Automatically uses root formatter.x
},
},
series: [
// All series labels and tooltips also use root formatters
],
};
axes: {
y: {
type: 'number', // β οΈ REQUIRED field
position: 'left',
label: {
// Only override if this axis needs different formatting
formatter: (params) => `${params.value}%`, // Specific to percentage axis
},
},
};
Apply: 6 minutes, Impact: MEDIUM
// Style specific axis labels based on value or position
axes: {
y: {
type: 'number', // β οΈ REQUIRED field
position: 'left',
label: {
itemStyler: (params) => {
const { value, formattedValue } = params;
// Emphasize baseline (0) or target values
if (value === 0) {
return {
fontWeight: 'bold',
// Don't set color - theme handles contrast
};
}
// Highlight target thresholds
if (value === 100000) {
return {
fontWeight: 'bold',
fontSize: 14, // Slightly larger for targets
// Don't set color - theme handles it
};
}
return {}; // Default styling for other labels
},
},
},
};
Apply: 6 minutes, Impact: HIGH
axes: {
x: {
type: 'time',
position: 'bottom',
label: {
formatter: ({ value }) => [
{ text: value.toLocaleString('en-US', { month: 'short' }) },
{ text: ` ${value.getFullYear()}`, opacity: 0.6 },
],
},
title: {
formatter: ({ defaultValue }) => [
{ text: defaultValue, fontWeight: 'bold' },
{ text: ' (local time)', opacity: 0.7 },
],
},
},
};
TextOrSegments arrays to combine emphasis and supporting text without HTML overlays.Apply: 5 minutes, Impact: MEDIUM
axes: {
y: {
type: 'number',
position: 'left',
crossAt: {
value: 0,
sticky: true, // Keep the horizontal axis locked to domain 0
},
},
x: {
type: 'time',
position: 'bottom',
crossAt: {
value: new Date('2025-01-01'),
},
},
};
nice: falseApply: 2 minutes, Impact: Medium
// For continuous axes (number, time, log), control axis range padding
axes: {
y: {
type: 'number', // β οΈ REQUIRED field
position: 'left',
nice: false, // β
Data fits exactly to min/max (no padding)
// Default nice: true adds padding for round numbers
},
x: {
type: 'time', // β οΈ REQUIRED field
position: 'bottom',
nice: false, // β
Time scale starts/ends at data boundaries
// Useful for showing exact date ranges
},
};
nice: falsenice: true (default)New Nov 2024 β’ Apply: 3 minutes β’ Impact: MEDIUM
axes: {
y: {
type: 'number', // β οΈ REQUIRED field
position: 'left',
preferredMin: 0, // Soft lower bound - can be extended by data or nice
preferredMax: 100, // Soft upper bound - can be extended by data or nice
// These are "preferred" values that will be used unless:
// - Data extends beyond them
// - nice: true rounds beyond them
},
}
Difference from min/max:
min/max: Hard bounds that take priority - axis will never go beyond these valuespreferredMin/preferredMax: Soft bounds that can be extended by data or nice optionWhen to use preferredMin/preferredMax:
nice: true should be able to round beyond your preferred boundsWhen to use min/max instead:
Apply: 10 minutes, Impact: HIGH
axes: {
y: {
type: 'number', // β οΈ REQUIRED field
position: 'left',
nice: false, // β
Data fits snugly to scale (no extra padding)
title: {
text: 'Revenue ($M)', // β Don't set fontSize
// Theme handles all font properties
},
label: {
// β Don't set fontSize - theme handles it
formatter: (params) => `$${params.value}M`,
},
gridLine: { style: [{ lineDash: [2, 3] }] }, // Don't set stroke color
tick: { width: 1 }, // Don't set stroke color
},
x: {
type: 'category', // β οΈ REQUIRED field
position: 'bottom',
bandHighlight: {
enabled: true,
// Don't set fill - theme provides the color
},
label: {
rotation: 45, // Angle labels if really needed
// β Don't set fontSize
},
},
};
Apply: 6 minutes, Impact: HIGH β RECOMMENDED
// Professional alternating bands - STRONGLY consider using this!
gridLine: {
style: [
{
// Primary grid lines
strokeWidth: 1,
lineDash: [3, 3],
// Don't set stroke - theme handles grid colors
},
{
// Alternating background bands for visual clarity
strokeWidth: 0, // No line, just fill
// Don't set fill - theme provides appropriate band colors
},
];
}
// Even more sophisticated with multiple styles:
gridLine: {
style: [
{ strokeWidth: 2 }, // Major grid lines (every 5th)
{ strokeWidth: 0 }, // Subtle bands
{ strokeWidth: 1, lineDash: [2, 2] }, // Minor grid lines
];
}
// BEST PRACTICE: Combine with bandHighlight for maximum impact
axes: {
x: {
type: 'category', // β οΈ REQUIRED field
position: 'bottom',
gridLine: {
style: [
{ strokeWidth: 1, lineDash: [2, 2] },
{ strokeWidth: 0 }, // Background bands
],
},
bandHighlight: {
enabled: true,
},
},
};
Axis bands dramatically improve chart readability by:
Creates a layered visual experience where:
axes: {
y: {
type: 'number',
position: 'left',
label: {
formatter: (params) => `$${(params.value / 1e6).toFixed(1)}M`,
},
gridLine: {
style: [
{ strokeWidth: 1, lineDash: [2, 2] },
{ strokeWidth: 0 }, // Bands
],
},
},
};
Apply: 2 minutes, Impact: VERY HIGH for financial data ββ INDUSTRY STANDARD
For financial and monetary data, follow standard industry conventions:
axes: {
y: {
type: 'number',
position: 'right', // β
PREFERRED for price/monetary values
label: {
formatter: (params) => `$${(params.value / 1e6).toFixed(1)}M`,
},
title: {
text: 'Price ($)',
},
gridLine: {
style: [
{ strokeWidth: 1, lineDash: [2, 2] },
{ strokeWidth: 0 }, // Background bands
],
},
},
x: {
type: 'time',
position: 'bottom',
// Date/time axis configuration
},
};
β
Stock prices, currency values, trading data
β
Financial performance metrics (revenue, profit)
β
Economic indicators and market data
β
Any chart where the primary value represents money/price
β
Non-financial numerical data (counts, percentages, measurements)
β
Charts with mixed data types where money is secondary
β
Legacy charts that users are accustomed to reading on the left
axes: {
x: {
type: 'time',
position: 'bottom',
nice: false, // Exact date range
label: {
formatter: (params) => {
const date = params.value;
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
});
},
},
},
};
axes: {
x: {
type: 'category',
position: 'bottom',
bandHighlight: { enabled: true },
label: {
rotation: 45, // Only if labels overlap
autoRotate: true, // Automatic rotation when needed
},
},
};
New Nov 2024 β’ Apply: 4 minutes β’ Impact: MEDIUM
axes: {
x: {
type: 'grouped-category',
position: 'bottom',
label: {
wrapping: 'on-space', // 'always' | 'hyphenate' | 'on-space' | 'never'
truncate: true, // Add ellipsis when text is truncated
},
},
}
Wrapping Options:
'always': Always wrap text to fit within maxWidth'hyphenate': Similar to 'always', but inserts a hyphen (-) if forced to wrap mid-word'on-space' (default): Only wrap on whitespace. If no space available and maxWidth can't be satisfied, text will be truncated'never': Disable text wrappingTruncate:
truncate: true, text that exceeds available space will be truncated with an ellipsis (...)wrapping - if wrapping can't fit the text, truncation appliesUse Cases:
Radial and polar charts can quickly become cluttered. Follow these guidelines:
// β AVOID - Too many axis elements in radial charts
axes: {
angle: {
type: 'angle-category',
gridLine: { enabled: true, style: [...] }, // Often clutters
label: { enabled: true, formatter: ... }, // Can overlap
crossLines: [...], // Usually overkill
},
radius: {
type: 'radius-number',
gridLine: { enabled: true }, // Multiple circles can overwhelm
label: { enabled: true }, // Often unnecessary
},
};
// β
BETTER - Minimal, focused approach
axes: {
angle: {
type: 'angle-category',
gridLine: { enabled: false }, // Clean look
label: {
enabled: true, // Only if essential
// Keep labels short to avoid overlap
},
},
radius: {
type: 'radius-number',
gridLine: {
enabled: true,
style: [{ strokeWidth: 1 }], // Subtle single style
},
label: { enabled: false }, // Often not needed
},
};
type: This is a required field for all axes