The grammar of graphics visualization library that Flutter developers have been waiting for.
Finally, create beautiful data visualizations in Flutter without fighting against chart widgets or settling for web-based solutions.
Visit our complete documentation for step-by-step guides, interactive examples, |
Stop wrestling with limited chart libraries. Cristalyse brings the power of grammar of graphics (think ggplot2) to Flutter with buttery-smooth 60fps animations and true cross-platform deployment.
- π¨ Grammar of Graphics API - Familiar syntax if you've used ggplot2 or plotly
- π Native 60fps Animations - Leverages Flutter's rendering engine, not DOM manipulation
- π± True Cross-Platform - One codebase β Mobile, Web, Desktop, all looking identical
- β‘ GPU-Accelerated Performance - Handle large datasets without breaking a sweat
- π― Flutter-First Design - Seamlessly integrates with your existing Flutter apps
- π Dual Y-Axis Support - Professional business dashboards with independent left/right scales
- π Advanced Bar Charts - Grouped, stacked, and horizontal variations with smooth animations
- π Interactive Charts - Engage users with tooltips, hover effects, and click events.
Interactive scatter plots with smooth animations and multi-dimensional data mapping
Progressive line drawing with customizable themes and multi-series support
flutter pub add cristalyse
That's it! No complex setup, no additional configuration.
import 'package:cristalyse/cristalyse.dart';
import 'package:flutter/material.dart';
class MyChart extends StatelessWidget {
@override
Widget build(BuildContext context) {
final data = [
{'x': 1, 'y': 2, 'category': 'A'},
{'x': 2, 'y': 3, 'category': 'B'},
{'x': 3, 'y': 1, 'category': 'A'},
{'x': 4, 'y': 4, 'category': 'C'},
];
return CristalyseChart()
.data(data)
.mapping(x: 'x', y: 'y', color: 'category')
.geomPoint(
size: 8.0, // Made points a bit larger to see border clearly
alpha: 0.8,
shape: PointShape.triangle, // Example: use triangles
borderWidth: 1.5, // Example: add a border to points
)
.scaleXContinuous()
.scaleYContinuous()
.theme(ChartTheme.defaultTheme())
.build();
}
}
Result: A beautiful, animated scatter plot that works identically on iOS, Android, Web, and Desktop.
Your first chart - clean, responsive, and cross-platform
Add real-time panning capabilities to your charts with seamless range updates and smooth interaction.
CristalyseChart()
.data(myData)
.mapping(x: 'x', y: 'y')
.geomLine()
.interaction(
pan: PanConfig(
enabled: true,
onPanUpdate: (info) {
// Handle real-time updates based on visible X range
print('Visible X range: \\${info.visibleMinX} - \\${info.visibleMaxX}');
},
),
)
.build();
Features:
- Maintains pan state across interactions
- Synchronizes displayed range between header and chart axis
- Enhanced UI for range display card
Bring your data to life with a fully interactive layer. Add rich tooltips, hover effects, and click/tap events to give users a more engaging experience.
// Add tooltips and click handlers
CristalyseChart()
.data(salesData)
.mapping(x: 'week', y: 'revenue', color: 'rep')
.geomPoint(size: 8.0)
.interaction(
tooltip: TooltipConfig(
builder: (point) {
// Build a custom widget for the tooltip
final category = point.getDisplayValue('rep');
final value = point.getDisplayValue('revenue');
return Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.8),
borderRadius: BorderRadius.circular(4),
),
child: Text(
'$category: \$$value k',
style: const TextStyle(color: Colors.white, fontSize: 12),
),
);
},
),
click: ClickConfig(
onTap: (point) {
// Handle tap event, e.g., show a dialog
print('Tapped on: ${point.data}');
},
),
)
.build();
CristalyseChart()
.data(salesData)
.mapping(x: 'date', y: 'revenue', color: 'region', size: 'deals')
.geomPoint(alpha: 0.7)
.animate(duration: Duration(milliseconds: 800), curve: Curves.elasticOut)
.theme(ChartTheme.defaultTheme())
.build()
CristalyseChart()
.data(timeSeriesData)
.mapping(x: 'month', y: 'users', color: 'platform')
.geomLine(strokeWidth: 3.0)
.geomPoint(size: 4.0)
.animate(duration: Duration(milliseconds: 1200))
.theme(ChartTheme.darkTheme())
.build()
CristalyseChart()
.data(analyticsData)
.mapping(x: 'week', y: 'engagement')
.geomLine(strokeWidth: 2.0, alpha: 0.8) // Trend line
.geomPoint(size: 5.0, alpha: 0.9) // Data points
.animate(duration: Duration(milliseconds: 1000), curve: Curves.easeInOutCubic)
.build()
// Perfect for budget breakdowns and composition analysis
CristalyseChart()
.data(revenueData)
.mapping(x: 'quarter', y: 'revenue', color: 'category')
.geomBar(
style: BarStyle.stacked, // Stack segments on top of each other
width: 0.8,
alpha: 0.9,
)
.scaleXOrdinal()
.scaleYContinuous(min: 0)
.theme(ChartTheme.defaultTheme())
.animate(duration: Duration(milliseconds: 1400))
.build()
Stacked bars with segment-by-segment progressive animation
// Compare multiple series side-by-side
CristalyseChart()
.data(productData)
.mapping(x: 'quarter', y: 'revenue', color: 'product')
.geomBar(
style: BarStyle.grouped, // Place bars side-by-side
width: 0.8,
alpha: 0.9,
)
.scaleXOrdinal()
.scaleYContinuous(min: 0)
.theme(ChartTheme.defaultTheme())
.build()
Grouped bar charts for comparing multiple series side-by-side
// Great for ranking and long category names
CristalyseChart()
.data(departmentData)
.mapping(x: 'department', y: 'headcount')
.geomBar(
borderRadius: BorderRadius.circular(4), // Rounded corners
borderWidth: 1.0, // Add borders
)
.coordFlip() // Flip to horizontal
.scaleXOrdinal()
.scaleYContinuous(min: 0)
.theme(ChartTheme.defaultTheme())
.build()
Perfect for part-to-whole relationships - visualize market share, revenue distribution, user demographics, and any categorical data where proportions matter.
// Revenue Distribution by Platform
CristalyseChart()
.data([
{'category': 'Mobile', 'revenue': 45.2},
{'category': 'Desktop', 'revenue': 32.8},
{'category': 'Tablet', 'revenue': 22.0},
])
.mappingPie(value: 'revenue', category: 'category')
.geomPie(
outerRadius: 120.0,
strokeWidth: 2.0,
strokeColor: Colors.white,
showLabels: true,
showPercentages: true,
)
.theme(ChartTheme.defaultTheme())
.animate(
duration: Duration(milliseconds: 1200),
curve: Curves.elasticOut,
)
.build()
// User Analytics with Donut Visualization
CristalyseChart()
.data(userPlatformData)
.mappingPie(value: 'users', category: 'platform')
.geomPie(
innerRadius: 60.0, // Creates donut hole
outerRadius: 120.0,
strokeWidth: 3.0,
strokeColor: Colors.white,
showLabels: true,
showPercentages: false, // Show actual values
)
.theme(ChartTheme.darkTheme())
.animate(
duration: Duration(milliseconds: 1500),
curve: Curves.easeOutBack,
)
.build()
// Market Share Analysis with Exploded Slices
CristalyseChart()
.data(marketShareData)
.mappingPie(value: 'market_share', category: 'product')
.geomPie(
outerRadius: 150.0,
strokeWidth: 2.0,
strokeColor: Colors.white,
showLabels: true,
showPercentages: true,
explodeSlices: true, // Explode slices for emphasis
explodeDistance: 15.0,
labelRadius: 180.0, // Position labels further out
labelStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
)
.theme(ChartTheme.solarizedLightTheme())
.build()
Perfect for business dashboards - correlate volume metrics with efficiency metrics on independent scales.
// Revenue vs Conversion Rate - The Classic Business Dashboard
CristalyseChart()
.data(businessData)
.mapping(x: 'month', y: 'revenue') // Primary Y-axis (left)
.mappingY2('conversion_rate') // Secondary Y-axis (right)
.geomBar(
yAxis: YAxis.primary, // Revenue bars use left axis
alpha: 0.7,
)
.geomLine(
yAxis: YAxis.secondary, // Conversion line uses right axis
strokeWidth: 3.0,
color: Colors.orange,
)
.geomPoint(
yAxis: YAxis.secondary, // Points on conversion line
size: 8.0,
color: Colors.orange,
)
.scaleXOrdinal()
.scaleYContinuous(min: 0) // Left axis: Revenue ($k)
.scaleY2Continuous(min: 0, max: 100) // Right axis: Percentage (%)
.theme(ChartTheme.defaultTheme())
.build()
Dual axis charts for correlating two different metrics on independent scales
// Sales Volume vs Customer Satisfaction
CristalyseChart()
.data(salesData)
.mapping(x: 'week', y: 'sales_volume')
.mappingY2('satisfaction_score')
.geomBar(yAxis: YAxis.primary) // Volume bars
.geomLine(yAxis: YAxis.secondary) // Satisfaction trend
.scaleY2Continuous(min: 1, max: 5) // Rating scale
.build();
// Website Traffic vs Bounce Rate
CristalyseChart()
.data(analyticsData)
.mapping(x: 'date', y: 'page_views')
.mappingY2('bounce_rate')
.geomArea(yAxis: YAxis.primary, alpha: 0.3) // Traffic area
.geomLine(yAxis: YAxis.secondary, strokeWidth: 2.0) // Bounce rate line
.scaleY2Continuous(min: 0, max: 100) // Percentage scale
.build();
- Scatter plots with size and color mapping
- Line charts with multi-series support and progressive drawing
- Area charts with smooth fills and multi-series transparency
- Bar charts (vertical, horizontal, grouped, stacked) with smooth animations
- Pie charts and donut charts with exploded slices and smart label positioning
- Dual Y-axis charts for professional business dashboards
- Combined visualizations (bars + lines, points + lines, etc.)
- Grammar of Graphics API - Familiar ggplot2-style syntax
- Smooth 60fps animations with customizable timing and curves
- Dual Y-axis support with independent scales and data routing
- Coordinate flipping for horizontal charts
- Multiple themes (Light, Dark, Solarized Light/Dark)
- Custom color palettes and styling options
- Responsive scaling for all screen sizes
- High-DPI support for crisp visuals
- Flexible data formats - List<Map<String, dynamic>>
- Mixed data types - Automatic type detection and conversion
- Missing value handling - Graceful degradation for null/invalid data
- Large dataset support - Optimized for 1000+ data points
- Real-time updates - Smooth transitions when data changes
Export your charts as professional-quality SVG vector graphics for reports, presentations, and documentation.
// Simple SVG export
final result = await chart.exportAsSvg(
width: 1200,
height: 800,
filename: 'sales_report',
);
print('Chart saved to: ${result.filePath}');
// Advanced configuration
final config = ExportConfig(
width: 1920,
height: 1080,
format: ExportFormat.svg,
filename: 'high_res_dashboard',
);
final result = await chart.export(config);
SVG Export Features:
- β Scalable Vector Graphics - Infinite zoom without quality loss
- β Professional Quality - Perfect for presentations and reports
- β Small File Sizes - Efficient for web and print
- β Design Software Compatible - Editable in Figma, Adobe Illustrator, etc.
- β Cross-Platform Reliable - Works consistently on all platforms
- β Automatic File Management - Saves to Documents directory with timestamp
- Statistical overlays (regression lines, confidence intervals)
- Interactive zoom capabilities with scale persistence
- Faceting for small multiples and grid layouts
- Enhanced SVG export with full chart rendering
Widget buildRevenueTrend() {
return CristalyseChart()
.data(monthlyRevenue)
.mapping(x: 'month', y: 'revenue', color: 'product_line')
.geomLine(strokeWidth: 3.0)
.geomPoint(size: 5.0)
.scaleXContinuous()
.scaleYContinuous(min: 0)
.theme(ChartTheme.solarizedDarkTheme()) // Use Solarized Dark theme
.animate(duration: Duration(milliseconds: 1500))
.build();
}
Widget buildEngagementScatter() {
return CristalyseChart()
.data(userMetrics)
.mapping(x: 'session_length', y: 'pages_viewed',
color: 'user_type', size: 'revenue')
.geomPoint(alpha: 0.6)
.scaleXContinuous()
.scaleYContinuous()
.theme(isDarkMode ? ChartTheme.darkTheme() : ChartTheme.defaultTheme())
.animate(duration: Duration(milliseconds: 800), curve: Curves.elasticOut)
.build();
}
Widget buildMarketSharePie() {
return CristalyseChart()
.data(marketData)
.mappingPie(value: 'market_share', category: 'product')
.geomPie(
outerRadius: 140.0,
strokeWidth: 3.0,
strokeColor: Colors.white,
showLabels: true,
showPercentages: true,
explodeSlices: true, // Emphasize key segments
explodeDistance: 12.0,
labelStyle: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
),
)
.theme(ChartTheme.defaultTheme())
.animate(duration: Duration(milliseconds: 1200), curve: Curves.elasticOut)
.build();
}
Widget buildKPIDashboard() {
return CristalyseChart()
.data(kpiData)
.mapping(x: 'quarter', y: 'revenue')
.mappingY2('profit_margin') // Dual Y-axis for percentage
.geomBar(
yAxis: YAxis.primary,
style: BarStyle.stacked, // Stack revenue components
color: 'revenue_source',
)
.geomLine(
yAxis: YAxis.secondary, // Profit margin trend
strokeWidth: 4.0,
color: Colors.green,
)
.scaleXOrdinal()
.scaleYContinuous(min: 0) // Revenue scale
.scaleY2Continuous(min: 0, max: 50) // Percentage scale
.theme(ChartTheme.defaultTheme())
.build();
}
Alternative | Why Cristalyse is Better |
---|---|
fl_chart | Grammar of graphics API vs basic chart widgets. Dual Y-axis support vs single axis limitation. |
charts_flutter | Active development vs deprecated. Stacked bars and advanced features vs basic charts. |
Web charts (plotly.js) | Native performance vs DOM rendering. True mobile deployment vs responsive web. |
Platform-specific charts | Write once vs write 3x for iOS/Android/Web. Consistent UX vs platform differences. |
Business tools (Tableau) | Embedded in your app vs separate tools. Full customization vs template limitations. |
final customTheme = ChartTheme(
backgroundColor: Colors.grey[50]!,
primaryColor: Colors.deepPurple,
colorPalette: [Colors.blue, Colors.red, Colors.green],
gridColor: Colors.grey[300]!,
axisTextStyle: TextStyle(fontSize: 14, color: Colors.black87),
padding: EdgeInsets.all(40),
);
chart.theme(customTheme)
chart.animate(
duration: Duration(milliseconds: 1200),
curve: Curves.elasticOut, // Try different curves!
)
// Map any data structure
chart
.data(complexData)
.mapping(
x: 'timestamp', // Time series
y: 'metric_value', // Numeric values
color: 'category', // Color grouping
size: 'importance' // Size encoding
)
.mappingY2('efficiency') // Secondary Y-axis for dual charts
chart
.data(budgetData)
.mapping(x: 'department', y: 'amount', color: 'category')
.geomBar(
style: BarStyle.stacked, // Stack segments
width: 0.8, // Bar width
borderRadius: BorderRadius.circular(4), // Rounded corners
alpha: 0.9, // Transparency
)
.scaleXOrdinal()
.scaleYContinuous(min: 0)
- β iOS 12+
- β Android API 21+
- β Web (Chrome 80+, Firefox, Safari)
- β Windows 10+
- β macOS 10.14+
- β Linux (Ubuntu 18.04+)
Current Version: 1.0.0 - Production ready with enhanced dual Y-axis SVG export and comprehensive interactive capabilities
We're shipping progressively! Each release adds new visualization types while maintaining backward compatibility.
- β v0.1.0 - Scatter plots and basic theming
- β v0.2.0 - Line charts and animations
- β v0.3.0 - Bar charts (including horizontal) and areas
- β v0.4.0 - Enhanced theming with custom colors and text styles, stacked bars
- β v0.5.0 - Dual Y-axis support and advanced bar chart variations
- β v0.6.0 - Interactive tooltips
- β v0.7.0 - Interactive panning
- β v0.8.0 - Area chart support with animations and multi-series capabilities
- β v0.9.0 - Enhanced dual Y-axis SVG export with comprehensive scale support
We'd love your help! Check out our contributing guide and:
- π Report bugs
- π‘ Suggest features
- π Improve documentation
- π§ Submit pull requests
MIT License - build whatever you want, commercially or otherwise.
- π¦ pub.dev package
- π Full documentation
- π Issue tracker
- π¬ Discussions
Ready to create stunning visualizations? flutter pub add cristalyse
and start building! π
Cristalyse: Finally, the grammar of graphics library Flutter developers deserve.