Related
I'm using syncfusion package; in this case, it is an exponential moving average (EMA).
An EMA indicator is a simple, arithmetic moving average that is calculated by adding the closing price for the number of time periods and dividing the total value by the number of periods.
This is my code:
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class EMA extends StatefulWidget {
const EMA({super.key});
#override
State<EMA> createState() => _EMAState();
}
class _EMAState extends State<EMA> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SfCartesianChart(
primaryXAxis: DateTimeAxis(),
legend: Legend(isVisible: true),
indicators: <TechnicalIndicators<dynamic, dynamic>>[
EmaIndicator<dynamic, dynamic>(
seriesName: 'HiloOpenClose',
valueField: 'high',)],
series: <ChartSeries<ChartData, DateTime>>[
HiloOpenCloseSeries<ChartData, DateTime>( //hhere throws the error
name: 'HiloOpenClose')
]
)
)
);
}
}
class ChartData {
ChartData(this.x, this.low, this.high, this.open, this.close, );
final DateTime x;
final double? low;
final double? high;
final double? open;
final double? close;
}
My data:
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class CartesianChart extends StatefulWidget {
CartesianChart({Key? key, required this.title}) : super(key: key);
final String title;
#override
_CartesianChartState createState() => _CartesianChartState();
}
class _CartesianChartState extends State<CartesianChart> {
late List<ExpenseData> _chartData;
late TooltipBehavior _tooltipBehavior;
#override
void initState() {
_chartData = getChartData();
_tooltipBehavior = TooltipBehavior(enable: true);
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SfCartesianChart(
title: ChartTitle(
text: 'Hours focused \n Main activities'),
legend: Legend(isVisible: true),
tooltipBehavior: _tooltipBehavior,
series: <ChartSeries>[
StackedColumnSeries<ExpenseData, String>(
dataSource: _chartData,
xValueMapper: (ExpenseData exp, _) => exp.expenseCategory,
yValueMapper: (ExpenseData exp, _) => exp.father,
name: 'Node.js',
markerSettings: MarkerSettings(
isVisible: true,
)),
StackedColumnSeries<ExpenseData, String>(
dataSource: _chartData,
xValueMapper: (ExpenseData exp, _) => exp.expenseCategory,
yValueMapper: (ExpenseData exp, _) => exp.mother,
name: 'Flutter',
markerSettings: MarkerSettings(
isVisible: true,
)),
StackedColumnSeries<ExpenseData, String>(
dataSource: _chartData,
xValueMapper: (ExpenseData exp, _) => exp.expenseCategory,
yValueMapper: (ExpenseData exp, _) => exp.son,
name: 'Learn from youtube',
markerSettings: MarkerSettings(
isVisible: true,
)),
StackedColumnSeries<ExpenseData, String>(
dataSource: _chartData,
xValueMapper: (ExpenseData exp, _) => exp.expenseCategory,
yValueMapper: (ExpenseData exp, _) => exp.daughter,
name: 'MongoDB',
markerSettings: MarkerSettings(
isVisible: true,
)),
],
primaryXAxis: CategoryAxis(),
),
));
}
List<ExpenseData> getChartData() {
final List<ExpenseData> chartData = [
ExpenseData('Monday', 55, 40, 45, 48),
ExpenseData('Tuesday', 33, 45, 54, 28),
ExpenseData('Wednesday', 43, 23, 20, 34),
ExpenseData('Thursday', 32, 54, 23, 54),
ExpenseData('Friday', 56, 18, 43, 55),
ExpenseData('Saturday', 23, 54, 33, 56),
];
return chartData;
}
}
class ExpenseData {
ExpenseData(
this.expenseCategory, this.father, this.mother, this.son, this.daughter);
final String expenseCategory;
final num father;
final num mother;
final num son;
final num daughter;
}
What should I do in order to solve this problem?
Thanks for any help you can provide.
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;
}
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 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(),
),
);