Output array of hashes from Ruby on Rails to chart.js - javascript

I'm having some trouble preparing data from my Ruby on Rails project for use in chart.js, when using time as a second axis.
I've looked at various other questions and managed to get very close, but am having issues with exporting the data in a format that chart.js can recognise.
Thanks for your help!
Issue
I need the data to be printed in this form:
data: [
{"x":1567006282000,"y":145},
{"x":1567009767000,"y":120},
{"x":1567009838000,"y":130}
]
But am currently getting the following:
data: [
{"x":1567006282000,"y":145},
{"x":1567009767000,"y":120},
{"x":1567009838000,"y":130}
]
Current Attempt
I am creating the array as follows from within my controller, where reading_time and obs.heart_rate are integers, I think this is creating an array of hashes:
...
#hr.push ( { :x => reading_time, :y => obs.heart_rate } )
...
I then print this in my view, converting to json so that it would in theory work with the javascript library chart.js:
...
data: <%= #hr.to_json %>,
...
Pretty sure my issue is somewhere in the two lines above, but the full code is below in case it is needed.
Full Code
This is how I am creating (what I think) is an array of hashes within my controller:
def chart
# Load observations for specific patient
#observations = Observation.where(:patient_id => params[:patient_id]);
# Prep arrays
#readings = []
#hr = []
# Cycle through all observations for this patient
#observations.each do |obs|
# Convert created time to integer
# Multiple by 1000 as chart.js expects milliseconds while ruby uses seconds from UNIX epoch
reading_time = obs.created_at.to_i * 1000
# Add time to array so we can use this for the labels
#readings.push(reading_time)
# Create hash of time and observation value
hr_temp = {:x => reading_time , :y => obs.heart_rate }
# Push hash to the array
#hr.push( hr_temp )
# Repeat for other obserations - blood pressure, oxygen sats, etc
end
end
And finally how I am then printing that within my view:
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js" integrity="sha256-xKeoJ50pzbUGkpQxDYHD7o7hxe0LaOGeguUidbq6vis=" crossorigin="anonymous"></script>
<canvas id="myChart" width="400" height="400"></canvas>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var scatterChart = new Chart(ctx, {
type: 'line',
data: {
labels: <%= #readings %>,
datasets: [{
label: 'Heart Rate',
data: <%= #hr.to_json %>,
borderWidth: 1
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'X', // parse x values as unix timestamp
tooltipFormat: 'MMM Do, \'YY'
},
}]
}
}
});
</script>
Working Example
This is a working hard coded example showing what I am aiming for.
var ctx = document.getElementById('myChart').getContext('2d');
var scatterChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Heart Rate',
data: [
{"x":1567006282000,"y":145},
{"x":1567009767000,"y":120},
{"x":1567009838000,"y":130}
]
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'X', // parse x values as unix timestamp
tooltipFormat: 'MMM Do, \'YY'
},
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js" integrity="sha256-xKeoJ50pzbUGkpQxDYHD7o7hxe0LaOGeguUidbq6vis=" crossorigin="anonymous"></script>
<canvas id="myChart" width="400" height="400"></canvas>

Due to rendering, which uses to_s under the hood which could cause some encoding issues while rendering from a string type object. You should try using using html_safe method on the object returned by #hr.to_json like #hr.to_json.html_safe

Related

How to update a echart with a js function and 2D array

Good morning.
I need to do the following: Update a stacked line chart using a function in javascript that takes a 2d array ([[0,1],[0,2],...]).
My page is running in a Java fx webview so I can dynamically update my data. All the examples I've seen so far create a predefined X axis and pass the y values ​​accordingly, I wanted to pass the two values ​​together to plot a line on the chart.
How could I make this function? It's the first time I use echarts so I'm lost.
I even managed to do something similar but when plotting the chart it was all wrong.
Char Image
var option = {
xAxis: {
type: "value",
},
yAxis: {
type: "value",
},
series: [
{
type: "line",
data: [],
},
],
};
vibrationStackedLineChart.setOption(option);
function updateEchart(dataArray) {
// Parse the JSON string back into a 2D int array
var data = JSON.parse("[" + dataArray + "]");
// Update the chart with the new data
vibrationStackedLineChart.setOption({
series: [
{
data: data,
},
],
});
}
Java function with array 2d

Chart.js not displaying when passing dynamic labels

I am trying to draw a chart by passing values for labels and data dynamically using char.js.
The chart.js module refuses to accept the labels when passed as a variable.
When I hardcode it, it works just fine.
The label variable prints out the values on the page and seems to be correct in format.
Very similar to the problem described in the below query, except that I am already using a proper array.
[https://stackoverflow.com/questions/60453491/chart-js-not-showing-data-when-pass-dynamic-labels][1]
mypage.html:
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4"></script>
{{Messages.vm_size_in_use_labels}}
{{Messages.vm_size_in_use_data}}
<canvas id="chart" width="50" height="50"></canvas>
<script lang="JavaScript">
let ctx = document.getElementById("chart").getContext("2d");
let chart = new Chart(ctx, {
type: "pie",
data: {
labels: {{Messages.vm_size_in_use_labels}},
datasets: [
{
label: "Gross volume ($)",
backgroundColor: "#79AEC8",
borderColor: "#417690",
data: {{Messages.vm_size_in_use_data}},
}
]
},
options: {
title: {
text: "Gross Volume in 2020",
display: true
}
}
});
</script>
The page shows the printed value correctly but chart doesn't display:
['Standard_B1ls', 'Standard_D2_v2', 'Standard_D4s_v3', 'Standard_B1s']
[3, 3, 1, 1]
If I change the label to hard values,
labels: ['Standard_B1ls', 'Standard_D2_v2', 'Standard_D4s_v3', 'Standard_B1s'],
this works just fine and chart is displayed.
Not sure what is missing here. the framework is django if it matters.

Why prettier put a comma ',' at the last element of the object

In Visual studio code, When I am using chart.js in my app, prettier always put a comma at the end of the last data of the object 'label'. I think, it's create a bug which unable to show my chart on my browser. it show blank. Code is given bellow.
let massPopChart2 = new Chart(myChart2, {
type: "bar", // bar, horizontalBar, pie, line, doughnut, radar, polarArea
data: {
labels: [
"1st Day",
"2nd Day",
"3rd Day",
"4th Day",
"5th Day",
"6th Day",
"7th Day",
],
},
});
can anyone help me figure out why this happening?
JavaScript has allowed trailing commas in array literals since the
beginning, and later added them to object literals (ECMAScript 5) and
most recently (ECMAScript 2017) to function parameters.
This is a relatively new change in syntax, but the basic idea is that by putting a comma on each line allows for:
Easier to add an item or re-order items. Before you always had to check the trailing comma and make sure it was present or removed depending on location.
Removes the need to have one line item be special because it lacks the ,.
Allows for cleaner Git diffs.
You can read up on the full documentation if you like - it goes into further detail:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Trailing_commas
As far as the issue with your chart not displaying, unless you are using a very old browser, a trailing comma should not cause an error/information to not display.
You need to update the configuration of prettier extension.
There are two ways. Below one is mostly used.
Create a .prettierrc file at the root of your project and
specifying the below configuration.
{ "trailingComma": "es5" }
In order to honor the configuration make sure to enable the below
setting in vs code configuration.
"prettier.requireConfig": true
Prettier adds those commas at the end just because if you wanna add another data after that you don't need to type a comma. it does the same for semicolons(;).
you got the error because you haven't provided datasets.
data takes an object which contains labels & datasets values.
{/* <canvas id="myChart" width="400" height="400"></canvas> */}
// var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['1','2'],
datasets: [
{
label: '1st',
data: '120',
borderColor: Utils.CHART_COLORS.red,
backgroundColor: Utils.transparentize(Utils.CHART_COLORS.red, 0.5),
},
{
label: '2',
data: '240',
borderColor: Utils.CHART_COLORS.red,
backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
}
]
},
// options: {
// indexAxis: 'y',
// elements: {
// bar: {
// borderWidth: 2,
// }
// },
// responsive: true,
// plugins: {
// legend: {
// position: 'right',
// },
// title: {
// display: true,
// text: 'Chart.js Horizontal Bar Chart'
// }
// }
// },
// };
you can know more about it on official docs https://www.chartjs.org/docs/latest/charts/bar.html

'scales' option appears to break Chart.js graph

I'm trying to include a line chart for some stock data in my django project using Chart.js. I can render a simple chart with the data I want just fine, but when I try to format the x-axis for date and time, the chart doesn't render anymore. Here's the working version of the file (client_small_market_view.html):
{% load static %}
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4/dist/Chart.min.js"></script>
<div id="container" class="chartjs-wrapper">
<canvas id="stock-chart" class="chartjs" style="display: block;"></canvas>
</div>
<script>
var dateFormat = 'YYYY-MM-DD';
// the dates come ins as a list of strings formatted YYYY-MM-DD, so I use this function here to
// convert to Date
function parseDate(date){
var parts = date.split("-");
return new Date(parts[0], parts[1] - 1, parts[2])
};
var config = {
type: "line",
data: {
labels: {{ market_data.1|safe }}.map(dateString =>parseDate(dateString)),
datasets: [
{
label: "{{ market_data.0.0.0|safe }}",
data: {{ market_data.0.1.0|safe }},
fill: false,
},
],
},
options:{
title:{
text: 'Market',
display: true
},
}
};
var ctx = document.getElementById('stock-chart');
var chart = new Chart(ctx, config);
</script>
And here is the graph it produces on my end.
However, adding in the 'scales' option to format the x-axis labels like here
{% load static %}
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4/dist/Chart.min.js"></script>
<div id="container" class="chartjs-wrapper">
<canvas id="stock-chart" class="chartjs" style="display: block;"></canvas>
</div>
<script>
var dateFormat = 'YYYY-MM-DD';
function parseDate(date){
var parts = date.split("-");
return new Date(parts[0], parts[1] - 1, parts[2])
};
var config = {
type: "line",
data: {
labels: {{ market_data.1|safe }}.map(dateString =>parseDate(dateString)),
datasets: [
{
label: "{{ market_data.0.0.0|safe }}",
data: {{ market_data.0.1.0|safe }},
fill: false,
},
],
},
options: {
title:{
text: 'Market',
display: true
}
// when I take 'scales' out the chart renders fine,
// but I need it to format the x-axis dates
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'YYYY-MM-DD',
unit: 'day',
displayFormats: {
'day': 'YYYY-MM-DD'
}
},
ticks: {
source: 'data'
}
}]
}
}
};
var ctx = document.getElementById('stock-chart');
var chart = new Chart(ctx, config);
</script>
leaves me with a blank canvas. I've spent hours and hours trying to figure out what the problem is, but can't figure it out. For reference this html doc is included in a parent doc that serves as the home page for the app :
{% include './client_navbar.html'%}
{% include './client_small_market_view.html' with market_data=market_data%}
{% include './client_portfolios_summary_view.html' with portfolioss=portfolios %}
In addition I'm also using Bootstrap 4.4.1, but I can't imagine that's the reason for the problem. Any tips would be greatly appreciated!
It seems to work for me. Have you checked in your browser to make sure you're not getting any JS exceptions being thrown that are preventing the chart from being displayed?
Specifically, I believe you need to include the moment module (https://momentjs.com/) in order to use
type: 'time'
If the module is not loading for some reason, it could be throwing an exception and giving you a blank chart.
Here's another reference describing a similar problem: ChartJS not displaying time data using Moment.js

Two line chart from JSON on c3.js

i've got a JSON that store multiple value like this,
[
{"Description":"bankname1", "Month":"April", "Amount":"1700"},
{"Description":"bankname1", "Month":"June", "Amount":"1300"},
{"Description":"bankname1", "Month":"March", "Amount":"1500"},
{"Description":"bankname2", "Month":"March", "Amount":"100"},
{"Description":"bankname2", "Month":"April", "Amount":"1200"},
]
Into this JSON I've 12 Month for each Bankname (JSON can have multiple bank name).
I would like to show a line-bar for each bankname and on x axis show Month name.
At this moment I can see only one line chart with value of bank mixed on name line.
this is my code:
var chart = c3.generate({
bindto: '#c3_incassi',
data: {
json: data,
keys: {
x: 'MONTH',
value: ['AMOUNT']
},
type: 'line'
},
axis: {
x: {
type: 'category',
categories: ['GENNAIO', 'FEBBRAIO', 'MARZO', 'APRILE', 'MAGGIO', 'GIUGNO', 'LUGLIO', 'AGOSTO', 'SETTEMBRE', 'OTTOBRE', 'NOVEMBRE', 'DICEMBRE'],
}
}
});
How can I solve this problem?
Many thanks
Bye
Francesco
You need to get your json data into the correct format, as already commented by Abhas. The correct json format for c3.js line chart with multiple lines looks as follows:
{"bankname1":[1700,1300,1500,1100,1400,1800,2000,2100,1900,1100,1250,1050],"bankname2":[100,1200,300,1100,400,700,350,200,1200,1400,1050,900]}
The json string would contain the "bankname1" followed by 12 numeric values, one for each month, then "bankname2" followed by the 12 numeric values etc.
If you are using php at server-side, you can echo your json data, let's call it "dataset", into c3.js by:
var dataset = <?php echo $dataset; ?>;
data: {
json: dataset
},
I am doing it the excact same way and it works. The axis labels you can set up as in your code:
axis: {
x: {
type: 'category',
categories: ['GENNAIO', 'FEBBRAIO', 'MARZO', 'APRILE', 'MAGGIO', 'GIUGNO', 'LUGLIO', 'AGOSTO', 'SETTEMBRE', 'OTTOBRE', 'NOVEMBRE', 'DICEMBRE'],
}
}

Categories

Resources