I would like to have the y-axis only with the min/max values of my data.
I tried to use the d3 directive but without results.
I had a look at google but I didn't find an answer to achieve this behaviour.
Below the code:
$.getJSON('assets/json/chartc3.json', function(data)
{
scene=data;
var chart = c3.generate({
bindto: '#chartc3',
data:
{
json: scene,
keys:
{
x: 'round',
value: ['Marketable', 'Total Requested Capacity', 'Your Bid'],
},
types: {
Marketable: 'area'
},
colors: {
Marketable: '#A09FA2',
'Total Requested Capacity': '#272E80',
'Your Bid': '#8EBF60'
}
},
axis:
{
x: {
tick:
{
culling:
{
max: 10
}
},
type: 'category'
},
y:
{
min: 0,
padding : {
bottom : 0
},
tick:
{
values: [[0], [***d3.max(scene)]***],
format: function (d) { return d3.format(',f')(d) +' kWh/h' }
//or format: function (d) { return '$' + d; }
}
}
}.........
How could I achieve the result described above ? d3.max(scene) returns NaN.
Well the problem is scene is not an array its a json object.
var k = d3.max([1,5,2])
k will be 5
so you will need to pass an array of elements which constitute your y ordinals.
you need to use
d3.max(arr, function(d){return numberic value});
or
var arr = scene.map(function(d){return ...the number value..})
y:{
min:d3.min(arr),
max:d3.max(arr)
},
the function depends on the array element of your data.
I used a little function to calculate the max by myself.
var maxs=0;
for (var j=0; j<scene.length; j++) {
var maxtemp=Math.max(scene[j].Marketable, scene[j]['Your Bid'], scene[j]['Total Requested Capacity']);
maxs=Math.max(maxs, maxtemp);
}
Related
I'm relative new to highcharts so I'm not that knowledgeable.
But what I am trying to do is that I am trying to dynamically create series with a name and some x, y values. To get the x and y values I use two dictionaries looking like this:
The X values. They are dates
The Y values. They are seconds
What I want to do is create a series that have the names of the keys and then they can have multiple points for x, y values.
So for example at "Fiber_Mätning" I have two values in the key in both dictionaries. What I want to do is that I create a series with the name "Fiber_Mätning", and then it should have two points where I give both x and y value.
So the 1st point in "Fiber_Mätning" would be x:"2020-10-28" y:"28800"
and the 2nd point in "Fiber_Mätning" would be x:"2020-10-29" y:"18000"
After that I would move on onto the next key in both dictionaries and do the same. So the way I create the series need to be a function that is dynamically creating series and the points depending on the amount of keys and values in the dictionaries.
Currently my highchart code looks like this:
$('#container').highcharts({
chart:{
type: 'column',
events:{
load: function(){
RedrawColumns(this)
},
redraw: function(){
RedrawColumns(this)
}
}
},
title:{
text: 'Time worked by {{user_to_show}}'
},
subtitle:{
text:'{{user_to_show}}´s flex time: '
},
tooltip:{
formatter: function (){
var text = 'Date: ' + this.x + '<br>' + 'Time: ' + secondsTimeSpanToHMS(this.y/1000) +
'<br>' +'Extra info:' + {{extra_info|safe}}[this.x];
return text;
}
},
xAxis:
{
categories: {{all_dates|safe}}
},
yAxis:
[{
title:
{
text: '' //If it isnt given '' it will display "value" so using '' to hide it
},
gridLineWidth: 1,
type: 'datetime', //y-axis will be in milliseconds
dateTimeLabelFormats:
{ //force all formats to be hour:minute:second
second: '%H:%M:%S',
minute: '%H:%M:%S',
hour: '%H:%M:%S',
day: '%H:%M:%S',
week: '%H:%M:%S',
month: '%H:%M:%S',
year: '%H:%M:%S'
},
opposite: true
}],
plotOptions:
{
series:
{
dataLabels:
{
enabled: true,
formatter: function()
{
if( this.series.index == 0 )
{
return secondsTimeSpanToHMS(this.y/1000) ;
}
else
{
return this.y;
}
}
}
}
},
series:
[{
}]
});
});
(I am doing this with django, html and js)
If anything is unclear please say so and I will try to explain it in further detail.
Thanks in advance for any replies.
Here is my proposal for the solution. I think that everything is explained in the comments. If something is unclear, feel free to ask.
let data1 = {
Jarnvag_asdasd: ['2020-10-22'],
Fiber_Matning: ['2020-10-28', '2020-10-29'],
Fiber_Forarbete: ['2020-10-28', '2020-10-29'],
};
let data2 = {
Jarnvag_asdasd: [28800],
Fiber_Matning: [28800, 18000],
Fiber_Forarbete: [28800, 14400],
};
// The constructor to create the series structure
function CreateSeries(name, data) {
this.name = name;
this.data = data;
}
// series array
let series = [];
// Iterate through the data to concat them
for (let i in data1) {
let data = [];
data1[i].forEach((d, j) => {
data.push([d, data2[i][j]])
})
series.push(new CreateSeries(i, data))
}
Highcharts.chart('container', {
series: series
});
Demo: https://jsfiddle.net/BlackLabel/r7ame5gw/
I am generating a c3.js chart with the folling JSON and code, I'm trying to change the format of the X axis dates like this "November 2016" "N16". Can I get some help with this please? Thanks!
response = [["November 2016","December 2016","January 2017","February 2017","March 2017","April 2017"],["total"
,2,43,60,51,46,110],["mammo",1,20,34,12,12,60],["face",1,20,16,30,32,32],["body",0,3,10,9,2,18],["photo"
,0,19,27,12,5,21],["scan",2,24,33,39,41,89]]
initMonthlyUsageChart(response);
function initMonthlyUsageChart(amounts) {
var months = amounts.shift();
c3.generate({
bindto: '#monthly_usage_chart-js',
data: { columns : amounts },
axis: {
x: {
type: 'category',
categories: months,
tick: {
rotate: 90,
format: function (x) { // x comes in as a time string.
x[0] = x[0].map(function(date) {
return date.replace(/^(\w{1}).*(\d{2})$/gi, "$1$2");
});
}
}
}
}
});
}
x doesn't come in as a time string, it comes in as an index to the category
Therefore, change to this bit of code to do what you need:
format: function (x) { // x comes in as an index
return months[x].replace(/^(\w{1}).*(\d{2})$/gi, "$1$2");
}
This approach may helps to format categorical chart tick formatting :
var config = bindto: '#monthly_usage_chart-js',
data: { columns : amounts },
axis: {
x: {
type: 'category',
categories: months,
tick: {
rotate: 90,
format: function (x) { // x comes in as a time string.
x[0] = x[0].map(function(date) {
return date.replace(/^(\w{1}).*(\d{2})$/gi, "$1$2");
});
}
}
}
};
config.axis.x.tick = {
format : function(x) {
var desiredValue = config.axis.x.categories[x];//'cause x here is a key for category chart
return desiredValue.replace(/^(\w{1}).*(\d{2})$/gi, "$1$2");//apply your formatting stuff
}
};
var chart = c3.generate(config);
I'm using Chart.js 2.1.4 and I would like to sort tooltip items based on the tooltip item value (yAxis value). I would also like to add thousands separator to values.
The lines in following picture should be sorted based on the value:
This adds separator for Scales: Chart.js 2.0 Formatting Y Axis with Currency and Thousands Separator
Using Documentation: http://www.chartjs.org/docs/#chart-configuration-tooltip-configuration and the Question above I have tried modifying the code for Tooltips value:
var chart_config = {
type: 'line',
data: {datasets: mydatasets},
options: {
tooltips: {
mode: 'label',
bodySpacing: 10,
titleMarginBottom: 15,
callbacks: {
beforeLabel: function(tooltipItem, data) {
var tooltipValue = tooltipItem.xLabel + ': ' + tooltipItem.yLabel.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
console.log(tooltipValue);
return tooltipValue;
},
},
},
}
};
var chartHolder = document.getElementById("chartHolder");
var chart = new Chart(chartHolder, chart_config);
The problem is it now returns only part of the tooltip items and there is error in console: TypeError: vm.labelColors[i] is undefined.
How should I format the function's return value to not have any errors and present the data as specified?
You can use the itemSort callback option for tooltips, e.g.
tooltips: {
itemSort: (a, b, data) => b.yLabel - a.yLabel
}
You have this information in the Docs: ChartJS Tooltip Configuration Callbacks
You could do this:
var myChart;
myChart = {
type: 'line',
data: {
datasets: mydatasets
},
options: {
tooltips: {
mode: 'label',
callbacks: {
title: function(tooltipItem) {
return moment(tooltipItem[0].xLabel).format('ll');
},
label: function(tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + ": " + tooltipItem.yLabel;
}
}
}
}
};
I've merged positive and negative data to one data set called yAxis (multiple columns for both positive and negative). Here's the code:
//...
var yAxis = [wololoTotalValues];
var xAxis = wololoTotalKeys;
window.onload = function () {
Flotr.draw(document.getElementById("chart"), yAxis, {
title: "wololo",
bars: {
show: true,
barWidth: 0.8
},
yaxis: {
min: 0,
max: wololoMaxValue + 10,
tickDecimals: 0
},
xaxis: {
ticks: xAxis
}
});
};
//...
<div id='chart' style="width:1200px;height:500px;"></div>
I would like 'bad' and 'ble' to be red. I found some manuals how to handle this problem with flot, but not flotr(flotr2).
Is there any way to make it somehow like below? Or maybe I must split the data like here?
colors: (yAxis[0-lastGood] : "#0000FF"), (yAxis[lastGood+1-lastBad] : "#FF0000")
Okay, found the solution, splitting the data into two arrays helped. Code is below:
var gud = [];
for(i=0; i<wololoLengthGood; i++){
gud.push([i, wololoValuesGood[i]]);
}
var bad = [];
for(i=wololoLengthGood; i<wololoLengthGood+wololoLengthBad; i++){
bad.push([i, wololoValuesBad[i-wololoLengthGood]]);
}
window.onload = function () {
Flotr.draw(document.getElementById("chart"),
[{ // replacement of 'yAxis' from here
data: gud,
color: "#0000FF"
},{
data: bad,
color: "#FF0000"
}], // till here.
//...
I'm using Highcharts to draw a spline. This works good.
I'm using secondary series (columns) for another data.
My problem is: how to set column height to be matched with spline.
As far i've done this: jsfiddle
Columns have height almost i need, but not all.
It is possible at all?
Relevant code:
$('#chart').highcharts({
title: {text: 'Chart'},
chart: {
type: 'spline'
},
xAxis: {
title: {
text: 'X-Axis'
}
},
yAxis: {
title: {
text: 'Y-Axis'
},
labels: {
enabled: false
}
},
series: [{
name: 'Chart',
data: chdata,
marker: {
enabled: false
},
}],
legend: {
enabled: false
}
});
var chartObj = Highcharts.charts[$('#chart').attr('data-highcharts-chart')];
var d = [];
for(var i = 0; i < ldata.length; i++) {
d.push([ldata[i],getYValue(chartObj,0,getClosest(ldata[i],bdata[0]))]);
}
chartObj.addSeries({
type: 'column',
pointWidth: 1,
borderWidth: 0,
data: d
});
I've tried even with plotLines, but it have height of whole chart.
Thanks,
Bartek
Rather than plotting the height of the closest point, try plotting the average height of the points either side of your bar.
You can get even closer if you work out a linear best fit for your bar on the line between the points either side. Something like:
function getY(xVal,points) {
var higher = 0;
var lower=0;
for(var i=0;i<points.length;i++){
if (points[i][0] > xVal) {
higher=i;
lower=i-1;
break;
}
}
return points[lower][1] + ((points[higher][1]-points[lower][1])*(xVal-points[lower][0])/(points[higher][0]-points[lower][0]));
};
http://jsfiddle.net/5h471o3d/