Create a Stacked Column Chart with series in javascript - javascript

I am trying to create a stacked column chart with 2 categories "Kosten" & "Stromertrag". Every category has it's own column with different values. Below is the attachment of what I want to achieve.
I tried to implement 4-5 chart libraries like canvasjs, highchart, etc. But they want the array of data. But in my case I have below json from which I want to build the same.
{
substratkosten: "9,000"
kosten1: "156,600"
kosten2: "298,286"
kosten3: "64,800"
strom2: "583,200"
substrat: "108,000"
}
Where first four values is for 'Kosten' category and last 2 values is for 'Stromertrag' category. I also tried to change the chart columns color, but I didn't found any property to achieve the same.
Can anyone please help to achieve the same?
Thanks in advance.

You can parse data in the format accepted by CanvasJS and render the chart. Below is the working code.
var jsonData = {
substratkosten: "9,000",
kosten1: "156,600",
kosten2: "298,286",
kosten3: "64,800",
strom2: "583,200",
substrat: "108,000"
};
var data = [];
for (var key in jsonData) {
if(key.includes("kosten")){
data.push({type: "stackedColumn", indexLabel: "{y}", dataPoints: [{x: 1, label: "Kosten", y: parseFloat(jsonData[key].replace(/,/g, ''))}]});
}
else {
data.push({type: "stackedColumn", indexLabel: "{y}", dataPoints: [{x: 2, label: "Stromertrag", y: parseFloat(jsonData[key].replace(/,/g, ''))}]})
}
}
var chart = new CanvasJS.Chart("chartContainer", {
title:{
text: "StackedColumn Chart"
},
data: data
});
chart.render();
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<div id="chartContainer" style="height: 300px; width: 100%;"></div>

Related

Draw pie chart using spring boot, thymeleaf, js, highchart but can't

I'm new with js and spring, now i want to create a html dashboard and this page will have a small div with pie chart. But i can't create pie chart.
I try some tutorial in youtube but now i want to pass value to ajax or something like that to get the pie chart.
Here is my Code:
admin_homepage.html:
<div class="col-xl-4 col-lg-5">
<div class="card shadow mb-4">
<!-- Thay chart vào thẻ div này -->
<div class="card-body">
<div class="chart-pie pt-4 pb-2">
<div id="chartContainer" style="height: 370px; width: 100%;"></div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$.ajax({
/* for pie chart */
url: "admin_home",
success: function(result){
/* pie chart starts here */
var series = [];
var data = [];
for(var i = 0; i < result.length; i++){
var object = {};
object.name = result[i].catName.toUpperCase();
object.y = result[i].catCount;
data.push(object);
}
var seriesObject = {
name: 'Course By Category',
colorByPoint: true,
data: data
};
series.push(seriesObject);
drawPieChart(series);
/* pie chart ends here */
}
});
/* for pie chart */
function drawPieChart(series){
Highcharts.chart('chartContainer', {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Browser market shares in January, 2018'
},
tooltip: {
formatter: function() {
return '<strong>'+this.key+': </strong>'+ this.y;
}
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.y}'
}
}
},
series: series
});
}
</script>
My Controller
#GetMapping("/admin_home")
public String viewHomePage(){
// Get list of course and count
List<CountCourse> pieChart = dashBoardRepository.countCourseByCategory();
model.addAttribute("pieChart",pieChart);
return "Admin_Homepage";
}
All i want is pass value of catName, catCount to pie chart but i can't
Any one help me. Many thanks.
Because you are using a Thymeleaf template, you are not required to use $.ajax({...}) to retrieve the pie chart data. Instead you can provide the data directly to the Thymeleaf template.
(Alternatively, you can continue to use an Ajax call - in which case, The Thymeleaf template will be rendered to HTML - and then as a separate step, the Ajax call will fetch the pie chart data.)
The following assumes the first approach (no Ajax needed):
No Ajax Needed
I took your Thymeleaf template in the question and made some changes to the script:
I removed the Ajax call.
I added a Thymeleaf variable to hold the chart data.
Here is the updated script:
<script th:inline="javascript">
// this simply wraps the code in a function
// that waits for the DOM to be ready:
(function () {
// this is populated by Thymeleaf:
var pieChartData = /*[[${pieChartData}]]*/ [];
var series = [];
var data = [];
for (var i = 0; i < pieChartData.length; i++) {
var object = {};
object.name = pieChartData[i].catName.toUpperCase();
object.y = pieChartData[i].catCount;
data.push(object);
}
var seriesObject = {
name: 'Course By Category',
colorByPoint: true,
data: data
};
series.push(seriesObject);
drawPieChart(series);
// draw the pie chart:
function drawPieChart(series) {
Highcharts.chart('chartContainer', {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Your Heading Goes Here'
},
tooltip: {
formatter: function () {
return '<strong>' + this.key + ': </strong>' + this.y;
}
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.y}'
}
}
},
// use the series data defined earlier:
series: series
});
}
})();
</script>
The key points about this script are:
The script tag looks like this:
<script th:inline="javascript">
This tells Thymeleaf that the script will contain one or more Thymeleaf expressions.
In our case we have one expression - here it is:
var pieChartData = /*[[${pieChartData}]]*/ [];
This syntax will cause Thymeleaf to replace the pieChartData variable with the data structure provided by the Java controller.
Here is that piece from the controller:
List<CountCourse> pieChartData = dashBoardRepository.countCourseByCategory();
model.addAttribute("pieChartData", pieChartData);
return "admin_homepage";
This assumes you have a CountCourse object which contains String catName and int catCount.
Thymeleaf will take the List<CountCourse> pieChartData data and generate the following JavaScript for you (using my test data):
var pieChartData = [
{"catName":"Humanities","catCount":123},
{"catName":"Sciences","catCount":145},
{"catName":"Other","catCount":67}
];
After that, I use the same logic as you have in your Ajax success function to convert this raw data into HightCharts pie chart data.
The end result is the following HTML page:
With Ajax
If you want to use your Ajax approach instead of this, then you need to build a separate end point which will return the pie chart data directly to the Ajax handler in your JavaScript code.
When you take this approach, you no longer need to use the Thymeleaf attribute:
var pieChartData = /*[[${pieChartData}]]*/ []; // NO LONGER NEEDED
And you no longer need to pass this data to your model in the controller:
model.addAttribute("pieChartData", pieChartData); // NO LONGER NEEDED
Instead, you need to continue using your $.ajax code and you need to build a separate end-point which returns the pieChartData as JSON for that Ajax call:
$.ajax({
/* for pie chart */
url: "piechart_data_json", // some new URL for your JSON pie chart data
...
});
Given you are using Thymeleaf already, I think there is no need for this approach.
Update
Just to explain the following syntax a bit more:
var pieChartData = /*[[${pieChartData}]]*/ [];
It looks like an empty JavaScript array []. But in fact, there is more to it.
The Thymeleaf variable ${pieChartData} receives the data from the controller.
Because the variable is in a <script> tag, it's not sufficient just to use the standard Thymeleaf ${pieChartData} expression. You also have to surround that expression with [[ and ]]. This is because ${pieChartData} is actually valid JavaScript - for example, as used in string interpolation.
That gives us this:
var pieChartData = [[${pieChartData}]];
This is all you need. This will work.
The problem here is, it's not valid JavaScript, so your IDE may highlight it as having a syntax error.
To work around this, you can take one extra step. You can "hide" the expression in a JavaScript comment - and then provide a valid value (the empty array). This keeps the JavaScript syntax checker happy in your IDE.
Thymeleaf will locate the variable inside that comment and remove it - and also remove the placeholder [] value.
That is how Thymeleaf pushes the Java model data into the template in this case.

Sending list information for google charts properly via flask to JS?

I'm mapping out ratings against episodes on a scatterplot on Google Charts. I have properly set the code up to send
data = [1, 8.7],[2, 8.8],[3, 8.3],[4, 8.4],[5, 9.3],[6, 8.9],[8, 9.3],[9, 8.4],[10, 8.3],[11, 8.4],[12, 8.9],[13, 8.7],[14, 9.2],[15, 9.1],[16, 8.6],[17, 8.9],[18, 9.3],[19, 9.3],[21, 8.7],[22, 8.5],[23, 8.3],[24, 8.7],[25, 9.3],[26, 9.6],[27, 8.8],[28, 8.5],[29, 7.8],[30, 8.5],[31, 9.5],[32, 9.7],[34, 8.3],[35, 8.1],[36, 8.7],[37, 8.7],[38, 8.5],[39, 8.9],[40, 9.3],[41, 8.9],[42, 9.6]
From Python to my graph.
Python:
def SendtoHTML():
dataPoint = data
return render_template('Scatter.html', series = series,finalEpNum = finalEpNum,minRatingFinal = minRatingFinal ,dataPoint = dataPoint)
if __name__ == '__main__':
app.run()
Script:
<script>
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var series = '{{series}}';
var finalEpNum = '{{finalEpNum}}'
var minRatingFinal = '{{minRatingFinal}}'
var data1 = google.visualization.arrayToDataTable([
['Episode', 'Rating'],
]);
var options = {
title: series,
hAxis: {title: 'Episode', minValue: 1, maxValue: finalEpNum},
vAxis: {title: 'Rating', minValue: minRatingFinal , maxValue: 10},
legend: true
};
var chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
chart.draw(data1, options);
}
Which currently creates a google charts graph with all blue points.
However, I want to change colors of the datapoints after a given [x] value until another given [x] value. Kinda like this graph I made in matplotlib where the colors change from blue to red after season 1 ends. How would I achieve this in python or JS?
you can use a style column role
in your JS, add the role as the last column heading.
(the style role should follow the series column it represents)
var data1 = google.visualization.arrayToDataTable([
['Episode', 'Rating', {role: 'style', type: 'string'}], // <-- add style role
]);
then in your data, you can add the color each point should be...
data = [1, 8.7, 'blue'],[2, 8.8, 'blue'],[3, 8.3, 'blue'],[4, 8.4, 'red'],[5, 9.3, 'red'],[6, 8.9, 'orange'],[8, 9.3, 'orange'],[9, 8.4, 'orange'],
Here is my working code now after properly formatting the data block.
Python
def SendtoHTML():
finalEpNumParsable = int(finalEpNum)
datapointTest = [[1, 8.7, "0000ff"],[2, 6.7, "orange"],[3, 8.7, "0000ff"],[4,6.7,'red']]
render = render_template('Scatter.html', dataPoint = datapointTest)
return render
JS
function drawChart() {
var dataPoint = {{ dataPoint | tojson }};
var series = '{{series}}';
var finalEpUnparsed = {{finalEpNum}}
var finalEpNum = parseInt(finalEpUnparsed, 10);
var minRatingFinal = '{{minRatingFinal}}'
var data1 = google.visualization.arrayToDataTable([
['Episode', 'Rating', { role: 'style', type: 'string' }], // <-- add style role
dataPoint[0]
]);
for (i = 1; i < finalEpNum-5; i++){
data1.addRows([dataPoint[i]]);}

Fix data to show with scroll bar with morris graph

I am using Morris Bar chart with php with data from mysql database
Now it is showing bar graph.
My question is:
There are about 100 rows in mysql database and they are increasing day by day.
My bar graph is displaying date wise data.
Can we fix number of days to display bargraph along with horizontal scroll bar to view previous data ?
Code I am using now is as follows :
<div id="graphdatewise"></div>
<script>
$(function () {
var graphdatewise = {
element: 'graphdatewise',
data: <?php echo json_encode($chartresult);?>,
xkey: 'cur_date',
ykeys: ['counter', 'counter_unique_visit'],
labels: ['PageViews', 'UniqueVisits'],
parseTime: true,
barColors: ['#F4FA58', '#00FFFF'],
xLabels: 'Date',
xLabelAngle: 70
}
bar1 = Morris.Bar(graphdatewise)
});
</script>
Now with this code, bars get resized and whole data is displayed in graph. Instead of that can we show 10 days data in graph with horizontal scroll bar to access rest data ?
It is not possbile to make a x-scroll with Morris chart. But I suppose that if you limit the width of the parent widder than the width of the chart, that should be ok. Something like:
<div id='parent' style='width: 100px;'>
<div id='graphdatewise' style='width: 50px;'></div>
</div>

anychart not taking dynamically added data

I am using anychart to draw a chart in my page, My code is like this
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdn.anychart.com/js/7.12.0/anychart-bundle.min.js"></script>
<link rel="stylesheet" href="https://cdn.anychart.com/css/7.12.0/anychart-ui.min.css" />
<input id="chart-charitytomoney" value="[["Charity 4",10.00],["Charity 2",20.00],["Charity Donate",100.00],["Donate Your Humanity",5920.00],["Gift your Work",3155.00],["Celebrate Baby Shower",770.00],["Refer Friends",110.00],["Gift Your Friends",200.00],["Celebrate B\u0027day With Us",220.00],["Celebrate Weekend",50.00],["Piggy Bank",4100.00],["Give a Single Gift",4050.00]]">
<div id="chart-container" style="height:550px!important"></div>
<script type="text/javascript">
$(document).ready(function(){
anychart.onDocumentReady(function () {
var data = $("#chart-charitytomoney").val();
// create column chart
chart = anychart.column();
// turn on chart animation
chart.animation(true);
// set chart title text settings
chart.title('Charities by donation');
// create area series with passed data
alert(data);
var series = chart.column(data);
// set series tooltip settings
series.tooltip().titleFormatter(function () {
return this.x
});
series.tooltip().textFormatter(function () {
return '$' + parseInt(this.value).toLocaleString()
});
series.tooltip().position('top').anchor('bottom').offsetX(0).offsetY(5);
// set scale minimum
chart.yScale().minimum(0);
// set yAxis labels formatter
chart.yAxis().labels().textFormatter("${%Value}");
// tooltips position and interactivity settings
chart.tooltip().positionMode('point');
chart.interactivity().hoverMode('byX');
// axes titles
chart.xAxis().title('Product');
chart.yAxis().title('Revenue');
// set container id for the chart
chart.container('chart-container');
// initiate chart drawing
chart.draw();
});
});
</script>
Everything looks okay to me, But chart is not working.
but if I changed this line
var data = $("#chart-charitytomoney").val();
to
var data = [["Charity 4", 10.00], ["Charity 2", 20.00], ["Charity Donate", 100.00], ["Donate Your Humanity", 5920.00], ["Gift your Work", 3155.00], ["Celebrate Baby Shower", 770.00], ["Refer Friends", 110.00], ["Gift Your Friends", 200.00], ["Celebrate B\u0027day With Us", 220.00], ["Celebrate Weekend", 50.00], ["Piggy Bank", 4100.00], ["Give a Single Gift", 4050.00]]
Everything works. Can anyone point out what I am doing wrong here? And How I can overcome it?
It is a peculiar way to pass data but you can do that, just:
Option 1
You should use quotes in the input field:
<input id="chart-charitytomoney" value="[['Charity 4',10.00],['Charity 2',20.00],['Charity Donate',100.00],['Donate Your Humanity',5920.00],['Gift your Work',3155.00],['Celebrate Baby Shower',770.00],['Refer Friends',110.00],['Gift Your Friends',200.00],['Celebrate B\u0027day With Us',220.00],['Celebrate Weekend',50.00],['Piggy Bank',4100.00],['Give a Single Gift',4050.00]]">
And you need to eval() the result:
var data = eval($("#chart-charitytomoney").val());
Here is a sample: http://jsfiddle.net/yr35w6nu/8/
However, eval is no quite secure, if you want to store data in a string in a field like this consider using code like this:
Option 2
var data = JSON.parse($("#chart-charitytomoney").val().replace(/\'/g,'\"'));
shown in this sample: http://jsfiddle.net/yr35w6nu/9/
The same may be applied to your code with &quote;:
var data = JSON.parse($("#chart-charitytomoney").val().replace(/\"/g,'\"'));
Sample parsing quotes: http://jsfiddle.net/yr35w6nu/10/
Option 3
There is also a way to store CSV formatted string:
<input id="chart-charitytomoney" value="Charity 4,10.00;Charity 2,20.00;Charity Donate,100.00;Donate Your Humanity,5920.00;Gift your Work,3155.00;Celebrate Baby Shower,770.00\nRefer Friends,110.00;Gift Your Friends,200.00;Celebrate B\u0027day With Us,220.00;Celebrate Weekend,50.00\nPiggy Bank,4100.00\nGive a Single Gift,4050.00">
and then use it:
var data = anychart.data.set($("#chart-charitytomoney").val(),{rowsSeparator: ';'});
http://jsfiddle.net/yr35w6nu/13/

Morris chart not showing the last xkey value with MVC

My Morris Chart is not showing the last xkey value:
Any ideia why?
My data is:
[{"Date":"2016-07-17","Average":0.0},{"Date":"2016-07-16","Average":0.0},{"Date":"2016-07-15","Average":4.125},{"Date":"2016-07-14","Average":0.0},{"Date":"2016-07-13","Average":0.0},{"Date":"2016-07-12","Average":0.0},{"Date":"2016-07-11","Average":0.0}]
The View:
<script>
var surveyLastDaysChartData = #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.SurveyLastDaysChartData));
</script>
<div class="col-lg-6">
<div class="card-box">
<h4 class="header-title m-t-0">Média dos últimos 7 dias</h4>
<div id="dsb-survey-last-days-chart" style="height: 217px;"></div>
</div>
</div><!-- end col -->
The script to build it:
var _surveyLastDaysChartId = "dsb-survey-last-days-chart";
Morris.Line({
// ID of the element in which to draw the chart.
element: _surveyLastDaysChartId,
// Chart data records -- each entry in this array corresponds to a point on the chart.
data: surveyLastDaysChartData,
// The name of the data record attribute that contains x-values.
xkey: 'Date',
// A list of names of data record attributes that contain y-values.
ykeys: ['Average'],
// Labels for the ykeys -- will be displayed when you hover over the chart.
labels: ['Média'],
resize: true,
hideHover: 'auto',
ymax: 5
});
This happened to me too.
I'm not sure how Morris calculates its elements, but sometimes, it cuts off values on the x-axis when it exceeds the width.
The way I was able to fix it (it is a hack, though) was to use their gridTextSize option and change it to a smaller font-size.
Example:
Morris.Line({
...
gridTextSize: 10,
...
});
Another option, if your app allows you to shorten your date, it to use their xLabelFormat option to parse your dates into a smaller format.
Example:
var display_date = function(d) {
var month = d.getMonth() + 1,
day = d.getDate();
var formattedDay = month + '-' + day
return formattedDay; // Return "M-DD" format for date
}
Morris.Line({
...
xLabelFormat: function(x) { return display_date(x); },
...
});
It's the default behaviour of Morris.js when the label is too long. You can use xLabelAngle, is and angle in degrees from horizontal to draw x-axis labels:
Morris.Line({
// ID of the element in which to draw the chart.
element: _surveyLastDaysChartId,
// Chart data records -- each entry in this array corresponds to a point on the chart.
data: surveyLastDaysChartData,
// The name of the data record attribute that contains x-values.
xkey: 'Date',
// A list of names of data record attributes that contain y-values.
ykeys: ['Average'],
// Labels for the ykeys -- will be displayed when you hover over the chart.
labels: ['Média'],
resize: true,
hideHover: 'auto',
xLabelAngle: 60, //<-- add this
ymax: 5
});
Demo: https://jsfiddle.net/iRbouh/hpq42x7b/

Categories

Resources