Overview
Pie charts are perfect for displaying proportional data and percentages. Cristalyse supports both traditional pie charts and donut charts with smooth animations, customizable styling, and interactive features.
Basic Pie Chart
Create a simple pie chart to show proportions:
final marketData = [
{'company': 'Apple', 'marketShare': 28.5},
{'company': 'Samsung', 'marketShare': 22.1},
{'company': 'Google', 'marketShare': 15.8},
{'company': 'Xiaomi', 'marketShare': 12.3},
{'company': 'Others', 'marketShare': 21.3},
];
CristalyseChart()
.data(marketData)
.mapping(
pieValue: 'marketShare',
pieCategory: 'company',
)
.geomPie(
outerRadius: 150,
showLabels: true,
showPercentages: true,
)
.theme(ChartTheme.defaultTheme())
.build()
Donut Chart
Create a donut chart with a hollow center:
final salesData = [
{'region': 'North America', 'sales': 450000},
{'region': 'Europe', 'sales': 320000},
{'region': 'Asia Pacific', 'sales': 280000},
{'region': 'Latin America', 'sales': 150000},
{'region': 'Middle East', 'sales': 100000},
];
CristalyseChart()
.data(salesData)
.mapping(
pieValue: 'sales',
pieCategory: 'region',
)
.geomPie(
outerRadius: 180,
innerRadius: 80, // Creates donut effect
showLabels: true,
showPercentages: false,
)
.theme(ChartTheme.defaultTheme())
.build()
Exploded Pie Chart
Create separation between slices for emphasis:
final budgetData = [
{'category': 'Development', 'amount': 450000},
{'category': 'Marketing', 'amount': 280000},
{'category': 'Operations', 'amount': 320000},
{'category': 'Sales', 'amount': 180000},
];
CristalyseChart()
.data(budgetData)
.mapping(
pieValue: 'amount',
pieCategory: 'category',
)
.geomPie(
outerRadius: 160,
explodeSlices: true,
explodeDistance: 15,
showLabels: true,
showPercentages: true,
)
.theme(ChartTheme.defaultTheme())
.build()
Styling Options
Custom Colors
Override default color mapping:
CristalyseChart()
.data(data)
.mapping(
pieValue: 'value',
pieCategory: 'category',
)
.geomPie(
outerRadius: 150,
colors: [
Colors.blue,
Colors.green,
Colors.orange,
Colors.red,
Colors.purple,
],
)
.build()
Stroke Styling
Add borders to pie slices:
CristalyseChart()
.data(data)
.mapping(
pieValue: 'value',
pieCategory: 'category',
)
.geomPie(
outerRadius: 150,
strokeWidth: 2.0,
strokeColor: Colors.white,
showLabels: true,
)
.build()
Custom Label Styling
Customize label appearance:
CristalyseChart()
.data(data)
.mapping(
pieValue: 'value',
pieCategory: 'category',
)
.geomPie(
outerRadius: 150,
showLabels: true,
showPercentages: true,
labelRadius: 180,
labelStyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
)
.build()
Animation Options
Progressive Slice Animation
Slices animate in sequence:
CristalyseChart()
.data(data)
.mapping(
pieValue: 'value',
pieCategory: 'category',
)
.geomPie(
outerRadius: 150,
animationDuration: Duration(milliseconds: 1500),
)
.animate(
duration: Duration(milliseconds: 1500),
curve: Curves.easeInOutCubic,
)
.build()
Custom Start Angle
Control where the pie starts:
CristalyseChart()
.data(data)
.mapping(
pieValue: 'value',
pieCategory: 'category',
)
.geomPie(
outerRadius: 150,
startAngle: -pi / 2, // Start at top (12 o'clock)
)
.build()
Real-World Examples
E-commerce Sales by Category
final ecommerceData = [
{'category': 'Electronics', 'sales': 2850000, 'color': Colors.blue},
{'category': 'Clothing', 'sales': 1920000, 'color': Colors.green},
{'category': 'Home & Garden', 'sales': 1450000, 'color': Colors.orange},
{'category': 'Books', 'sales': 890000, 'color': Colors.red},
{'category': 'Sports', 'sales': 720000, 'color': Colors.purple},
];
CristalyseChart()
.data(ecommerceData)
.mapping(
pieValue: 'sales',
pieCategory: 'category',
)
.geomPie(
outerRadius: 180,
innerRadius: 60,
showLabels: true,
showPercentages: true,
labelRadius: 220,
strokeWidth: 3,
strokeColor: Colors.white,
explodeSlices: true,
explodeDistance: 8,
)
.theme(ChartTheme.defaultTheme())
.build()
Project Time Allocation
final projectData = [
{'phase': 'Planning', 'hours': 120},
{'phase': 'Development', 'hours': 480},
{'phase': 'Testing', 'hours': 160},
{'phase': 'Deployment', 'hours': 80},
{'phase': 'Documentation', 'hours': 60},
];
CristalyseChart()
.data(projectData)
.mapping(
pieValue: 'hours',
pieCategory: 'phase',
)
.geomPie(
outerRadius: 160,
showLabels: true,
showPercentages: true,
labelStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
),
)
.theme(ChartTheme.defaultTheme())
.build()
Advanced Features
Interactive Pie Charts
Add hover effects and click handling:
CristalyseChart()
.data(data)
.mapping(
pieValue: 'value',
pieCategory: 'category',
)
.geomPie(
outerRadius: 150,
showLabels: true,
onSliceClick: (data, index) {
print('Clicked slice: ${data['category']}');
},
)
.interactions(
enableHover: true,
enableClick: true,
)
.build()
Responsive Sizing
Automatically adjust based on container size:
LayoutBuilder(
builder: (context, constraints) {
final radius = math.min(constraints.maxWidth, constraints.maxHeight) / 3;
return CristalyseChart()
.data(data)
.mapping(
pieValue: 'value',
pieCategory: 'category',
)
.geomPie(
outerRadius: radius,
innerRadius: radius * 0.4,
showLabels: constraints.maxWidth > 300,
)
.build();
},
)
Best Practices
When to Use Pie Charts
✅ Good for:
- Showing parts of a whole
- Displaying percentages
- Comparing proportions (5-7 categories max)
- Simple data visualization
❌ Avoid for:
- Too many categories (>7)
- Comparing exact values
- Time series data
- Negative values
Design Tips
- Limit to 5-7 slices for readability
- Use contrasting colors
- Order slices by size (largest first)
- Consider donut charts for modern look
- Use exploded slices sparingly for emphasis
- Optimize for large datasets by grouping small values
- Use appropriate animation durations
- Consider static rendering for print/export
- Test on different screen sizes
Common Patterns
Market Share Analysis
final marketShare = [
{'company': 'Leader', 'share': 35.2},
{'company': 'Challenger', 'share': 24.8},
{'company': 'Follower', 'share': 18.5},
{'company': 'Niche', 'share': 12.1},
{'company': 'Others', 'share': 9.4},
];
CristalyseChart()
.data(marketShare)
.mapping(pieValue: 'share', pieCategory: 'company')
.geomPie(
outerRadius: 160,
showLabels: true,
showPercentages: true,
explodeSlices: true,
explodeDistance: 10,
)
.build()
Survey Results
final surveyResults = [
{'response': 'Very Satisfied', 'count': 45},
{'response': 'Satisfied', 'count': 38},
{'response': 'Neutral', 'count': 12},
{'response': 'Dissatisfied', 'count': 3},
{'response': 'Very Dissatisfied', 'count': 2},
];
CristalyseChart()
.data(surveyResults)
.mapping(pieValue: 'count', pieCategory: 'response')
.geomPie(
outerRadius: 150,
innerRadius: 50,
showLabels: true,
showPercentages: true,
)
.build()