Echart: How to set mark area to fill sections in xAxis - javascript

I have a problem with marking area: i need to be able to select a bar area based on xAxis, for example from 0 to 1, from 1 to 2, etc. But when i try to provide options for bar like
[{xAxis: 0, itemStyle: {color: red}},{xAxis: 1}]
it marks an area from a middle of xAxis area with an index of 0 to a middle of xAxis area with an index of 1. Is there a way to make it mark from start of an area to an end. Currently i managed to do so only with x option in pixels:
https://codesandbox.io/s/react-echart-markarea-ksj31?file=/src/index.js:714-726
Is there a better way to do it?

I can't imagine a method that would cover your requirements. It seems there is no such but nothing prevents to do it ourselves, see below.
When call function with join = true markedArea will calc as range from first to last.
calcMarkAreaByBarIndex(myChart, join = true, [4, 9])
When call function with join = false markedArea will calc for each bar.
calcMarkAreaByBarIndex(myChart, join = true, [4, 5, 6, 9])
var myChart = echarts.init(document.getElementById('main'));
var option = {
tooltip: {},
xAxis: {
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
},
yAxis: {},
series: [
{
id: 'myBar',
name: 'Series',
type: 'bar',
data: [11, 11, 11, 11, 12, 13, 110, 123, 113, 134, 93, 109],
markArea: {
data: [
[{x: 184},{x: 216}],
[{x: 224},{x: 256}],
]
},
},
]
};
myChart.setOption(option);
function calcMarkAreaByBarIndex(chartInstance, join = false, barIdx){
var series = chartInstance.getModel().getSeriesByType('bar');
var seriesData = series.map((s, idx) => s.getData())[0];
var barNum = seriesData.count();
var barCoors = [];
var layout = idx => seriesData.getItemLayout(idx);
for(var i = 0; i < barNum; i++){
if(!barIdx.includes(i)) continue;
barCoors.push([
{ x: layout(i).x },
{ x: layout(i).x + layout(i).width },
])
}
if(join){
return [
[
{ x: barCoors[0][0].x },
{ x: barCoors[barCoors.length - 1][1].x }
]
]
} else {
return barCoors
}
}
var markedAreas = {
series: {
id: 'myBar',
markArea: {
data: calcMarkAreaByBarIndex(myChart, join = true, [4,9])
}
}
};
myChart.setOption(markedAreas);
<script src="https://cdn.jsdelivr.net/npm/echarts#4.7.0/dist/echarts.min.js"></script>
<div id="main" style="width: 600px;height:400px;"></div>

I found a solution, that worked for me:
Basically, you need to manually set yAxis's max props, add another xAxis, make it invisible, create a custom series with type 'bar' and set xAxisIndex to 1:
data: [maxYaxisValue,maxYaxisValue...], //length === xAxis.data.length
type: 'bar',
barWidth: '100%',
color: transparent,
xAxisIndex: 1,
And style a bar by index with background color and borderWidth
You can check the working example here
https://codesandbox.io/s/react-echart-markarea-m0mgq?file=/src/index.js

Related

Chart Js - Globally set bar chart color based on value

I want to generate a page with multiple bar charts and set the color of each globally based on a value in array!
this is the code i have so far..it works in so far as it takes one of the values and assigns it all of the bars! Where I need it to assign RED to FALSE and GREEN to TRUE
var win = simpleData[0].myWin; //array containing either true or false
var myBorderColors = [];
$.each(win, function (index, value) {
if (value == true) {
myBorderColors[index] = "rgba(0, 177, 106, 1)";
} else {
myBorderColors[index] = "rgba(207, 0, 15, 1)";
}
});
Chart.defaults.global.elements.rectangle.backgroundColor = myBorderColors;
Given an array named "win" that contains boolean values, you could create the "myBorderColors" array as follows using Array.map.
var myBorderColors = win.map(b => b ? "rgba(0, 177, 106, 1)" : "rgba(207, 0, 15, 1)");
And then use the following assignment to Chart.defaults.
Chart.defaults.global.datasets.bar.borderColor = myBorderColors;
Please have a look at the runnable code snippet below.
var win = [true, false, false, true];
var myBorderColors = win.map(b => b ? "rgba(0, 177, 106, 1)" : "rgba(207, 0, 15, 1)");
Chart.defaults.global.datasets.bar.borderColor = myBorderColors;
new Chart(document.getElementById('myChart'), {
type: 'bar',
data: {
labels: ['A', 'B', 'C', 'D'],
datasets: [{
label: "My Dataset",
data: [3, 5, 4, 2],
borderWidth: 3
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
canvas {
max-width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="200"></canvas>

Highcharts Graph displaying 0 value continuously : Javascript Array

I am trying to display the points on a graph using PHP Mysql, I saved the data into an array in php Variable and then passed that array into a Javascript array.
Now, What I want to do is that I want to show the array elements one by one after every one second. But what is Happening is that the graph plots 0 value countinuously on the Highchart.
Here is my Code :
numArray = [1,5,3,5,6,3,3,7,4,6,7,3,5,3,6,7,5,2,5,7,4,6,4,5,3,6,7,8,5,4,3,6,7,8,5,7,8,8,5,3,2,4,6,7,4,6,7] ;
/* Just for understanding */
var json_array =numArray ;
var i = 0;
function next() {
return json_array[i];
i++;
}
Highcharts.chart('container', {
chart: {
type: 'line',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0],
chart = this;
setInterval(function() {
var x = (new Date()).getTime(), // current time
y =next();
console.log(y) ;
series.addPoint([x, y], false, true);
}, 1000);
setInterval(function() {
chart.redraw(false);
}, 1000);
}
}
},
time: {
useUTC: false
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
headerFormat: '<b>{series.name}</b><br/>',
pointFormat: '{point.x:%Y-%m-%d %H:%M:%S}<br/>{point.y:.2f}'
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
animation: false,
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -1000; i <= 0; i += 1) {
data.push([
time + i * 10,
null
]);
}
return data;
}())
}]
});
Here is the Fiddle that I have created :
https://jsfiddle.net/abnitchauhan/v7tdLr1j/2/
The Chart runs till infinite loop and show only 0 Value. I just want to show the array values till the End
Check the below demo with the result you probably want to achieve.
Code:
const numArray = [1, 5, 3, 5, 6, 3, 3, 7, 4, 6, 7, 3, 5, 3, 6, 7, 5, 2, 5, 7, 4, 6, 4, 5, 3, 6, 7, 8, 5, 4, 3, 6, 7, 8, 5, 7, 8, 8, 5, 3, 2, 4, 6, 7, 4, 6, 7];
Highcharts.chart('container', {
chart: {
events: {
load: function() {
let chart = this,
now = (new Date()).getTime(),
i = 0;
const interval = setInterval(function() {
chart.series[0].addPoint([
now + i * 1000,
numArray[i]
]);
i++;
if (i === numArray.length) {
clearInterval(interval);
}
}, 1000);
}
}
},
xAxis: {
type: 'datetime'
},
series: [{}]
});
Demo:
https://jsfiddle.net/BlackLabel/vf906wam/
First of there is no endpoint in your setInterval method. It will keep on calling after 1 sec. You cant even stop. First, have a separate function to form data. Let's say have series data initialized. Have as a global variable. then have the Promise to generate you x point.
var promise1 = new Promise(function(resolve, reject) {
var points [];
setTimeout(function() {
var x = (new Date()).getTime(), // current time
y =next();
points.push([x, y], false, true);
if(your counter let says 1000 : points.lenght > 1000) {
resolve(points) //resolve your points
}
}, 300);});
wrap above thins in function and return a promise and call that.
callYourDefinedFun().then(function(points) {
// now you have points ready, series ready make your chart configuration and then
// call to render the chart
});

How to show more than one "dataMax" in Highcharts?

Currently, I'm showing a max point in the line chart. But I want to change dataMax to top 5 max value points in chart.How can I achieve this in Highcharts?
var defaultData = 'urlto.csv';
var urlInput = document.getElementById('fetchURL');
var pollingCheckbox = document.getElementById('enablePolling');
var pollingInput = document.getElementById('pollingTime');
function createChart() {
Highcharts.chart('closed5', {
chart: {
type: 'area',
zoomType: 'x'
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
style: {},
formatter: function() {
if (this.y === this.series.dataMax) {
return this.y;
}
}
}
}
},
title: {
text: 'Chart for charting'
},
data: {
csvURL: urlInput.value,
enablePolling: pollingCheckbox.checked === true,
dataRefreshRate: parseInt(pollingInput.value, 10)
}
});
if (pollingInput.value < 1 || !pollingInput.value) {
pollingInput.value = 1;
}
}
urlInput.value = defaultData;
// We recreate instead of using chart update to make sure the loaded CSV
// and such is completely gone.
pollingCheckbox.onchange = urlInput.onchange = pollingInput.onchange = createChart;
// Create the chart
createChart();
As #ewolden rightly noticed, you can sort your data and show only the five highest values:
var data = [11, 22, 33, 44, 55, 66, 15, 25, 35, 45, 55, 65],
sortedData = data.slice().sort(function(a, b){
return b - a
});
Highcharts.chart('container', {
series: [{
data: data,
dataLabels: {
enabled: true,
formatter: function() {
if (sortedData.indexOf(this.y) < 5) {
return this.y;
}
}
}
}]
});
Live demo: http://jsfiddle.net/BlackLabel/xkf2w5tb/
API: https://api.highcharts.com/highmaps/series.mapbubble.dataLabels.formatter
As far as I know formatter callback is the way to format the data labels. If you want to show the top N points you should sort the data in a new array and pull the top 5 values. This is an example of how to clone and sort the array and extract the top 5 elements in the formatter call.
let data = [32, 10, 20, 99, 30, 54, 85, 56, 11, 26, 15, 45, 55, 65];
//Copy the array
let temp = data.slice();
// Sort the temp array in descending order
temp.sort((a, b) => b - a);
Highcharts.chart('closed5', {
chart: {
type: 'area',
zoomType: 'x'
},
title: {
text: 'Chart for charting'
},
series: [{
data: data,
dataLabels: {
enabled: true,
formatter: function() {
if (temp.indexOf(this.y) < 5) {
return this.y;
}
},
},
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="closed5"></div>

"Play with this data!" not showing up for my plotly.js plot

I was under the assumption the "Play with this data!" link was supposed the show up by default. Any ideas on why it may not appear? I am just working with a basic scatter plot.
Note that this code below is not standalone as is, it is just the excerpt that does the plotly work.
var xData = [];
var yData = [];
var h = results;
for(var k in h) {
var localdate = k;
var plotdate = moment(localdate).format('YYYY-MM-DD HH:mm:ss');
xData.push(plotdate);
if (currentPort === "t") {
yData.push(CtoF(h[k]));
} else {
yData.push(h[k]);
};
}
var plotdata = [
{
x: xData,
y: yData,
type: 'scatter',
mode: 'markers+lines',
line: {
'color': HELIUM_BLUE
},
marker: {
'symbol': 'circle',
'color': HELIUM_PINK,
'maxdisplayed': 50
}
}
];
var layout = {
title: currentData,
xaxis: {
'title': 'Date / Time'
},
yaxis: {
'title': title
}
};
Plotly.newPlot(plotHolder, plotdata, layout);
You would need to add {showLink: true} as the fourth argument (after layout). I guess the default value changed from true to false.
If you want to change the caption of the button, use {showLink: true, "linkText": "Play with this data"}
var xData = [1, 2, 3, 4, 5];
var yData = [10, 1, 25, 12, 9];
var plotdata = [
{
x: xData,
y: yData,
type: 'scatter',
mode: 'markers+lines',
}
];
var layout = {
title: 'Edit me',
xaxis: {
'title': 'x'
},
yaxis: {
'title': 'y'
}
};
Plotly.newPlot(plotHolder, plotdata, layout, {showLink: true, "linkText": "Play with this data"});
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id='plotHolder'>
</div>

Test alignment 'Center' to the highchart legend content

I have been working on the highchart for a while, I have the chart like this
and i have placed the legend at the botton of the page and what i need to do is make the legend text align center like in the following image
I found few question of text alignment in highchart but does not suite my request. So I am unable to move further.
Fiddle http://jsfiddle.net/AbNpB/12/
Thanks in Advance!
It's possible to align each line using a custom code that will translate each legend item.
It's easier to resize output window in JSFiddle: http://jsfiddle.net/BlackLabel/a02czac2/
$(function() {
(function(H) {
H.wrap(H.Legend.prototype, 'render', function(proceed) {
// proceed
proceed.apply(this, [].slice.call(arguments, 1));
// custom
var legend = this,
centerRow = function(tab, w, x) {
var offset = (legend.legendWidth - (x + w)) / 2;
H.each(tab, function(elem) {
elem.legendGroup.attr({
translateX: elem.legendGroup.translateX + offset
});
});
}
if (legend.options.centerItemLines) {
var items = legend.allItems || [],
lastY = items[0] && items[0]._legendItemPos[1],
rowItems = [],
pos, prevX, prevW;
H.each(items, function(item) {
pos = item._legendItemPos;
if (pos[1] > lastY) {
lastY = pos[1];
centerRow(rowItems, prevW, prevX);
rowItems = [];
}
rowItems.push(item);
prevX = pos[0];
prevW = item.legendGroup.getBBox(true).width;
});
centerRow(rowItems, prevW, prevX); // last line
}
});
}(Highcharts))
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
legend: {
itemStyle: {
width: 350
},
centerItemLines: true
},
series: [{
data: [6, 4, 2],
name: 'First'
}, {
data: [7, 3, 2],
name: 'Second a longer legend text and longer and longer and longer'
}, {
data: [9, 4, 8],
name: 'Third'
}, {
data: [1, 2, 6],
name: 'Fourth'
}, {
data: [4, 6, 4],
name: 'Fifth'
}]
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container" style="height: 400px;"></div>
Try to add this one:
legend: {
align: 'center',
verticalAlign: 'bottom',
x: 0,
y: 0
},
Hope this helps.

Categories

Resources