Show a "Bar" for zero results with morris.js - javascript

I'm using Morris.js to display data in charts, Id like to show a bar for every option, even if its zero, currently I get this:
As you can see the values for 'HIV Instant' for age group 21-25 and 26-30 are 0, how would I show a line (just a thin one) for each result? is this possible with Morris? I've searched the docs for bar charts & searched google & SO but cant find anything? Any help is appreciated. Cheers
Here is the code for generating said chart:
// break up the object
var age_barParts = [];
$.each( results_by_age_chart, function(key , val){
age_barParts.push({
'test': key,
'u16': val['u16'],
'16-20': val['16-20'],
'21-25': val['21-25'],
'26-30': val['26-30'],
'31-49': val['31-49'],
'50+': val['50+']
});
});
//build the graph
var age_bar = Morris.Bar({
element: 'age_bar',
data: age_barParts,
xkey: ['test'],
ykeys: ['u16', '16-20', '21-25', '26-30', '31-49', '50+'],
labels: ["Under 16s", "16 to 20", "21 to 25", "26 to 30", "31 to 49", "Over 50s"],
barColors: color_array,
hideHover: 'auto',
resize: 'true',
gridTextSize: 16,
gridTextColor: '#5cb85c',
xLabelAngle: '70',
resize: true,
padding: 40
});

In Morris.js there is no option to force drawing of a line for zero values, but you can set them to a very low non-zero value, for example 0.05.
Below an example with Morris:
var age_barParts = [];
age_barParts.push({
'test': 'HIV',
'u16': 3,
'16-20': 5,
'21-25': 1,
'26-30': 2,
'31-49': 8,
'50+': 2
});
age_barParts.push({
'test': 'HIV Instant',
'u16': 1,
'16-20': 4,
'21-25': 0.05,
'26-30': 0.05,
'31-49': 7,
'50+': 3
});
var age_bar = Morris.Bar({
element: 'age_bar',
data: age_barParts,
xkey: ['test'],
ykeys: ['u16', '16-20', '21-25', '26-30', '31-49', '50+'],
labels: ["Under 16s", "16 to 20", "21 to 25", "26 to 30", "31 to 49", "Over 50s"],
hideHover: 'auto',
resize: 'true',
gridTextSize: 16,
gridTextColor: '#5cb85c',
xLabelAngle: '70',
resize: true,
padding: 40
});
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
<div id="age_bar" style="height: 450px;"></div>
As alternative you can adopt Highcharts which has a specific plotOption.
Below an example with Highcharts:
$(function () {
$('#age_bar').highcharts({
chart: {
type: 'column'
},
title: {
text: 'HIV stats'
},
xAxis: {
categories: ['HIV', 'HIV Instant']
},
yAxis: {
title: {
text: '#'
}
},
plotOptions: {
column: {
minPointLength: 3
}
},
colors: ["#0b62a4","#7a92a3","#4da74d","#afd8f8","#edc240","#cb4b4b","#9440ed"],
series: [{
name: 'u16',
data: [1, 0]
}, {
name: '16-20',
data: [5, 4]
}, {
name: '21-25',
data: [1, 0]
}, {
name: '26-30',
data: [2, 0]
}, {
name: '31-49',
data: [8, 7]
}, {
name: '50+',
data: [2, 3]
}],
});
});
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//code.highcharts.com/highcharts.js"></script>
<div id="age_bar" style="height: 450px;"></div>
Update:
Here is a jsfiddle (for Morris) which modifies the hover legend replacing 0.05 with 0. You can improve this approach editing the hoverCallback function:
https://jsfiddle.net/beaver71/zm8wt4pj/

If you compile from coffee script files, just add after lastTop += size in morris.bar.coffee
if size == 0 then size = 1
Otherwise, if you just want to modify the javascript file, just add after lastTop += size; in morris.js
if (size === 0) { size = 1; }

Related

Highcharts update x-axis categories dynamically

i'm looking for help with updating the x-axis categories on a Highcharts chart with periodically received data.
The chart is defined in a file called forecastgraph.html. It is loaded to index.php, the webpage where I want it displayed, by means of <?php require("widget/forecastgraph.html"); ?>. The chart renders as expected.
Live data which is handled via a js script (called mqtt.js) that receives incoming mqtt data in json format and using jquery updates various parts of index.php in this way: $("#elementid").html(a.b.c);. I load mqtt.js in the head of index.php using <script src="./js/mqtt.js"></script> This again works flawlessly.
What I am struggling with is how to pass incoming data from mqtt.js to the chart to update it as new data comes in. Specifically, I am trying to update the xAxis categories and the corresponding value pairs. Periodically, mqtt.js receives a new weather forecast and so the xAxis categories need to be updated with the new time period that the forecast applies to and the data needs to be updated to reflect the new high and low temperatures for the respective forecast periods.
The code for the chart is posted below. Any help would be appreciated.
Baobab
<script type="text/javascript">
$(function () {
$('#forecastgraph').highcharts({
chart: {
type: 'columnrange',
backgroundColor: 'rgba(0,0,0,0)',
borderWidth: 0,
margin: [12, 6, 36, 20]
},
title: {
text: null,
},
exporting: {
enabled: false
},
credits: {
enabled: false
},
xAxis: {
categories: [1,2,3,4],
labels: {
y: 30,
style: {
color: 'white',
fontSize: '10px',
fontWeight: 'bold'
}
}
},
yAxis: {
title: {
enabled: false,
x: -14,
},
labels: {
align: 'left'
},
maxPadding: 0.5,
plotLines: [{
value: 10, //normmax
width: 2,
color: '#FF0000'
},{
value: 2, //normmin
width: 2,
color: '#009ACD'
}]
},
tooltip: {
enabled: false
},
plotOptions: {
columnrange: {
dataLabels: {
enabled: true,
style: {
textOutline: 'none'
},
crop: false,
overflow: 'none',
formatter: function () {
var color = this.y === this.point.high ? '#33C4FF' : 'red';
return '<span style="font-size: 12px; font-family:helvetica; font-weight:normal; text-shadow: none; color:' + color + '">' + this.y + '°</span>';
}
}
}
},
legend: {
enabled: false
},
series: [{
name: 'Temperatures',
data: [
[20, -3],
[5, -2],
[6, -2],
[8, -15]
],
color: '#b9deea',
borderColor: '#92cbde',
borderRadius: 4
}]
});
});
</script>
EDIT: Additional Information.
The incoming json data looks like this:
[{
"period": "Monday",
"condition": "Cloudy",
"high_temperature": "7",
"low_temperature": "-2"
"icon_code": "10",
"precip_probability": "20"
}, {
"period": "Tuesday",
"condition": "A mix of sun and cloud",
"high_temperature": "6",
"low_temperature": "-2"
"icon_code": "02",
"precip_probability": "20"
}, {
"period": "Wednesday",
"condition": "A mix of sun and cloud",
"high_temperature": "3",
"low_temperature": "-5"
"icon_code": "02",
"precip_probability": "20"
}, {
"period": "Thursday",
"condition": "A mix of sun and cloud",
"high_temperature": "1",
"low_temperature": "-10"
"icon_code": "02",
"precip_probability": "20"
}]
The function responsible for the incoming json formatted data in the mqtt.js script loaded to index.php handles the incoming data in this way (mqtt.js is started when index.php is loaded):
function onMessageArrived(message) {
console.log("onMessageArrived: " + message.payloadString);
//Env Canada forecast
if (message.destinationName == "myHome/ec/json_data_ec") {
var data = JSON.parse(message.payloadString);
$("#forecast_period_1").html(data[0].period); // update div forecast_period_1 in index.php for debugging purposes and show that data is coming in
forecast_period_1 = (data[0].period); // assign to global var
forecast_period_1_high = (data[0].high_temperature); // global var
forecast_period_1_low = (data[0].low_temperature); // global var
Updating various html elements throughout index.php with the incoming data works great and is stable. What I have attempted to do, but with no success, is to update the chart using the data placed in the global variables (declared as global at he beginning of the script) by the mqtt.js script. In the example above, forecast_period_1 needs to be used as the first of the four xAxis categories and forecast_period_1_high and forecast_period_1_low, to update the respective hi and lo values in the chart's data.
Is this an output that you want to achieve? In the below demo, I wrote a function that takes a high and low temperatures value and next is triggered on the button. The new data is attached to the chart via using the series.update feature.
Demo: https://jsfiddle.net/BlackLabel/he768cz3/
API: https://api.highcharts.com/class-reference/Highcharts.Series#update
I have found a solution for it. First, you have to store the chart in a variable then after you are able to update chart data. Like below
var chart = $('#forecastgraph').highcharts({ ...option })
Update xAxis or series data
// Update xAxis data label
chart.update({
xAxis: {
categories: [1,2,3,4]
}
});
// Update series data
chart.series[0].update({
data: [
[20, -3],
[5, -2],
[6, -2],
[8, -15]
]
});

Replace chart code of data-ui-options attribute

I'm new with this and I'd like to know how can I replace the chart code into attribute data-ui-options unsing JQUERY.
<div id="graficoHell" data-ui-jp="echarts" data-ui-options="{
xAxis: {
data: ['a', 'b', 'c', 'd'],
axisTick: {show: false},
axisLabel: {
formatter: 'barGap: \'-100%\''
}
},
yAxis: {
splitLine: {show: false}
},
animationDurationUpdate: 1200,
series: [{
type: 'bar',
itemStyle: {
normal: {
color: '#ddd'
}
},
silent: true,
barWidth: 40,
barGap: '-100%', // Make series be overlap
data: [60, 60, 60, 60]
}, {
type: 'bar',
barWidth: 40,
z: 10,
data: [4, 60, 13, 25]
}]
} " style="height:300px" >
I tried the same code as string into JavaScript but it did not work.
$('#graficoHell').attr('data-ui-options', "same_string_into_data-ui-options");
All examples I saw, was using echarts object, but the template I bought is in this way.
Even though this is an old question I may answer it anyway.
You can use the element.dataset function in order to query / change data of an html element.
Querying the data according to the documentation:
<div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth>John Doe</div>
const el = document.querySelector('#user');
// el.id == 'user'
// el.dataset.id === '1234567890'
// el.dataset.user === 'johndoe'
// el.dataset.dateOfBirth === ''
Updating data:
const el = document.querySelector('#user');
el.dataset.dateOfBirth = '1960-10-03';

chart width changes when a trendline is added in highcharts

I'm facing a serious problem. Whenever I try to add any trendline starting from a bit below to the top of the chart (near about 70-85 degree angle), it changes its width. But in case of vertical and horizental line I'm not facing the problem. Is there any way to prevent this?
My code is:
$(function() {
$.getJSON('http://api-sandbox.oanda.com/v1/candles?instrument=EUR_USD&candleFormat=midpoint&granularity=W', function(data) {
// create the chart
var onadata =[];
var yData=[];
var type='line';
var datalen=data.candles.length;
var all_points= [];
var all_str="";
for(var i=0; i<datalen;i++)
{
var each=[Date._parse(data.candles[i].time), data.candles[i].openMid, data.candles[i].highMid, data.candles[i].lowMid, data.candles[i].closeMid]
onadata.push(each);
yData.push(data.candles[i].closeMid);
}
chart();
function chart()
{
$('#container').highcharts('StockChart', {
credits: {
enabled : 0
},
rangeSelector : {
buttons: [{
type: 'month',
count: 1,
text: '1M'
}, {
type: 'month',
count: 3,
text: '3M'
},{
type: 'month',
count: 6,
text: '6M'
},{
type: 'all',
text: 'All'
}],
selected:3
},
legend: {
enabled: true,
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
title : {
text : 'Stock Price'
},
xAxis :{
minRange : 3600000
},
chart: {
events: {
click: function(event) {
var x1=event.xAxis[0].value;
var x2 =this.xAxis[0].toPixels(x1);
var y1=event.yAxis[0].value;
var y2 =this.yAxis[0].toPixels(y1);
selected_point='['+x1+','+y1+']';
all_points.push(selected_point);
all_str=all_points.toString();
if(all_points.length>1)
{
this.addSeries({
type : 'line',
name : 'Trendline',
id: 'trend',
data: JSON.parse("[" + all_str + "]"),
color:'#'+(Math.random()*0xEEEEEE<<0).toString(16),
marker:{enabled:true}
});
}
if(all_points.length==2)
{
all_points=[];
}
}
}
},
series : [{
//allowPointSelect : true,
type : type,
name : 'Stock Price',
id: 'primary',
data : onadata,
tooltip: {
valueDecimals: 5,
crosshairs: true,
shared: true
},
dataGrouping : {
units : [
[
'hour',
[1, 2, 3, 4, 6, 8, 12]
], [
'day',
[1]
], [
'week',
[1]
], [
'month',
[1, 3, 6]
], [
'year',
[1]
]
]
}
},
]
});
}
});
});
and this is my JSfiddle.
Please check the images also.
Normal chart
Chart with trendline
This is normal. It is adjusting the height of the chart (not the width) to accommodate the points you are adding. It adds a little buffer to make the chart point a bit more readable.
You can also use min/max parameters or set tickPositions / tickPositioner to keep ticks always in the same postions.
Docs: http://api.highcharts.com/highcharts

Loading Javascript Highcharts series data issues

Server is sending back data like this:
{"barData":
[
{"Accepted":[0,0,0]},
{"Rejected":[0,0,0]},
{"In_Process":[0,1,0]}]
}
In the browser, it shows up as such:
My perhaps (and very likely) incorrect belief was that this was the correct structure to populate a Highcharts stacked bar chart as seen here:
Example Stacked Bar in jsFiddle
The example in the documentation shows a fixed data set that appears like this:
series: [{
name: 'John',
data: [5, 3, 4, 7, 2]
}, {
name: 'Jane',
data: [2, 2, 3, 2, 1]
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5]
}]
This is what I was attempting to emulate. So, at the end of all that, I get a zero plot. My Javascript looks like this:
$.ajax({
url : 'http://localhost:8080/afta/report/transfersbynetwork',
success : function(point) {
data = [];
$.each(point.barData, function(itemNo, item) {
data.push([ item[0], parseInt(item[1][0]), parseInt(item[1][1]), parseInt(item[1][2])]);
});
barchart = new Highcharts.Chart(baroptions);
baroptions.series[0].data = data;
},
cache : false
});
So where did I bone this up? I'm getting no plot and am quite convinced the problem is either in my presentation of the data from the server (possible) or in the javascript that's parsing the data structure and loading the series (highly likely).
Any insight would be appreciated.
Based on your structure, you need to change your function to process the data:
$(function () {
var point = {
"barData": [{
"Accepted": [1, 2, 3]
}, {
"Rejected": [3, 4, 5]
}, {
"In_Process": [0, 1, 0]
}]
},
data = [];
$.each(point.barData, function (itemNo, item) {
for (var prop in item) {
data.push({
name: prop,
data: [parseInt(item[prop][0]), parseInt(item[prop][1]), parseInt(item[prop][2])]
});
}
});
$('#container').highcharts({
chart: {
type: 'bar'
},
title: {
text: 'Stacked bar chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears']
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
}
},
legend: {
backgroundColor: '#FFFFFF',
reversed: true
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: data
});
});
http://jsfiddle.net/9jVJb/

Using different symbols for plotting data not working

I am attempting to use a different symbol for one of my data series on my flot graph as it is at a much larger scale then the rest of the data. I am using this example as reference: http://www.flotcharts.org/flot/examples/symbols/index.html
Here is what I have so far:
My includes:
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.flot.js"></script>
<script type="text/javascript" src="jquery.flot.symbol.js"></script>
I then configure my flot options like so:
var options = {
grid: {hoverable : true},
xaxis: { mode: "time", timeformat: "%H:%M", tickLength: 1},
series: { points : { show: true } }
};
I then actually plot the data:
$.plot('#placeholder', [{
data: my_data,
lines: { show : true},
points: { symbol: "square"},
color: '#CB4B4B',
label: 'My Data'
}], options);
}
However, flot is still graphing the points as the default circle. I get no error messages in firebug and I have even tried adding a logging message in the jquery.flot.symbol.js library itself to see if the "square" handler is even being called like so:
var handlers = {
square: function (ctx, x, y, radius, shadow) {
console.log("Square handler was called");
// pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2
var size = radius * Math.sqrt(Math.PI) / 2;
ctx.rect(x - size, y - size, size + size, size + size);
},
I am getting no console messages so I am assuming the handler is not getting called correctly. Am I missing something here?
EDIT:
Example of data I am trying to plot:
var d1 = [
[1364342400000, 208],
[1364346000000, 107],
[1364353200000, 42],
[1364371200000, 1680],
[1364360400000, 52],
[1364349600000, 67],
[1364385600000, 1118],
[1364367600000, 163],
[1364382000000, 1359],
[1364378400000, 1468],
[1364389200000, 1023],
[1364356800000, 63],
[1364374800000, 1601],
[1364392800000, 556],
[1364364000000, 84],
],
d2 = [
[1364342400000, 86],
[1364346000000, 42],
[1364353200000, 13],
[1364371200000, 458],
[1364360400000, 10],
[1364349600000, 22],
[1364385600000, 453],
[1364367600000, 45],
[1364382000000, 369],
[1364378400000, 379],
[1364389200000, 358],
[1364356800000, 17],
[1364374800000, 471],
[1364392800000, 147],
[1364364000000, 16],
],
d3 = [
[1364342400000, 7],
[1364346000000, 5],
[1364382000000, 11709],
[1364371200000, 58336],
[1364360400000, 1],
[1364349600000, 1],
[1364367600000, 2],
[1364389200000, 1191],
[1364378400000, 9085],
[1364385600000, 4688],
[1364374800000, 9386],
[1364392800000, 1140],
[1364364000000, 1],
];
I have also edited my options parameter and how the plot function is called:
var options = {
grid: {hoverable : true},
xaxis: { mode: "time", timeformat: "%H:%M", tickLength: 1}
};
$.plot("#placeholder", [{
data: d1,
lines: { show : true },
points: { show: true},
color: '#EDC240',
label: "d1"
}, {
data: d2,
lines: { show : true },
points: { show : true},
color: '#AFD8F8',
label: "d2"
}, {
data: d3,
yaxis: 2,
lines: { show : true},
points: { show: true, symbol: "square"},
color: '#CB4B4B',
label: "d3"
}], options);
I am also sure that the symbol library is being included because I have added some logging itself to the library and that is showing up fine.
I see no issue with what you've done. I made a quick working example here: http://jsfiddle.net/ryleyb/shLtU/1/
I would guess that you haven't included the symbol library (even though you say you have).
Or show your data, might somehow be an issue there (doubtful?).
This is the full flot code I ran to make a working example (plus including flot and the symbol library):
$.plot('#placeholder', [{
data: [
[1, 1],
[2, 3],
[4, 4],
[5, 9]
],
lines: {
show: true
},
points: {
show: true,
symbol: "square"
},
color: '#CB4B4B',
label: 'My Data'
}]);

Categories

Resources