How to display multiple lines in UltraDataChart given a datatable - infragistics

I Have a datatable with 3 columns
Year (string)
Line name (string)
table.Columns.Add("YEAR", typeof(string));
table.Columns.Add("LINE_NAME", typeof(string));
table.Columns.Add("COUNT", typeof(double));
table.Rows.Add(new object[] {"2018", "Line1" , 2 });
table.Rows.Add(new object[] {"2017", "Line2" , 6 });
table.Rows.Add(new object[] {"2018", "Line2" , 1 });
table.Rows.Add(new object[] {"2011", "Line3" , 35 });
table.Rows.Add(new object[] {"2013", "Line3" , 143 });
table.Rows.Add(new object[] {"2014", "Line3" , 108 });
table.Rows.Add(new object[] {"2015", "Line3" , 50 });
table.Rows.Add(new object[] {"2016", "Line3" , 44 });
table.Rows.Add(new object[] {"2017", "Line3" , 34 });
table.Rows.Add(new object[] {"2013", "Line4" , 3 });
table.Rows.Add(new object[] {"2014", "Line4" , 6 });
table.Rows.Add(new object[] {"2015", "Line4" , 4 });
table.Rows.Add(new object[] {"2016", "Line4" , 1 });
table.Rows.Add(new object[] {"2017", "Line4" , 2 });
What i am trying to achieve is:
Have the X axis as the YEAR
Have the Y axis as the COUNT
Have a separate line on the line chart for each line in LINE_NAME column.
I can't for the life of me figure out how to do it using UltraDataChart...
Can someone please be kind enough to implement even a two line chart based on this given data as an example?
The amount of "lines" that will exist is technically unknown, but surely any concrete example can be converted into a more generic loop

UltraDataChart accepts as DataSource list of objects. What you need to do is first convert your data to a lists of objects like this:
var data = table.AsEnumerable() // convert the data to Enumerable so you can use linq over it
.Select(r => new { year = r["YEAR"], lineName = r["LINE_NAME"], count = r["COUNT"] }) // convert data to list of anonimous objects
.GroupBy(d => d.lineName, (key, value) => new { key = key, value = value.ToList() }) // group the data by line names
.ToArray();
Then you need to add a new series for each line name. First add the necessary axes you need:
var xAxis = new NumericXAxis();
var yAxis = new NumericYAxis();
myChart.Axes.Add(xAxis);
myChart.Axes.Add(yAxis);
Then go through the data you have created and add all the necessary series:
foreach (var line in data)
{
var lineData = line.value;
var series = new ScatterLineSeries();
series.XAxis = xAxis;
series.YAxis = yAxis;
series.XMemberPath = "year";
series.YMemberPath = "count";
series.DataSource = lineData;
myChart.Series.Add(series);
}

Related

How to count category value of array of List

let's say I have a list like the example below
<Categories>myList = [
Categories(
nameCategory: 'Book',
amount: '20'
),
Categories(
nameCategory: 'Book',
amount: '40'
),
Categories(
nameCategory: 'Food',
amount: '20'
),
Categories(
nameCategory: 'Food',
amount: '15'
),
];
How I can combine the duplicate values of that list and count the value of the list based on name ??
I can combine the list and the count value of the list but that only works just in a general list like sum total
what I want to do is make a new List but only combine several parts that share the same property like the same category or same class like that
this is an example what I want to achieve
<Categories> anotherList= [
Categories(
nameCategory: 'Book',
amount: '60'
),
Categories(
nameCategory: 'Food',
amount: '35'
),
];
I would replace your List<Categories> with a Map<String, Categories>. Then you can easily look up the Categories object given its name and mutate the existing Categories object. For example, something like:
var mergedCategories = <String, Categories>{};
for (var categories in myList) {
var name = categories.nameCategory;
var amount = categories.amount;
(mergedCategories[name] ??= Categories(nameCategory: name, amount: 0))
.amount += amount;
}
You're essentially trying to get an aggregate value from a list, which is what List.fold is meant to help with.
Here's an example of how you might use it:
class Category {
final String name;
int amount;
Category({required this.name, required this.amount});
String toString() => "Category(name: $name, amount: $amount)";
}
void main() {
final categories = [
Category(
name: 'Book',
amount: 20
),
Category(
name: 'Book',
amount: 40
),
Category(
name: 'Food',
amount: 20
),
Category(
name: 'Food',
amount: 15
),
];
/**
* Here is where the aggregation is done
*/
final List<Category> aggregated = categories.fold([], (list, item) {
try {
// Check whether the category is already in the aggregate
final existingCategory = list.firstWhere((c) => c.name == item.name);
// Category is already in the list, so just add the amount of the current item.
existingCategory.amount += item.amount;
return list;
} catch (_) {
// The category has not yet been added - so add it here
list.add(item);
return list;
}
});
print(aggregated);
}
I've changed your category class a bit for simplicity, but the principle should be the same. You can read more about the fold function here: https://api.dart.dev/stable/2.13.4/dart-core/Iterable/fold.html
A pretty straightforward method is by using the groupBy function provided by the collection.dart package.
import 'package:collection/collection.dart';
groupBy<Categories, String>(list, (c) => c.nameCategory).values.map(
(list) => list.reduce(
(a, b) => new Categories(a.nameCategory, a.amount + b.amount)
)
);

Linq query with group by with .NET Core

I'm trying to do a simple query. I want to have a list with a string and a Guid and a sub-list with a decimal and a string. I have my query this way but it keeps getting error when translated to Entity Framework what am I doing wrong?
Thanks in advance
var a = ( from c in DbContext.CC
join icc in DbContext.ICC c.Id equals icc.CCId
join i in DbContext.I on icc.IId equals i.Id
join p in DbContext.P on i.PId equals p.Id
select new
{
GuidId = p.Id,
StringN = p.StringN,
CCString = c.CCString ,
DecimalValue = icc.DecimalValue
}).GroupBy(x => new { x.GuidId , x.StringN }).
Select(x => new Model
{
GuidId = x.Key.GuidId ,
StringN = x.Key.StringN ,
Values= x.Select(y => new OtherModel
{
DecimalValue = y.DecimalValue ,
CCString = y.CCString
})
}
).OrderBy(x => x.StringN );
Error:
The LINQ expression '(GroupByShaperExpression:
KeySelector: new {
GuidId = (p.Id),
StringN = (p.Name)
},
ElementSelector:new {
GuidId = (ProjectionBindingExpression: GuidId ),
StringN = (ProjectionBindingExpression: StringN ),
CCString = (ProjectionBindingExpression: CCString ),
DecimalValue = (ProjectionBindingExpression: DecimalValue )
}
)
.Select(y => new OtherModel{
DecimalValue = y.DecimalValue ,
CCString = y.CCString
}
)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
It is SQL limitation. You cannot select grouped items, only Key and aggregation result is allowed.
Add AsEnumerable to your LINQ query to do grouping on the client side:
var a = (
from c in DbContext.CC
join icc in DbContext.ICC c.Id equals icc.CCId
join i in DbContext.I on icc.IId equals i.Id
join p in DbContext.P on i.PId equals p.Id
select new
{
GuidId = p.Id,
StringN = p.StringN,
CCString = c.CCString,
DecimalValue = icc.DecimalValue
})
.AsEnumerable()
.GroupBy(x => new { x.GuidId , x.StringN })
.Select(x => new Model
{
GuidId = x.Key.GuidId,
StringN = x.Key.StringN,
Values = x.Select(y => new OtherModel
{
DecimalValue = y.DecimalValue,
CCString = y.CCString
})
})
.OrderBy(x => x.StringN);

Type Mismatch error when altering a google.visualization.DataTable() column value even after explicitly changing its data type

I have a datatable that's being returned by google.visualization.data.group()
var aggData = google.visualization.data.group(
view,
[0],
aggColumns
);
I want to set several columns to be of type string with a tooltip role, and converting values in them to an html string
for (var col=2; col < aggData.getNumberOfColumns(); col = col + 2){
aggData.setColumnProperties(col,{'type':'string', 'role':'tooltip', 'p':{'html':true}});
//looking to see if the column type was actually changed
console.log('Column '+col+' type: ' + aggData.getColumnProperty(col, 'type'))
for (var row = 0; row < aggData.getNumberOfRows(); row = row + 1){
aggData.setValue(row, col, getHTML(aggData.getValue(row, col)))
}
}
function getHTML(count) {;
return 'Projects Completed: <b>' + count + '</b>';
}
I checked the column data type in the log and it does return a string but when i set the value to a string it throws a type mismatch error.
Column 2 type: string
Uncaught Error: Type mismatch. Value Projects Completed: <b>2</b> does not match type number in column index 2
I also tried setting the column type using setColumnProperty() method but it's the same result. What am I missing?
================================================================================================
Below is a snippet of the larger script if needed
Sample input data looks like
"Oct 1, 2019, 12:00:00 AM",Team C,68
"Sep 23, 2019, 12:00:00 AM",Team C,68
"Nov 29, 2019, 12:00:00 AM",Team C,87
"Dec 31, 2019, 12:00:00 AM",Team C,62
....................................
"Nov 21, 2018, 12:00:00 AM",Team A,79
"Dec 29, 2018, 12:00:00 AM",Team A,58
"Nov 15, 2018, 12:00:00 AM",Team B,96
"Dec 29, 2018, 12:00:00 AM",Team B,77
The data is being read into a data table
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Year');
data.addColumn('string', 'Team');
data.addColumn('number', 'Total Score');
var groupData = google.visualization.data.group(
data,
[
{
column: 0,
modifier: getYear,
type: 'number'
},
1
],
[
{
column: 2,
aggregation: google.visualization.data.sum,
type: 'number'
},
{
column: 2,
aggregation: google.visualization.data.count,
type: 'number',
role: 'tooltip'
}
]
);
// create data view from groupData
var view = new google.visualization.DataView(groupData);
// sum column array
var aggColumns = [];
// use year (column 0) as first view column
var viewColumns = [0];
// build calculated view & agg columns for each team
groupData.getDistinctValues(1).forEach(function (team, index) {
// add a column to the view for each team
viewColumns.push({
calc: function (dt, row) {
if (dt.getValue(row, 1) === team) {
return dt.getValue(row, 2);
}
return null;
},
label: team,
type: 'number'
});
viewColumns.push({
calc: function (dt, row) {
if (dt.getValue(row, 1) === team) {
return dt.getValue(row, 3);
}
return null;
},
label: 'Number of Projects',
type: 'number'
});
// add sum column for each team
aggColumns.push({
aggregation: google.visualization.data.sum,
column: index*2 + 1,
label: team,
type: 'number'
});
aggColumns.push({
aggregation: google.visualization.data.sum,
column: index*2 + 2,
type: 'number',
role: 'tooltip',
});
});
// set view columns
view.setColumns(viewColumns);
var aggData = google.visualization.data.group(
view,
[0],
aggColumns
);
/*
The aggData looks like
"2,018",137,2,173,2,0,0
"2,019",864,12,"1,028",12,610,12
*/
for (var col=2; col < aggData.getNumberOfColumns(); col = col + 2){
aggData.setColumnProperties(col,{'type':'string', 'role':'tooltip', 'p':{'html':true}});
console.log('Column '+col+' type: ' + aggData.getColumnProperty(col, 'type'))
for (var row = 0; row < aggData.getNumberOfRows(); row = row + 1){
aggData.setValue(row, col, getHTML(aggData.getValue(row, col)))
}
}
data table method setColumnProperties isn't doing what you expect.
it only sets the properties portion of the column --> 'p':{'html':true}
so after your code runs, you end up with the following in your column properties.
'p': {'type':'string', 'role':'tooltip', 'p':{'html':true}}
and in fact, it is not possible to change a column's type,
once it has been created.
instead, you'll need to either use the addColumn or insertColumn method.
another option would be to use a data view.
then you could use a calculated column for the tooltip,
and exclude the original column you are trying to change,
using the setColumns method on the data view.

Draw two google line charts from one data table

I collect data from my arduino sensors into a mysql table then use google graphs to draw line charts with the data. My data is temperature, humidity and a calculated humidex. Part of my project was to draw a guage with the current values which i was able to do. So I select the data into a data table, then filter them using a data view. Then draw three separate guages for each of the filtered values. The problem is temperatures usually go from -40 to 40 let's say and humidity from 0 to 100%, so drawing them in the same graph makes the graph looks flat as far as the temperatures are concerned.
My goal is to draw two graphs without having to query the database twice (if possible of course)
Below is the relevant code
echo "[new Date(" . $row["Year"] .", " .$row["Month"].", " .$row["Day"].", " .$row["Hour"].", " .$row["Min"]."), ". $temperature . ", " . $humidex . ", " . $humidity . "]";
var temp_view = new google.visualization.DataView(data);
temp_view.setRows([0,1,2]);
var humid_view = new google.visualization.DataView(data);
humid_view.setRows([0,3]);
var options = {'title':'Temperature', 'width':650, 'height':500};
var chart1 = new google.visualization.LineChart(document.getElementById('temp_chart'));
chart1.draw(temp_view, options);
var chart2 = new google.visualization.LineChart(document.getElementById('humid_chart'));
chart2.draw(humid_view, options);
if the data results in an array similar to the following...
[new Date(2018, 5, 29, 7, 26), 70, 75, 0.98]
then you only have one row with 4 columns
which means you should be using setColumns, instead of setRows...
try...
var temp_view = new google.visualization.DataView(data);
temp_view.setColumns([0,1,2]);
var humid_view = new google.visualization.DataView(data);
humid_view.setColumns([0,3]);
var options = {'title':'Temperature', 'width':650, 'height':500};
var chart1 = new google.visualization.LineChart(document.getElementById('temp_chart'));
chart1.draw(temp_view, options);
var chart2 = new google.visualization.LineChart(document.getElementById('humid_chart'));
chart2.draw(humid_view, options);

Google chart Showing zero in case of missing date in bar graph

I have an object which contains "Date" and "Amount".The object will contain the data for last seven days.If any one date is missing in the object I want to show the bar graph as 0 for that date.
Can someone help me with this issue?
Found the answer .Incase if any one require you can have a look at below code
var orders = _orderService.GetAll(c => c.RestaurantId == restaurantId && (c.Date > DateTime.Now.AddDays(-7))).OrderBy(x => x.Date).GroupBy(item => item.Date.Date).OrderBy(g => g.Key).
Select(i => new Order { Date = i.Key.Date, GrossAmount = i.Sum(w => w.GrossAmount) }).ToList();
var from = DateTime.Now.AddDays(-7);
var to = DateTime.Now.AddDays(-1);
var days = Enumerable.Range(0, 1 + to.Subtract(from).Days)
.Select(offset => from.AddDays(offset))
.ToArray();
var data = days.Select(i =>new Order{ Date=i.Date,GrossAmount=orders.Where(p=>p.Date==i.Date).Sum(w=>w.GrossAmount)}).ToList();