Search code examples
graphsyncfusionpopulation

Syncfusion stacked bar chart


i am trying to make a pyramid population in flutter dart. i try a tricky way by using stacked bar chart while i make one series data in 'negative' (actually it's a positive number) is there any way to make axis value and data label looks positive (while actually it's a negative number). Or there is another way to create Pyramid Population with Synfusion chart in fultter dart?

what i'm expecting: enter image description here


Solution

  • The tornado chart a specialized type of the barseries in Charts. The requirement can be achieved by setting the enableSideBySideSeriesPlacement to false and removing the negative sign in the axisLabelFormatter and onDataLabelRender callbacks.

    Output:

    Tornado chart

    Added code snippet below for your reference.

    import 'package:flutter/material.dart';
    import 'package:syncfusion_flutter_charts/charts.dart';
    
    void main() {
      return runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(primarySwatch: Colors.blue),
          debugShowCheckedModeBanner: false,
          home: _MyHomePage(),
        );
      }
    }
    
    class _MyHomePage extends StatefulWidget {
      // ignore: prefer_const_constructors_in_immutables
      _MyHomePage({Key? key}) : super(key: key);
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<_MyHomePage> {
      List<_SalesData>? data;
    
      @override
      void initState() {
        super.initState();
        data = [
          _SalesData('0-4', -70.12, 67.12),
          _SalesData('5-9', -75.23, 71.23),
          _SalesData('10-14', -77.34, 72.44),
          _SalesData('15-19', -77.15, 72.11),
          _SalesData('20-24', -82.63, 75.22),
          _SalesData('25-29', -80.75, 74.45),
          _SalesData('30-34', -79.21, 75.67),
          _SalesData('35-39', -73.50, 73.78),
          _SalesData('40-44', -67.65, 70.12),
          _SalesData('45-49', -65.33, 70.32),
          _SalesData('50-54', -60.44, 63.54),
          _SalesData('55-59', -54.67, 55.63),
          _SalesData('60-64', -42.87, 43.71),
          _SalesData('65-69', -34.98, 33.87),
          _SalesData('70-74', -21.12, 21.66),
          _SalesData('75+', -18.11, 21.22),
        ];
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SfCartesianChart(
            title: const ChartTitle(text: 'Piramida Penduduk Kabupaten Cilacap'),
            legend: const Legend(isVisible: true, position: LegendPosition.bottom),
            enableSideBySideSeriesPlacement: false,
            primaryXAxis:
                const CategoryAxis(majorGridLines: MajorGridLines(width: 0)),
            primaryYAxis: NumericAxis(
              majorGridLines: const MajorGridLines(width: 0),
              axisLabelFormatter: (AxisLabelRenderDetails args) {
                if (args.value < 0) {
                  return ChartAxisLabel(
                      args.value.abs().toString().replaceAll(RegExp(r'[-.]0'), ''),
                      args.textStyle);
                }
                return ChartAxisLabel(args.text, args.textStyle);
              },
            ),
            onDataLabelRender: (dataLabelArgs) {
              if (dataLabelArgs.text != null) {
                double? yValue = double.tryParse(dataLabelArgs.text!);
    
                if (yValue != null && yValue < 0) {
                  dataLabelArgs.text =
                      yValue.abs().toString().replaceAll(RegExp(r'[-.]0'), '');
                }
              }
            },
            series: <CartesianSeries<_SalesData, String>>[
              BarSeries<_SalesData, String>(
                dataSource: data,
                xValueMapper: (_SalesData sales, _) => sales.x,
                yValueMapper: (_SalesData sales, _) => sales.y1,
                name: 'Laki-Laki',
                dataLabelSettings: const DataLabelSettings(
                  isVisible: true,
                  labelAlignment: ChartDataLabelAlignment.middle,
                ),
              ),
              BarSeries<_SalesData, String>(
                dataSource: data,
                xValueMapper: (_SalesData sales, _) => sales.x,
                yValueMapper: (_SalesData sales, _) => sales.y2,
                name: 'Prempuan',
                dataLabelSettings: const DataLabelSettings(
                    isVisible: true,
                    labelAlignment: ChartDataLabelAlignment.middle),
              ),
            ],
          ),
        );
      }
    }
    
    class _SalesData {
      _SalesData(this.x, this.y1, this.y2);
    
      final String x;
      final double? y1;
      final double? y2;
    }