I have a flutter project where I am using Syncfusion to render the JSON data into charts. I don't get any error when I debug my code but the chart is not rendering when the build is complete. I am not sure if there are mistakes in the codes but it worked fine for other charts.
In addition, some of the reasons I feel responsible for the chart not being rendered could be:
There is too much data to plot. (This may not be the problem since I also tried after reducing data)
The values to plot are too small since they mostly range from some negative values to some positive values and also the values are in decimal (eg 0.7, -0.6, and so on).
These are just my assumption on what could have gone wrong. Please correct me if I am mistaken.
Any ideas to resolve or at least help me understand what is wrong would be great. And yes please help me out :)). Below is the code that I have.
import 'package:flutter/material.dart';
import 'package:fyp/model/rainApiCall.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class Past extends StatefulWidget{
#override
_Past createState() => _Past();
}
class _Past extends State<Past>{
List<String> t = [];
List<String> ampA = [];
List<String> ampB = [];
List<String> ampC = [];
#override
void initState() {
fetchEQData();
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: FutureBuilder(
future: fetchEQData(),
builder: (context, snapshot){
if(snapshot.hasData) {
var stationID = '4853';
for(int i=0; i<snapshot.data.length; i++){
if(snapshot.data[i].stationId==stationID){
t.add(snapshot.data[i].recordLength);
ampA.add(snapshot.data[i].amplitudemaxa);
ampB.add(snapshot.data[i].amplitudemaxb);
ampC.add(snapshot.data[i].amplitudemaxc);
}
}
return Card(
child: SfCartesianChart(
series: <ChartSeries>[
StackedLineSeries<EqAmpData, double>(
dataSource: getColumnData(t, ampA, ampB, ampC),
dashArray: <double>[5,5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: (EqAmpData eqdata, _) => int.parse(eqdata.y1),
),
StackedLineSeries<EqAmpData, double>(
dataSource: getColumnData(t, ampA, ampB, ampC),
dashArray: <double>[5,5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: (EqAmpData eqdata, _) => int.parse(eqdata.y2),
),
StackedLineSeries<EqAmpData, double>(
dataSource: getColumnData(t, ampA, ampB, ampC),
dashArray: <double>[5,5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: (EqAmpData eqdata, _) => int.parse(eqdata.y3),
),
]
)
);
}
return CircularProgressIndicator();
},
),),);}}
class EqAmpData{
String x;
String y1;
String y2;
String y3;
EqAmpData(this.x, this.y1, this.y2, this.y3);
}
dynamic getColumnData(List xval, List yval1, List yval2, List yval3) {
List rtime = xval;
List y1 = yval1;
List y2 = yval2;
List y3 = yval3;
List<EqAmpData> columnData = <EqAmpData>[];
for (int i = 0; i < rtime.length; i++) {
columnData.add(EqAmpData(rtime[i], y1[i], y2[i], y3[i]));
}
return columnData;
}
Screen after build:
enter image description here
Screenshot of the data I have:
enter image description here
When you define your StackedLineSeries, your yValueMapper should provide double instead of int:
StackedLineSeries<EqAmpData, double>(
dataSource: getColumnData(t, ampA, ampB, ampC),
dashArray: <double>[5, 5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.y1),
),
Full source code for easy copy-paste
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Charts Demo',
home: Past(),
),
);
}
class Past extends StatefulWidget {
#override
_Past createState() => _Past();
}
class _Past extends State<Past> {
List<String> t = [];
List<String> ampA = [];
List<String> ampB = [];
List<String> ampC = [];
#override
void initState() {
fetchEQData();
super.initState();
}
Future<List<RawData>> fetchEQData() async {
await Future.delayed(Duration(seconds: 2));
return data;
}
StackedLineSeries<EqAmpData, double> prepareSerie({
List<EqAmpData> dataSource,
num Function(EqAmpData, int) yValueMapper,
}) {
return StackedLineSeries<EqAmpData, double>(
dataSource: dataSource,
dashArray: <double>[5, 5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: yValueMapper,
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: FutureBuilder<List<RawData>>(
future: fetchEQData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
snapshot.data
.where((item) => item.stationId == '4853')
.forEach((item) {
t.add(item.recordLength);
ampA.add(item.amplitudemaxa);
ampB.add(item.amplitudemaxb);
ampC.add(item.amplitudemaxc);
});
final dataSource = getColumnData(t, ampA, ampB, ampC);
return Card(
child: SfCartesianChart(
series: <ChartSeries>[
prepareSerie(
dataSource: dataSource,
yValueMapper: (eqdata, _) => double.parse(eqdata.y1),
),
prepareSerie(
dataSource: dataSource,
yValueMapper: (eqdata, _) => double.parse(eqdata.y2),
),
prepareSerie(
dataSource: dataSource,
yValueMapper: (eqdata, _) => double.parse(eqdata.y3),
),
],
),
);
}
return CircularProgressIndicator();
},
),
),
);
}
}
// DOMAIN
class EqAmpData {
final String x;
final String y1;
final String y2;
final String y3;
EqAmpData(this.x, this.y1, this.y2, this.y3);
}
dynamic getColumnData(List rtime, List y1, List y2, List y3) {
return List.generate(
rtime.length,
(i) => EqAmpData(rtime[i], y1[i], y2[i], y3[i]),
);
}
class RawData {
final String stationId;
final String recordLength;
final String amplitudemaxa;
final String amplitudemaxb;
final String amplitudemaxc;
RawData(
this.stationId,
this.recordLength,
this.amplitudemaxa,
this.amplitudemaxb,
this.amplitudemaxc,
);
}
// DATA
final random = math.Random();
final data = List.generate(
100,
(index) => RawData(
"4853",
(index * 0.01).toString(),
((random.nextInt(100) - 50) / 500).toString(),
((random.nextInt(100) - 50) / 1000).toString(),
((random.nextInt(100) - 50) / 1000).toString(),
),
);
Related
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: SfCartesianChart(
// Enables the legend
legend: Legend(isVisible: true),
// Initialize category axis
primaryXAxis: CategoryAxis(),
series: <ChartSeries>[
// Initialize line series
LineSeries<GraphModel, String>(
dataSource: [
// Bind data source
// retrieve data from database
GraphModel(
productName: ['prodName'], count: 'count'.length
),
],
xValueMapper: (GraphModel data, _) => data.productName,
yValueMapper: (GraphModel data, _) => data.count,
)
]
)
)
)
);
}
}
I want to retrieve data from firestore where I create GraphModel but i dont know to declare from firebase to input in the graph. Please help me how to declare this graph
need to import the cloud_firestore package to your pubspec.yaml file
Heres the full code to retrieve data from firestore:
import 'package:cloud_firestore/cloud_firestore.dart';
class GraphModel {
String productName;
int count;
GraphModel({this.productName, this.count});
}
class YourWidget extends StatefulWidget {
#override
_YourWidgetState createState() => _YourWidgetState();
}
class _YourWidgetState extends State<YourWidget> {
List<GraphModel> _graphData = [];
#override
void initState() {
super.initState();
_retrieveDataFromFirestore();
}
void _retrieveDataFromFirestore() async {
final firestore = FirebaseFirestore.instance;
final graphData = await firestore.collection('your_collection').get();
setState(() {
_graphData = graphData.docs.map((doc) => GraphModel(
productName: doc.data()['product_name'],
count: doc.data()['count'],
)).toList();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: SfCartesianChart(
legend: Legend(isVisible: true),
primaryXAxis: CategoryAxis(),
series: <ChartSeries>[
LineSeries<GraphModel, String>(
dataSource: _graphData,
xValueMapper: (GraphModel data, _) => data.productName,
yValueMapper: (GraphModel data, _) => data.count,
),
],
),
),
),
);
}
}
I have Lists of values containing double type numbers and each of this lists contains about 5000 values. Each of this lists has been collected from a microcontroller within 60 seconds.
I want to create a line chart to show the variance of this values. I tried to use the Spline Chart in Flutter but I cannot manage to make it read values from a list as its throwing this error:
The return type 'List?' isn't a 'num?', as required by the closure's context.
and here is the code:
Widget build(BuildContext context) {
final List<ChartData> chartData = [
ChartData(10, [5.5,0.6]),
ChartData(20, [2.5,0.6]),
ChartData(30, [1.5,0.6]),
ChartData(40, [0.5,0.6]),
ChartData(50, [0.5,3.6]),
ChartData(60, [0.5,2.6]),
ChartData(70, [0.5,1.6]),
ChartData(80, [0.5,0.63]),
ChartData(90, [0.5,0.126]),
];
return Scaffold(
body: Center(
child: Container(
child: SfCartesianChart(
series: <ChartSeries>[
// Renders spline chart
SplineSeries<ChartData, int>(
dataSource: chartData,
xValueMapper: (ChartData data, _) => data.x,
yValueMapper: (ChartData data, _) => data.y
)
]
)
)
)
);
}
}
class ChartData {
ChartData(this.x, this.y);
final int x;
final List? y;
}
I tried to create a list that has few values and called some elements from each list to the chart. It looked like this:
List x =[1.0,1.2,1.3,1.5,1.9,1.8,1.9,2.9,3.9,1.9,1.8,1.4];
#override
Widget build(BuildContext context) {
final List<ChartData> chartData = [
ChartData(10, x[1]),
ChartData(20, x[2]),
ChartData(30, x[0]),
ChartData(40, x[4]),
ChartData(50, x[5]),
ChartData(60, x[6]),
ChartData(70, x[7]),
ChartData(80, x[8]),
ChartData(90, x[9]),
];
And this worked for me but Can I make it so I can call all the elemnts from the list to the chart.
Do you have any suggestion on how to make this thing happens.
thank you in advance
Your y in ChartData is List. And you try to assign it to num?
yValueMapper: (ChartData data, _) => data.y
If the length of y is not fixed, you can use this function to generate SplineSeries
List<SplineSeries> generateSplineSeries(List<ChartData> chartData){
List<SplineSeries> splines = [];
for(int i=0; i<chartData.first.y!.length; i++){
splines.add( SplineSeries<ChartData, int>(
dataSource: chartData,
xValueMapper: (ChartData data, _) => data.x,
yValueMapper: (ChartData data, _) => data.y![i],
));
}
return splines;
}
Widget build(BuildContext context) {
final List<ChartData> chartData = [
ChartData(10, [5.5,0.6]),
ChartData(20, [2.5,0.6]),
ChartData(30, [1.5,0.6]),
ChartData(40, [0.5,0.6]),
ChartData(50, [0.5,3.6]),
ChartData(60, [0.5,2.6]),
ChartData(70, [0.5,1.6]),
ChartData(80, [0.5,0.63]),
ChartData(90, [0.5,0.126]),
];
return Scaffold(
body: Center(
child: Container(
child: SfCartesianChart(
series: generateSplineSeries(chartData),
)
)
)
);
}
#override
Widget build(BuildContext context) {
List x =[10.0,1.2,1.3,1.5,1.9,1.8,1.9,2.9,3.9,1.9,1.8,1.4];
final List<ChartData> chartData = [
ChartData(60,x),
];
List<SplineSeries> generateSplineSeries(List<ChartData> chartData){
List<SplineSeries> splines = [];
for(int i=0; i<chartData.first.y!.length; i++){
splines.add( SplineSeries<ChartData, int>(
dataSource: chartData,
xValueMapper: (ChartData data, _) => data.x,
yValueMapper: (ChartData data, _) => data.y![i],
));
}
return splines;
}
return Scaffold(
body: Center(
child: Container(
child: SfCartesianChart(
series: generateSplineSeries(chartData),
)
)
)
);
}
}
class ChartData {
ChartData(this.x, this.y);
final int x;
final List? y;
}
I created a list of graphs where I define the data in the Sales template but whenever I call it shows an error ( Declared with 0 type parameter ). I added the data but it doesn't show
Error: Expected 0 type arguments.
ErrorLine: new Expanded(child: new charts.BarChart(_chartdata)),
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:charts_flutter/flutter.dart' as charts;
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
#override
_State createState() => _State();
}
class Sales {
final String year;
final int sales;
Sales(this.year, this.sales);
}
class _State extends State<MyApp> {
List<Sales> _data = [];
List<charts.Series<Sales, String>> _chartdata = [];
void _makeData() {
// _data = new List<Sales>();
// _chartdata = new List<charts.Series<Sales, String>>();
final rnd = Random();
for(int i = 2010; i < 2019; i++) {
_data.add(new Sales(i.toString(), rnd.nextInt(1000)));
}
_chartdata.add(new charts.Series(
id: 'Sales',
colorFn: (_,__) => charts.MaterialPalette.red.shadeDefault, //Old version
//colorFn: (Sales sales,__) => charts.MaterialPalette.red.shadeDefault,
data: _data,
domainFn: (Sales sales, _) => sales.year,
measureFn: (Sales sales, _) => sales.sales,
fillPatternFn: (_,__) => charts.FillPatternType.solid, // Old version
//fillPatternFn: (Sales sales,__) => charts.FillPatternType.solid,
displayName: 'sales'
)
);
}
#override
void initState() {
_makeData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Layouts'),
backgroundColor: Colors.deepPurpleAccent,
),
body: Container(
padding: const EdgeInsets.all(32.0),
child: Center(
child: Column(
children: <Widget>[
Text('Sales'),
//new Expanded(child: new charts.BarChart<Sales>(_chartdata))
//new Expanded(child: new charts.BarChart<Sales>(_chartdata))
new Expanded(child: new charts.BarChart<Sales>(_chartdata)),
],
),
)
),
);
}
}
the error is shown in <Sales> in last.
Please help me out I don't know how to fix it.
Flutter, I have This Type of Json from api i want to show multiline chart of every user. Users can increase or decrease on district basis selection inside application? I searched alot from Syncfusion library or from many others but i didnot find any way please help.
**[{"id":"1", "name":"fayyaz","date":"12-1-2021","count":"5"},
{"id":"1", "name":"fayyaz","date":"13-1-2021","count":"7"},
{"id":"1", "name":"fayyaz","date":"14-1-2021","count":"2"},
{"id":"1", "name":"fayyaz","date":"15-1-2021","count":"15"},
{"id":"1", "name":"fayyaz","date":"16-1-2021","count":"10"},
{"id":"2", "name":"ali","date":"14-1-2021","count":"3"},
{"id":"2", "name":"ali","date":"16-1-2021","count":"6"},
{"id":"3", "name":"saad","date":"12-1-2021","count":"1"},
{"id":"3", "name":"saad","date":"13-1-2021","count":"10"},
{"id":"3", "name":"saad","date":"14-1-2021","count":"4"},
{"id":"3", "name":"saad","date":"15-1-2021","count":"3"}];**
SfCartesianChart(
plotAreaBorderWidth: 0,
title: ChartTitle(text: 'Monthly Progress'),
legend: Legend(
isVisible: isCardView ? false : true,
overflowMode: LegendItemOverflowMode.wrap),
primaryXAxis: CategoryAxis(
// Axis will be rendered based on the index values
interval: 1,
labelRotation: 90,
arrangeByIndex: true
),
primaryYAxis: NumericAxis(
edgeLabelPlacement: EdgeLabelPlacement.shift,
// labelFormat: '{value}k',
// minimum: 0,
// maximum: 12,
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(color: Colors.transparent)
),
tooltipBehavior: TooltipBehavior(enable: true),
series: <ChartSeries<MonthlyCount, String>>
[
LineSeries<MonthlyCount, String>(
animationDuration: 2500,
width: 2,
name: '',
markerSettings: const MarkerSettings(isVisible: true),
dataSource: chartDataMonthlyCount!,
xValueMapper: (MonthlyCount sales, _) => sales.xaxis,
yValueMapper: (MonthlyCount sales, _) => sales.collectCount,
),
]
),
first use this site quichtype to create a model class from your json. then you can use this model to set data for charts.
after you generate your model class from above site, let's call it User class. you can use it like this.
var json = jsonDecode(PutYourJsonHere);
List<Users> UsersList = json.map((e) => User.fromJson(e)).toList();
We created a sample for your requirement that will parse given JSON data and convert it into multiple lists of a data source based on the id value in the JSON and rendered multiple line series. We have attached the code snippet below and KB for your reference.
KB: https://www.syncfusion.com/kb/11674/how-to-render-a-flutter-chart-using-the-json-data-sfcartesianchart
code snippet
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<SalesData> chartData = [];
#override
void initState() {
loadSalesData();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FutureBuilder(
future: getJsonFromAssets(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return SfCartesianChart(
primaryXAxis: DateTimeAxis(),
series: getLineChart(chartData),
);
} else {
return const CircularProgressIndicator();
}
}));
}
Future<String> getJsonFromAssets() async {
return await rootBundle.loadString('assets/data.json');
}
Future loadSalesData() async {
final String jsonString = await getJsonFromAssets();
final dynamic jsonResponse = json.decode(jsonString);
for (Map<String, dynamic> i in jsonResponse) {
// for(int i = 0; i < chartData.length)
chartData.add(SalesData.fromJson(i));
}
}
List<ChartSeries<SalesData, DateTime>> getLineChart(List<SalesData> data) {
List<ChartSeries<SalesData, DateTime>> series = [];
List<SalesData> _data = [];
List<SalesData> _data1 = [];
List<SalesData> _data2 = [];
for (int i = 0; i < chartData.length; i++) {
chartData[i].id == 1
? _data.add(chartData[i])
: chartData[i].id == 2
? _data1.add(chartData[i])
: _data2.add(chartData[i]);
}
series.addAll([
LineSeries(
dataSource: _data,
xValueMapper: (SalesData data, _) => data.date,
yValueMapper: (SalesData data, _) => data.count),
LineSeries(
dataSource: _data1,
xValueMapper: (SalesData data, _) => data.date,
yValueMapper: (SalesData data, _) => data.count),
LineSeries(
dataSource: _data2,
xValueMapper: (SalesData data, _) => data.date,
yValueMapper: (SalesData data, _) => data.count)
]);
return series;
}
}
class SalesData {
SalesData({
this.id,
this.name,
this.date,
this.count,
});
int? id;
String? name;
DateTime? date;
int? count;
factory SalesData.fromJson(Map<String, dynamic> json) => SalesData(
id: int.parse(json["id"]),
name: json["name"],
date: DateFormat('dd-MM-yyyy').parse(json["date"]),
count: int.parse(json["count"]),
);
}
i will display linechart from the database using datajson with flutter. but the reference that I can use is hardcode data. Please help
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:charts_flutter/flutter.dart' as charts;
int dataTotal = 0;
class GrafikSpbj extends StatefulWidget {
final List<charts.Series> seriesList;
final bool animate;
GrafikSpbj(this.seriesList, {this.animate});
/// Creates a [LineChart] with sample data and no transition.
factory GrafikSpbj.withSampleData() {
return new GrafikSpbj(
_createSampleData(),
// Disable animations for image tests.
animate: false,
);
}
#override
_GrafikSpbjState createState() => _GrafikSpbjState();
/// Create one series with sample hard coded data.
static List<charts.Series<LinearSales, int>> _createSampleData() {
print(dataTotal);
final desktopSalesData = [
new LinearSales(0, 10),
new LinearSales(1, 50),
new LinearSales(2, 70),
new LinearSales(3, 100),
];
final tableSalesData = [
new LinearSales(0, 20),
new LinearSales(1, 40),
new LinearSales(2, 80),
new LinearSales(3, 100),
];
return [
new charts.Series<LinearSales, int>(
id: 'Desktop',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
data: desktopSalesData,
),
new charts.Series<LinearSales, int>(
id: 'Tablet',
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
data: tableSalesData,
),
];
}
}
class _GrafikSpbjState extends State<GrafikSpbj> {
List data;
Timer timer;
int jumlahData = 0;
Future<List> _getData() async {
final response = await http.get("xxxxxxxxxxxxx");
setState(() {
data = json.decode(response.body);
jumlahData =data.length;
print(data[0]['id_spbj']);
print(data[0]['minggu_ke']);
print(data[0]['hasil']);
print(data[0]['target_grafik']);
});
return json.decode(response.body);
}
// makeRequest() async {
// var response = await http.get(
// 'xxxxxxxxxxxxxxxxxxxxxxx',
// headers: {'Accept': 'application/json'},
// );
// setState(() {
// data = json.decode(response.body);
// jumlahData =data.length;
// });
// }
#override
void initState() {
_getData();
dataTotal = jumlahData;
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: new Text("Input Pelanggan hal 2"),
),
body: Column(
children: <Widget>[
SizedBox(
width: 600.0,
height: 250.0,
child: new charts.NumericComboChart(widget.seriesList,
animate: widget.animate,
defaultRenderer: new charts.LineRendererConfig(),
customSeriesRenderers: [
new charts.PointRendererConfig(customRendererId: 'customPoint')
]),
),
new Text("data"),
new Text("data"),
new Text("data")
],
),
);
}
}
/// Sample linear data type.
class LinearSales {
final int year;
final int sales;
LinearSales(this.year, this.sales);
}
values
[{"id_spbj":"1","minggu_ke":"1","hasil":"13.4353337","target_grafik":"25.00"},{"id_spbj":"1","minggu_ke":"2","hasil":"28.2629147","target_grafik":"25.00"},{"id_spbj":"1","minggu_ke":"3","hasil":"85.3285762","target_grafik":"25.00"},{"id_spbj":"2","minggu_ke":"1","hasil":"32.0184122","target_grafik":"25.00"},{"id_spbj":"2","minggu_ke":"2","hasil":"53.5296934","target_grafik":"25.00"}]
You can use FL_chart plugin library in flutter, where you draw all types of charts.
please find guideline to use FL_Chart