Related
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"]),
);
}
The code reads a firebase database then add each read in a list of objects (SalesData class), chartdata.
The problem is when I update the list (chartdata) in the function readData() I can print it inside databaseReference.once().then((DataSnapshot snapshot) {}, but when it out of this bracket it is always empty. I an wondering how I could use this list in the chart constructor "dataSource: "
P.S if I hot reload the chart builds fine!!
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
// próximo passo: colocar os valores lidos do firebase em uma lista que seja
class _HomeState extends State<Home> {
List<SalesData> chartdata = [];
#override
Widget build(BuildContext context) {
// here I try to update the list chartdata, in order to build the chart
readData();
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Column(
children: <Widget>[
RaisedButton(
child: Text('Read Data'),
onPressed: () {
readData();
},
),
SfCartesianChart(
primaryXAxis: CategoryAxis(),
series: <LineSeries<SalesData, double>>[
LineSeries<SalesData, double>(
// Bind data source
dataSource: chartdata,
xValueMapper: (SalesData sales, _) => sales.year,
yValueMapper: (SalesData sales, _) => sales.sales)
])
],
));
}
final databaseReference =
FirebaseDatabase.instance.reference().child("UID/Esp_32");
void readData() {
databaseReference.once().then((DataSnapshot snapshot) {
Map<dynamic, dynamic> dados = snapshot.value;
dados.forEach((key, value) {
chartdata.add(SalesData(value['VoltageIn'], value['Sensor40']));
});
});
}
}
class SalesData {
SalesData(this.year, this.sales);
final double year;
final double sales;
}
First remove the method readData() at the beginning of the build method this could cause an infinite loop, you can call in the initState method.
So in your readData method you need to call setState to update the screen, like this:
void readData() {
databaseReference.once().then((DataSnapshot snapshot) {
Map<dynamic, dynamic> dados = snapshot.value;
dados.forEach((key, value) {
chartdata.add(SalesData(value['VoltageIn'], value['Sensor40']));
});
setState((){});
});
}
But I think that you should study some architecture to improve your code, like MVVM.
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(),
),
);
I am trying to display line chart from local JSON file in flutter. This is my JSON file,
[
{
"time": "20",
"distance": "10"
},
{
"time": "25",
"distance": "30"
}
]
This is the code where I am getting Json data from file in asset and decoding and map it in dart but it shows some error regarding Mapping.
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
import 'dart:convert';
class HomePage extends StatefulWidget {
final Widget child;
HomePage({Key key, this.child}) : super(key: key);
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<charts.Series<Calculation, int>> seriesBarData;
_generateData() async {
final load =
await DefaultAssetBundle.of(context).loadString("asset/data.json");
var decoded = json.decode(load);
List<Calculation> chartdata = [];
for (var item in decoded) {
chartdata.add(Calculation.fromJson(item));
}
seriesBarData.add(charts.Series(
data: chartdata,
domainFn: (Calculation chartdata, _) => chartdata.time,
measureFn: (Calculation chartdata, _) => chartdata.distance,
id: 'Performance',
));
setState(() {});
}
#override
void initState() {
super.initState();
seriesBarData = List<charts.Series<Calculation, int>>();
_generateData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.cyan,
title: Center(child: Text('flutter charts')),
),
body: Column(
children: [
Text(
'Distance to Lane',
style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
),
SizedBox(
height: 10.0,
),
if (seriesBarData.length > 0)
Expanded(
child: charts.LineChart(
seriesBarData,
animate: true,
animationDuration: Duration(seconds: 5),
domainAxis: new charts.OrdinalAxisSpec(
//viewport: new charts.OrdinalViewport('AePS', 9),
),
),
)
else
Container(),
],
),
);
}
}
class Calculation {
int time;
int distance;
Calculation(this.time, this.distance);
Calculation.fromJson(Map<int, dynamic> json) {
time = json['time'];
distance = json['distance'];
}
}
;
I have found that this error is regarding with Mapping of JSON as I am new to flutter and JSON so I do not know how to map it and use it in code.
change your fromJson constructor to
Calculation.fromJson(Map<String, dynamic> json) {
time = json['time'];
distance = json['distance'];
}
Also time and distance property is String
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