chart.js in mvc graph are not show - javascript

Here is chart script using chart. js i am using chart in mvc 4 chart are not show ,
data are shore in variable but when pass data from controller to view then data or not show in chart, error is system.string[] or in labels when i put in labels then array data are show when i check in browser console but error is something like this inactive is not define . please review the code tell me where i am wrong.
<script>
var PieChartData =
{
labels: [#ViewBag.b],
datasets: [{
label: 'ProductWise Sales Count',
backgroundColor: [
"#f990a7",
"#aad2ed",
"#9966FF",
"#99e5e5",
"#f7bd83",
],
borderWidth: 2,
data: [#ViewBag.a]
}]
};
window.onload = function () {
var ctx1 = document.getElementById("Piecanvas").getContext("2d");
window.myBar = new Chart(ctx1,
{
type: 'pie',
data: PieChartData,
options:
{
title:
{
display: true,
text: "ProductWise Sales Count"
},
responsive: true,
maintainAspectRatio: true
}
});
}
</script>
Now Here is Controler
ICharts _ICharts;
public ChartController()
{
_ICharts = new mchart();
}
[HttpGet]
public ActionResult PieChart()
{
try
{
float[] Total;
string[] status;
_ICharts.mTotalMember(out Total, out status);
ViewBag.a = Total;
ViewBag.b = status;
return View();
}
catch (Exception)
{
throw;
}
}
and this is my function
public class mchart : ICharts
{
public void mTotalMember(out float [] Total, out string[] Status)
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["Real"].ToString()))
{
var productdata = con.Query<Member>("Sp_testing", null, null, true, 0, CommandType.StoredProcedure).ToList();
var varTotal = (from temp in productdata
select temp.Percentage).ToArray();
var varStatus = (from temp in productdata
select temp.LeadStatus).ToArray();
Total = varTotal;
Status = varStatus;
}
}
}
Here is my function
void mTotalMember(out float[] Total, out string[] status);

Use JsonConvert.SerializeObject along with Html.Raw method to get a javascript array from the ViewBag item. You do not need to wrap it with [ and ] as the result of the expression #Html.Raw(JsonConvert.SerializeObject(ViewBag.b)) will be an array.
var myLabels = #Html.Raw(JsonConvert.SerializeObject(ViewBag.b));
var myData = #Html.Raw(JsonConvert.SerializeObject(ViewBag.a));
//Let's verify it
console.log(myLabels);
console.log(myData);
var PieChartData =
{
labels : myLabels,
datasets: [{
label: 'ProductWise Sales Count',
backgroundColor: [
"#f990a7",
"#aad2ed",
"#9966FF",
"#99e5e5",
"#f7bd83",
],
borderWidth: 2,
data: myData
}]
};

Related

If the entries in the model are made on the same date then the fields of this model must be summed up

I have a model
class paidparking(models.Model):
adress = models.ForeignKey(Parking, on_delete=models.SET_NULL, null=True, verbose_name='Адрес парковки')
carnumber = models.CharField(max_length=150,verbose_name='Номер автомобиля')
amountoftime = models.IntegerField(verbose_name='Количество времени')
price = models.FloatField(verbose_name='Цена')
telephone = models.CharField(max_length=20,verbose_name='Номер телефона')
email = models.EmailField(verbose_name='Электронный адрес',null=True,blank=True )
datetimepaidparking = models.DateTimeField(auto_now_add=True, verbose_name='Дата и время оплаты')
expirationdate = models.DateField(null=True,verbose_name='Дата начала срока действия')
expirationtime = models.TimeField(null=True,verbose_name='Время начала срока действия')
enddateandtime = models.DateTimeField(null=True,blank=True,verbose_name='Окончание срока действия')
There is a function
startdate = datetime.strptime(request.POST['startdate'], '%d.%m.%Y')
enddate = datetime.strptime(request.POST['enddate'], '%d.%m.%Y')
paymentparking = paidparking.objects.filter(expirationdate__range=(startdate, enddate)).values('expirationdate',
'price')
In JS, I get this data and draw graphs
$.ajax({
type: "POST",
url: "date",
data: {
'startdate': finalDateStrStart, 'enddate': finalDateStrEnd,
},
dataType: "json",
cache: false,
success: function (data) {
if (data.result) {
var expirationdates = [];
var prices = [];
for (let i = 0; i < data.result.length; i++) {
expirationdates.push(data.result[i].expirationdate);
prices.push(data.result[i].price);
}
if(window.chart instanceof Chart)
{
window.chart.destroy();
}
var ctx = document.getElementById("line").getContext("2d");
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: expirationdates,
datasets: [{
label: 'Оплата парковочных пространств',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(144,204,244)',
data: prices,
}]
},
options: {
}
});
var ctx = document.getElementById("bar").getContext("2d");
var chart = new Chart(ctx, {
type: 'bar',
data: {
labels: expirationdates,
datasets: [{
label: 'Оплата парковочных пространств',
backgroundColor: 'rgb(144,204,244)',
borderColor: 'rgb(255, 99, 132)',
data: prices,
}]
},
options: {
}
});
}
}
});
return JsonResponse({'result': list(paymentparking)})
As a result, I get:
I need to make a query that would sum the values from the price field for the same date in the expirationdate field
Right now my query outputs all records if the expirationdate field falls within the date range between startdate and enddate
You have to use the trick with values and annotate as described very well here:
from django.db.models import Sum
qs = paidparking.objects.values('expirationdate').annotate(Sum('price'))
# if you want to order by date:
qs = qs.order_by('expirationdate')
This will output a queryset a list of dictionnaries containing expirationdate and price__sum as keys.
Edit:
For your question in the comment, just add the filter at the beginning of the query:
paidparking.objects.filter(expirationdate__range=(startdate, enddate)).values('expirationdate').annotate(Sum('price'))
You need to use annotate in django orm to get the output for the same.
from django.db.models import Sum
PaidParking.objects.values('expirationdate', 'price') \
.annotate(parking_price=Sum('price')) \
.order_by('-expirationdate')
I suppose this answer is suffice for the asked query.
Reference: For Basic understanding of the query how it works follow this link

plotly.js page render is super slow with 10 charts in DOM. firefox freezes. whats wrong?

I am getting super slow page loads (~10s on chrome, ~15 using firefox) when rendering a page with 10 Plotly charts (lines and bars) with very few data points on each chart (<100 per chart).
I'm not getting any errors, and my js code runs in ~300ms without errors (i used console.log() with timestamps). there is no network activity whilst waiting for the charts to render.
Am I doing something wrong?
The charts are rendered using a loop which calls a function with different parameters:
ajax call:
$.ajax({
method: "GET",
url: '/app/api/dashboard/data',
success: function(payload){
console.log('starting bal hist')
var bal_hist = JSON.parse(payload.balance_history);
balanceHistoryChart(elementID='balanceHistory', data=bal_hist);
console.log('ending bal hist')
var data = JSON.parse(payload.aggregated);
data = data.map(function(object) {
object.value_date = new Date(object.value_date);
return object
})
var allCategories = data.map(x => x.category);
var categories = new Set(allCategories);
console.log('starting loop')
for (var category of categories){
var chartID = category.toLowerCase().replace(' ','_') + '_chart';
console.log('starting catChart')
catChart(elementID=chartID, category=category, data=data)
console.log('ending catChart')
}
console.log('end loop')
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
function that creates the plotly charts:
function catChart(elementID, category, data) {
let filterForCat = data.filter(obj => obj.category === category);
let dates = filterForCat.map(function(obj) {
return obj.value_date
});
let weeklyTotal = filterForCat.map(function(obj) {
return obj.weekly_total
});
let movingAv = filterForCat.map(function(obj) {
return obj.moving_av
});
var movingAvSeries = {
type: "scatter",
mode: "lines",
name: '4-week average',
x: dates,
y: movingAv,
line: {color: 'green'}
};
var weeklyTotalSeries = {
type: "bar",
name: 'weekly totals',
x: dates,
y: weeklyTotal,
line: {color: 'red'}
};
var layout = {
showlegend: false,
title: false,
margin: {
l: 30,
r: 20,
b: 20,
t: 20,
pad: 5
},
};
var data = [ movingAvSeries, weeklyTotalSeries ];
var config = {
responsive: true,
displayModeBar: false,
};

ChartJs - displaying data dynamically from back-end

I have been struggling with this one for days now, really need some help. I need to apply gradient colors and some custom styling to our ChartJs bar chart, that contains call reporting data which comes from the back-end server. I found a way how to apply the styles and gradients, but can't figure out how to configure datasets to display correct data from the server, instead of some random numbers (eg. 10,20,30), like I tried for gradientGreen below. Any ideas?
//main html
<div class="row mb-4 mt-4">
<div class="col-9">
<h4 class="text-center">Call Distribution</h4>
#await Component.InvokeAsync("HourlyCallTotals", new { from = Model.From, to = Model.To, customer = Model.customer, site = Model.site })
</div>
//component html
#model CallReporter.ViewModels.BasicFilter
<div id="hourlyChart">
</div>
<script>
var HourlyCallData = #Html.RenderAction("HourlyTotals", "Calls", "", new { from = Model.from.ToString("s"), to = Model.to.ToString("s"), customer = Model.customer, site = Model.site })
</script>
//relevant part of JS function for Chart
function hoursChartAjax() {
var hourlyChart = $('#hourlyChart').html('<canvas width="400" height="300"></canvas>').find('canvas')[0].getContext('2d');
// set gradients for bars
let gradientGreen = hourlyChart.createLinearGradient(0, 0, 0, 400);
gradientGreen.addColorStop(0, '#66d8b0');
gradientGreen.addColorStop(1, '#1299ce');
let gradientBlue = hourlyChart.createLinearGradient(0, 0, 0, 400);
gradientBlue.addColorStop(0, '#1299ce');
gradientBlue.addColorStop(1, '#2544b7');
if (hourlyChart !== undefined) {
$.get(base + "Calls/HourlyTotals", { from: from.format(), to: to.format(), customer: currentCustomer.id, site: currentSite }, function (data) {
// set the default fonts for the chart
Chart.defaults.global.defaultFontFamily = 'Nunito';
Chart.defaults.global.defaultFontColor = '#787878';
Chart.defaults.global.defaultFontSize = 12;
var chart = new Chart(hourlyChart, {
type: 'bar',
data: {
labels: ['6AM', '9AM', '12AM', '3PM', '6PM', '9PM', '12PM'],
datasets: [
{
label: 'Total outgoing calls',
backgroundColor: gradientBlue,
data: HourlyCallData
},
{
label: 'Total incoming calls',
backgroundColor: gradientGreen,
data: [10, 20, 30]
}
]
},
//relevant part of back-end code that returns call data as Json
totalsContainer.Totals = allCallsHourly.OrderBy(x => x.Date).ToList();
return Json(new
{
labels = totalsContainer.Totals.Select(x => x.Date.ToString("hh tt")),
datasets = new List<object>() {
new { label = "Total Outgoing Calls", backgroundColor = "#1299CE", data = totalsContainer.Totals.Select(x => x.TotalOutgoingCalls) },
new { label = "Total Incoming Calls", backgroundColor = "#00B050", data = totalsContainer.Totals.Select(x => x.TotalIncomingCalls) } }
});
Attached img with console log and error, after trying solution below:
If the data comes formatted in the right way, you can just write this:
var chart = new Chart(hourlyChart, {
type: 'bar',
data: data: data
}
If not you could do it like so:
var chart = new Chart(hourlyChart, {
type: 'bar',
data: {
labels: data.labels,
datasets: [
{
label: data.datasets[0].label,
backgroundColor: gradientBlue,
data: data.datasets[0].data
},
{
label: data.datasets[1].label,
backgroundColor: gradientGreen,
data: data.datasets[1].data
}
]
}
}

How can I plot Charts w/ time x axis from JSON and MySQL in Chart.JS?

I'd like to plot some charts using Chart.js.
I have a script that gets two arrays from a database in JSON format.
The two arrays are:
-An array of Temperature (float)
-An array of Time (Obtained by the Database at the moment in which a temperature enters it by means of the function Current_Timestamp ())
I'd like to be able to graph the temperatures depending on the date with Chart.js
$(document).ready(function(){
$.ajax({
url : "http://localhost/js/data.php",
type: "GET",
success : function(data) {
console.log(data);
var datos = {
VectorTemp : [],
VectorFecha : []
}
var len = data.length;
for (var i = 0; i<len;i++){
if (data[i].chipID == 1){
datos.VectorTemp.push(data[i].temp);
datos.VectorFecha.push(data[i].fecha);
}
}
console.log(datos);
var ctx = $("#line-chartcanvas");
var data = {
labels: [],
datasets: [
{
x: datos.VectorFecha[1],
y: datos.VectorTemp[1]
}
]
};
var options = {
responsive: true,
title: {
display: true,
text: "Chart.js Time Scale"
},
}
var chart = new Chart (ctx, {
type: "line",
data : data,
options: options
});
},
error: function(data) {
console.log(data);
},
});
});

Set Additional Data to highcharts series

is there any way to pass some additional data to the series object that will use to show in the chart 'tooltip'?
for example
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
Highcharts.dateFormat('%b %e', this.x) +': '+ this.y;
}
here we can only use series.name , this.x & this.y to the series. lets say i need to pass another dynamic value alone with the data set and can access via series object. is this possible?
Thank you all in advance.
Yes, if you set up the series object like the following, where each data point is a hash, then you can pass extra values:
new Highcharts.Chart( {
...,
series: [ {
name: 'Foo',
data: [
{
y : 3,
myData : 'firstPoint'
},
{
y : 7,
myData : 'secondPoint'
},
{
y : 1,
myData : 'thirdPoint'
}
]
} ]
} );
In your tooltip you can access it via the "point" attribute of the object passed in:
tooltip: {
formatter: function() {
return 'Extra data: <b>' + this.point.myData + '</b>';
}
}
Full example here: https://jsfiddle.net/burwelldesigns/jeoL5y7s/
Additionally, with this solution, you can even put multiple data as much as you want :
tooltip: {
formatter: function () {
return 'Extra data: <b>' + this.point.myData + '</b><br> Another Data: <b>' + this.point.myOtherData + '</b>';
}
},
series: [{
name: 'Foo',
data: [{
y: 3,
myData: 'firstPoint',
myOtherData: 'Other first data'
}, {
y: 7,
myData: 'secondPoint',
myOtherData: 'Other second data'
}, {
y: 1,
myData: 'thirdPoint',
myOtherData: 'Other third data'
}]
}]
Thank you Nick.
For time series data, especially with enough data points to activate the turbo threshold, the proposed solutions above will not work. In the case of the turbo threshold, this is because Highcarts expects the data points to be an array like:
series: [{
name: 'Numbers over the course of time',
data: [
[1515059819853, 1],
[1515059838069, 2],
[1515059838080, 3],
// you get the idea
]
}]
In order not to lose the benefits of the turbo threshold (which is important when dealing with lots of data points), I store the data outside of the chart and look up the data point in the tooltip formatter function. Here's an example:
const chartData = [
{ timestamp: 1515059819853, value: 1, somethingElse: 'foo'},
{ timestamp: 1515059838069, value: 2, somethingElse: 'bar'},
{ timestamp: 1515059838080, value: 3, somethingElse: 'baz'},
// you get the idea
]
const Chart = Highcharts.stockChart(myChart, {
// ...options
tooltip: {
formatter () {
// this.point.x is the timestamp in my original chartData array
const pointData = chartData.find(row => row.timestamp === this.point.x)
console.log(pointData.somethingElse)
}
},
series: [{
name: 'Numbers over the course of time',
// restructure the data as an array as Highcharts expects it
// array index 0 is the x value, index 1 is the y value in the chart
data: chartData.map(row => [row.timestamp, row.value])
}]
})
This approach will work for all chart types.
I am using AJAX to get my data from SQL Server, then I prepare a js array that is used as the data in my chart.
JavaScript code once the AJAX is successfull:
...,
success: function (data) {
var fseries = [];
var series = [];
for (var arr in data) {
for (var i in data[arr]['data'] ){
var d = data[arr]['data'][i];
//if (i < 5) alert("d.method = " + d.method);
var serie = {x:Date.parse(d.Value), y:d.Item, method:d.method };
series.push(serie);
}
fseries.push({name: data[arr]['name'], data: series, location: data[arr]['location']});
series = [];
};
DrawChart(fseries);
},
Now to show extra meta-data in the tooltip:
...
tooltip: {
xDateFormat: '%m/%d/%y',
headerFormat: '<b>{series.name}</b><br>',
pointFormat: 'Method: {point.method}<br>Date: {point.x:%m/%d/%y } <br>Reading: {point.y:,.2f}',
shared: false,
},
I use a DataRow to iterate through my result set, then I use a class to assign the values prior to passing back in Json format. Here is the C# code in the controller action called by Ajax.
public JsonResult ChartData(string dataSource, string locationType, string[] locations, string[] methods, string fromDate, string toDate, string[] lstParams)
{
List<Dictionary<string, object>> dataResult = new List<Dictionary<string, object>>();
Dictionary<string, object> aSeries = new Dictionary<string, object>();
string currParam = string.Empty;
lstParams = (lstParams == null) ? new string[1] : lstParams;
foreach (DataRow dr in GetChartData(dataSource, locationType, locations, methods, fromDate, toDate, lstParams).Rows)
{
if (currParam != dr[1].ToString())
{
if (!String.IsNullOrEmpty(currParam)) //A new Standard Parameter is read and add to dataResult. Skips first record.
{
Dictionary<string, object> bSeries = new Dictionary<string, object>(aSeries); //Required else when clearing out aSeries, dataResult values are also cleared
dataResult.Add(bSeries);
aSeries.Clear();
}
currParam = dr[1].ToString();
aSeries["name"] = cParam;
aSeries["data"] = new List<ChartDataModel>();
aSeries["location"] = dr[0].ToString();
}
ChartDataModel lst = new ChartDataModel();
lst.Value = Convert.ToDateTime(dr[3]).ToShortDateString();
lst.Item = Convert.ToDouble(dr[2]);
lst.method = dr[4].ToString();
((List<ChartDataModel>)aSeries["data"]).Add(lst);
}
dataResult.Add(aSeries);
var result = Json(dataResult.ToList(), JsonRequestBehavior.AllowGet); //used to debug final dataResult before returning to AJAX call.
return result;
}
I realize there is a more efficient and acceptable way to code in C# but I inherited the project.
Just to add some kind of dynamism :
Did this for generating data for a stacked column chart with 10 categories.
I wanted to have for each category 4 data series and wanted to display additional information (image, question, distractor and expected answer) for each of the data series :
<?php
while($n<=10)
{
$data1[]=array(
"y"=>$nber1,
"img"=>$image1,
"ques"=>$ques,
"distractor"=>$distractor1,
"answer"=>$ans
);
$data2[]=array(
"y"=>$nber2,
"img"=>$image2,
"ques"=>$ques,
"distractor"=>$distractor2,
"answer"=>$ans
);
$data3[]=array(
"y"=>$nber3,
"img"=>$image3,
"ques"=>$ques,
"distractor"=>$distractor3,
"answer"=>$ans
);
$data4[]=array(
"y"=>$nber4,
"img"=>$image4,
"ques"=>$ques,
"distractor"=>$distractor4,
"answer"=>$ans
);
}
// Then convert the data into data series:
$mydata[]=array(
"name"=>"Distractor #1",
"data"=>$data1,
"stack"=>"Distractor #1"
);
$mydata[]=array(
"name"=>"Distractor #2",
"data"=>$data2,
"stack"=>"Distractor #2"
);
$mydata[]=array(
"name"=>"Distractor #3",
"data"=>$data3,
"stack"=>"Distractor #3"
);
$mydata[]=array(
"name"=>"Distractor #4",
"data"=>$data4,
"stack"=>"Distractor #4"
);
?>
In the highcharts section:
var mydata=<? echo json_encode($mydata)?>;
// Tooltip section
tooltip: {
useHTML: true,
formatter: function() {
return 'Question ID: <b>'+ this.x +'</b><br/>'+
'Question: <b>'+ this.point.ques +'</b><br/>'+
this.series.name+'<br> Total attempts: '+ this.y +'<br/>'+
"<img src=\"images/"+ this.point.img +"\" width=\"100px\" height=\"50px\"/><br>"+
'Distractor: <b>'+ this.point.distractor +'</b><br/>'+
'Expected answer: <b>'+ this.point.answer +'</b><br/>';
}
},
// Series section of the highcharts
series: mydata
// For the category section, just prepare an array of elements and assign to the category variable as the way I did it on series.
Hope it helps someone.

Categories