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
Related
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.
I am trying to get data from an API, pass it to the template with Jinja, and chart the data using CanvasJS.
When using baked in values, like in the CanvasJS examples, the graph displays properly; however, the second I try to use Jinja to input the values, the chart fails to show.
One reasons for the extra code, is that the API returns date in a "YYYY-MM-DD" form, whereas JS requires the individual values, so I split them using Jinja. Perhaps, I could split them using JS instead.
My CanvasJS code + Jinja looks like this:
window.onload = function () {
var chart = new CanvasJS.Chart("chartContainer",
{
title:{
text: "{{ ticker_symbol }}"
},
zoomEnabled: true,
axisY: {
includeZero:false,
title: "Prices",
prefix: "$ "
},
axisX: {
interval:2,
intervalType: "month",
valueFormatString: "MMM-YY",
labelAngle: -45
},
data: [
{
type: "candlestick",
dataPoints: [
{% for key, value in data.items() %}
{% set dates = key.split("-") %}
{x: new Date({{ dates[0] }}, {{ dates[1] }}, {{ dates[2] }}]),y:[{{ value['1. open'] }}, {{ value['2. high'] }}, {{ value['3. low'] }}, {{ value['4. close'] }}]},
{% endfor %}
]
}
]
});
chart.render();
}
The data is making it to the page, is displayed in the JS when viewing the source of the file in situ.
window.onload = function () {
var chart = new CanvasJS.Chart("chartContainer",
{
title:{
text: "MSFT"
},
zoomEnabled: true,
axisY: {
includeZero:false,
title: "Prices",
prefix: "$ "
},
axisX: {
interval:2,
intervalType: "month",
valueFormatString: "MMM-YY",
labelAngle: -45
},
data: [
{
type: "candlestick",
dataPoints: [
{x: new Date(2019, 11, 15]),y:[148.9300, 149.9900, 148.2700, 149.9700]},
...(repeated)...
]
}
]
});
chart.render();
}
But the graph still does not show!
I'm sure there is an issue with how the data is parsed into JS, but I am unable to spot it. One thing I noticed, is that the last date value is accompanied by an annoying "]" that does not seem to want to go away.
Any help would be greatly appreciated, thank you!
There was one major issue:
I had an extra ] when setting the x: variable for the chart. This is the primary thing that broke the entire graph.
The Jinja was fine. The JS was fine. My inability to hit {{ }} without making a square bracket was the issue.
Please commence public flogging.
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
Basic Problem
I'm making a bar graph using plotly.js where the x-axis represents dates. Dates are being fed to plotly as strings; when there are only 1 or 2 elements on the x-axis the labels don't match the strings being fed to plotly.
Context
This is part of a web-application using Flask and Python3, the data for the graph is coming from the Python backend; using console.log() statements I have confirmed that the arrays being given to plotly are as expected.
Example code that results in my error
x_labels = ["2019-01-14", "2019-01-15"]
y_axis = [11, 6]
var trace = {
type: 'bar',
x: x_labels,
y: y_axis,
}
var data = [trace]
var layout = {
xaxis: {
title: 'Date',
},
yaxis: {
title: 'Data'
}
}
Plotly.newPlot(graph, data, layout, {responsive: true})
JS Fiddle Demonstration
http://jsfiddle.net/yjk7r4x1/
Expected Output
The x-axis should just be showing dates such as Jan 13, 2019, Jan 14, 2019... etc. Instead, it is showing up as 12:00 Jan 13, 2019, 0:00 Jan 14, 2019... and so on. I assume those are meant to represent time, but I don't know where the time is coming from or why it is being displayed.
When defining your X-Axis you can modify it to include a "Type" and set the value to "category". By default, the library looks at the data attempts to determine the type for you if it is not specified. Here are what your changes should look like:
JFIDDLE:
http://jsfiddle.net/xa1uy5dz/
<head>
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<!-- Plotly chart will be drawn inside this DIV -->
<div id="incorrect_output" style="width: 100%; height: 500px;"></div>
<script>
graph = document.getElementById("incorrect_output");
x_labels = ["2019-01-14", "2019-01-15"]
y_axis = [11, 6]
var trace = {
type: 'bar',
x: x_labels,
y: y_axis,
}
var data = [trace]
var layout = {
xaxis: {
title: 'Date',
type: 'category'
},
yaxis: {
title: 'Data'
}
}
Plotly.newPlot(graph, data, layout, {responsive: true})
</script>
<div id="accurate_output" style="width: 100%; height: 500px;"></div>
<script>
graph = document.getElementById("accurate_output");
x_labels = ["2019-01-14", "2019-01-15", "2019-01-16"]
y_axis = [11, 6, 8]
var trace = {
type: 'bar',
x: x_labels,
y: y_axis,
}
var data = [trace]
var layout = {
xaxis: {
title: 'Date',
type: 'category'
},
yaxis: {
title: 'Data'
}
}
Plotly.newPlot(graph, data, layout, {responsive: true})
</script>
</body>
Referenced Info:
https://plot.ly/javascript/reference/#layout-xaxis-type
I have my canvas tag in my portfolio#show page:
<%= content_tag :canvas, "", id: "positions_chart", width: "300", height: "300", data: {positions: #positions } %>
In my portfolio.js file I have created a chartInstance object:
$(document).ready(function () {
var context = document.getElementById('positions_chart');
var ctx = context.getContext("2d");
var pieData = {
labels: $("#positions_chart").data(positions['name']),
datasets: [
{
backgroundColor: "rgba(220,220,220,1)",
borderColor: "rgba(220,220,220,1)",
data: $("#positions_chart").data(positions['quantity'])
}
]
}
var chartInstance = new Chart(ctx, {
type: 'pie',
data: pieData,
options: {
responsive: true
}
});
console.log(chartInstance);
});
I'm loading the data I want in the DOM -- a collection of position data.
<canvas id="positions_chart" width="600" height="600"
data-positions="[{"id":1,"ticker":"AAPL","name":"Apple Inc.",
"quantity":20,"portfolio_id":1,"created_at":"2016-10-22T18:19:36.255Z",
"updated_at":"2016-10-23T01:21:38.731Z","price":"116.6"},...
style="width: 300px; height: 300px;"></canvas>
The examples I've seen online are how to handle preloaded data within the data and dataset attributes in the js file. I want to have a pie chart with labels corresponding to the ticker names and using data from my rails database. I grab the data in the canvas tag and have access to it in my js file.
From what I understand, I'm passing the pieData object to the ctx object and whichever graph I chose (in this case pie) it should render the label and dataset to a graph. I'm not sure why the pie chart isn't showing up.
Is this what you want?
You can pass data you get from rails database and insert it into your js code immediately (no need to put it to data attribute in canvas tag).
I see you are using chart js v2 so no need to get context I think.
Also I fixed your code a little bit.
in your js code
$(document).ready(function() {
var positionsQuantity = <%= raw(#positions.map(&:quantity)) %>;
var positionName = <%= raw(#positions.map(&:name)) %>;
var ctx = $('#positions_chart');
var pieData = {
labels: positionName,
datasets: [
{
label: "pie labels",
data: positionsQuantity,
backgroundColor: "rgba(220,220,220,1)",
borderColor: "rgba(220,220,220,1)"
}]
}
var chartInstance = new Chart(ctx, {
type: 'pie',
data: pieData,
options: {
responsive: true
}
});
});
Hope it works!