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.
Related
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
I want to show a line chart on my "Weights" index page with Chart.js in my Rails app (a weight loss app). I have a table that holds a user's weight (as "kilograms") for each day (as "day"). I am able to show a line chart, however, but only with static data - not with the data from my Weights table.
What I want to do now is to have "day" on the x-axis and "kilograms" on the y-axis.
How can I achieve this? And as I just started coding few months ago: how should the code look like?
Thx a lot.
This is the code from my weights index.html.erb:
<canvas id="myChart" width="400" height="200"></canvas>
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["day 1", "day 2", "day 3", "day 4", "day 5", "day 6"],
datasets: [{
label: 'My Weight',
data: [82.4, 79.6, 79.3, 78.4, 77.5, 75.1],
backgroundColor: [
'rgba(0, 0, 0, 0.1)',
],
borderColor: [
'rgba(0,0,0,0.9)',
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:false
}
}]
}
}
});
</script>
The main thing that had me stuck forever was that Chart.js relies on calling its tooltiptemplate with <% however this would then be interpreted by ERB and cause a problem. The workaround is adding another % which tells erb not to interpret the tags it otherwise would have. That's not very well documented but what are you going to do. As for the rest, in your view-page.html.erb file you want to add the chart scripts at the bottom:
Set your timeline X-Axis (I'll show you how to load it dynamically but this could be static if you want in which case just enter them directly into the timeline array):
<script type="text/javascript">
$(function() {
var lineData = {
<% timeline = []
datapoints = []
#workout.each do |workout|
timeline << workout.day
datapoints << workout.weight
end
%>
//The "raw" method is needed to stop the auto escaping of the output. Test this out in your console and you will notice the output is formatted like "[\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\"]" This escaping of quotes causes errors in js...
labels: <%= raw timeline.to_json %>,
datasets: [{
label: "Weight Gain/Loss",
fillColor: "rgba(26,179,148,0.5)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#127A65",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: <%= raw datapoints.to_json %>,
}]
};
If you want to set some options remember to use the <%% tag for tooltips!
var lineOptions = {
scaleOverride : true,
tooltipTemplate: "<%%if (label){%>(<%%=label%>) <%%}%><%%= value %> pounds",
};
//NOTE THE ABOVE TOOLTIP REQUIRES A SECOND % SIGN ON OPENING TAGS SO THAT IS IS TAKEN LITERALLY AND NOT INTERPRETED BY RAILS ERB!!!!!!!!
var ctx = document.getElementById("myChart").getContext("2d");
var myNewChart = new Chart(ctx).Line(lineData, lineOptions);
});
</script>
I, too, was struggling with getting this to work on Rails, but I discovered that I did not have to use the Rails template escape characters that chart.js says that you do. In my case (needing to show a zero in the label when the value is set to 0.1), this is what I did:
tooltipTemplate: function(context){
var labelVal = (context.value == '0.1')? '0' : context.value;
var newLabel = context.label + ': ' + labelVal;
return newLabel;
}
I'm writing a django web app and I use highcharts for printing graphs. I have to use some tricks to actually make it work in django but there is something I just can't figure out.
Take a look here:
http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/highcharts/demo/spline-symbols/
There is a sun and cloud for highest and lowest temperature. I'd like to make something similar.
My views.py looks something like this:
# load data to variable last_day_data
class Chartdata(object):
def load_last_day():
values = Temperature.objects.raw('SELECT...')
for x in values:
last_day_data['avg_temperature'].append(round(x.avg_temperature,2))
last_day_data['date'].append('%s:00' % x.id)
return last_day_data
# set-up highcharts variables and pass to home.html
def home(request):
last_day_data = Chartdata.load_last_day()
chart3 = {"renderTo": 'chart_3', "type": 'line', "height": 300,}
title3 = {"text": 'Last 24 Hours Temperature'}
xAxis3 = {"title": {"text": 'Date'}, "categories": last_day_data['date'], "reversed": 'true'}
yAxis3 = {"title": {"text": 'Temperature [°C]'}}
series3 = [{"name": 'Temperature [°C]', "data": last_day_data['avg_temperature']}]
chart = {
'chartID3': 'chart_3',
'chart3': chart3,
'series3': series3,
'title3': title3,
'xAxis3': xAxis3,
'yAxis3': yAxis3
}
return render(request, 'home.html', chart)
And quick look at home.html (actually only part of it responsible for mapping passed data to highchart variables):
<script>
$(document).ready(function() {
$({{ chartID3|safe }}).highcharts({
chart: {{ chart3|safe }},
title: {{ title3|safe }},
xAxis: {{ xAxis3|safe }},
yAxis: {{ yAxis3|safe }},
series: {{ series3|safe }}
});
});
</script>
Right now, after loading my website, code above ('series' exactly) looks like this:
series: [{'name': 'Temperature [°C]', 'data': [12.0, 13.11, 14.59, 14.6, 14.36, 14.09, 13.73....]}]
What I have to do: find highest value and replace it with (according to jsfiddle):
{{y: highest_value, marker: {symbol: 'url(sun url)'}}
Finding highest value is easy, let say I have it stored in 'value' under 'index' so I do:
last_day_data['avg_temperature'][index] = "{y: %s, marker: {symbol: 'url(sun url)'}}" % value
But graph isn't displaying correctly and looking at site source:
series: [{'name': 'Temperature [°C]', 'data': [12.0, 13.11, 14.59, "{y: 14.6, marker: {symbol: 'url(sun url)'}}", 14.36, 14.09, 13.73, 13.29, 12.86, 12.82.... ]}]
Conclusion: it's not working with quotes and I have no idea how to get rid of them. Any ideas how to do it quick, easy and painlessly?
Finally figured it out, changed it to:
last_day_data['avg_temperature'][index_max] = "{\"y\": %s, \"marker\":" \
" {\"symbol\": \"url(%ssun.png)\"}" \
"}" % (value_max, settings.STATIC_URL)
And inside home.html:
var series = {{ series3|safe }};
var obj = series[0]['data'];
for(var x in obj){
if(typeof obj[x] === "string") obj[x] = JSON.parse(obj[x]);
}
series[0]['data'] = obj;
$({{ chartID3|safe }}).highcharts({
chart: {{ chart3|safe }},
title: {{ title3|safe }},
xAxis: {{ xAxis3|safe }},
yAxis: {{ yAxis3|safe }},
series: series
});
Now it works perfectly!
I am using Highcharts to plot JSON Data. The dates are in the string format.
JSON Data:
[{"BRENT_SPOT":70.88,"TRADE_DATE":"31-JUL-2009"},{"BRENT_SPOT":73.28,"TRADE_DATE":"03-AUG-2009"},{"BRENT_SPOT":74.31,"TRADE_DATE":"04-AUG-2009"},{"BRENT_SPOT":74.96,"TRADE_DATE":"05-AUG-2009"},{"BRENT_SPOT":74.4,"TRADE_DATE":"06-AUG-2009"},{"BRENT_SPOT":72.84,"TRADE_DATE":"07-AUG-2009"},{"BRENT_SPOT":73.29,"TRADE_DATE":"10-AUG-2009"},{"BRENT_SPOT":72.04,"TRADE_DATE":"11-AUG-2009"}]
HighCharts / JQuery Code :
<script>
var chart;
$(function() {
var options = {
chart: {
renderTo: 'container',
zoomType: 'xy',
type: 'line'
},
title: {
text: 'Brent Daily Price Curve (FPC as at <cfoutput>#f_date#</cfoutput>)'
},
xAxis: {
labels: {
rotation: 45,
step: 3
},
type: 'category'
},
yAxis: {
lineWidth: 1,
title: {
text: '$ USD'
},
min: 0
},
series: []
};
$.getJSON("brentpricehc_test.cfm?f_date=<cfoutput>#f_date#</cfoutput>", {}, function(jsonResult) {
var BrentUSDPrice = {
name: "Brent Spot (USD)",
type: "line",
data: [],
marker: {
radius: 2
}
};
$(jsonResult).each(function(index) {
BrentUSDPrice.data.push([this.TRADE_DATE, this.BRENT_SPOT]);
});
/*options.series[0] = BrentUSDPrice;*/
options.series.push(BrentUSDPrice);
chart = new Highcharts.Chart(options);
});
});
</script>
I'm unable to plot any values wrt each of the date strings. I tried converting the JSON dates to datetime instead but still the same issue.
Few More details (for testing purposes):
Modifying to the below line plots the graph with the correct "brent_spot" values. This means that the issue lies with the way the "trade_dates" are 'not' plotting.
BrentUSDPrice.data.push([index, this.BRENT_SPOT]);
Edit 2 : (Using Datetime type to make the code work)
JSON Data (New): Returned as TO_CHAR(TRADE_DATE, 'YYYY/MM/DD')
[{"BRENT_SPOT":70.88,"TRADE_DATE":"2009\/07\/31"},{"BRENT_SPOT":73.28,"TRADE_DATE":"2009\/08\/03"},{"BRENT_SPOT":74.31,"TRADE_DATE":"2009\/08\/04"},{"BRENT_SPOT":74.96,"TRADE_DATE":"2009\/08\/05"},{"BRENT_SPOT":74.4,"TRADE_DATE":"2009\/08\/06"},{"BRENT_SPOT":72.84,"TRADE_DATE":"2009\/08\/07"},{"BRENT_SPOT":73.29,"TRADE_DATE":"2009\/08\/10"},{"BRENT_SPOT":72.04,"TRADE_DATE":"2009\/08\/11"}]
$(jsonResult).each(function(index) {
BrentUSDPrice.data.push([new Date(this.TRADE_DATE), this.BRENT_SPOT]);
});
Server side language used : Coldfusion
Database : Oracle
Am I doing something silly somewhere?
I have just tried your code, and it works perfectly fine, see: http://jsfiddle.net/3bQne/1026/
I guess, you need to update to Highcharts 3.0.10 to get this working.
If you are using type: 'category' then you need to assign name: to the data points. See the categories entry at http://api.highcharts.com/highcharts#xAxis
If categories are present for the xAxis, names are used instead of numbers for that axis. Since Highcharts 3.0, categories can also be extracted by giving each point a name and setting axis type to "category".
So the question is whether you are using Highcharts 3.0 and if you do then it needs to look something like this:
data: [{
name: 'Point 1',
color: '#00FF00',
y: 0
}, {
name: 'Point 2',
color: '#FF00FF',
y: 5
}]
see: http://api.highcharts.com/highcharts#series.data
I'm a rails noob, and trying to figure out how to graph some data in a database using high charts. I have the following code for the chart:
<script type="text/javascript" charset="utf-8">
$(function() {
new Highcharts.Chart({
chart: {
renderTo: "pdd_graph"
},
title: {
text: "Percent Depth Dose"
},
xAxis: {
type: "datetime"
},
yAxis: {
max: 1.4,
min: 1.2,
title: {
text: "measmt"
}
},
series: [{
pointStart: <%= 12.months.ago.to_i * 1000 %>,
data: <%= (12.months.ago.to_date..Date.today).map { |test_date| #pdd.field_5x5 } %>,
name: '5cm X 5cm Field'
}]
});
});
</script>
I want to graph the columns test_date and field_5x5 from a table called pdd . I'm just having a hard time with the proper syntax. Any help would be appreciated.
Thanks.
I came across your post while researching an issue of my own. You may need to add .inspect on the end of your data: <%= (12.months.ago.to_date..Date.today).map { |test_date| #pdd.field_5x5 } %>, line. I would like to claim credit for this wisdom but I picked it up from Ryan's Railscast on Highcharts
Another thing I did was move that logic into my controller, assign it to a var and then pass the var along... that is not going well.