Echarts stacked barchart how to deal with data - javascript

Using echarts how can I have a horizontal stack bar chart taking in consideration the following scenario, I have groups and group has employees of different categories: freelance, permanent, student...
I want to show per group: divided stacks of employee categories but is not clear in this case how do I handle the code
import echarts from 'echarts';
let groupChart = echarts.init(document.getElementById('chartGroups'));
axios.get('/chart')
.then(function (response) {
// handle success
let stack = {}
let re = response.data
let categories = Object.keys(re.stacks).map(function(key, index) {
return key
})
let arr = re.labels.map(item => ({
name: item,
type: 'bar',
stack: item,
label: {
normal: {
show: true,
position: 'insideRight'
}
},
data: []
}))
console.log(arr)
let app = {}
app.title = 'Employees';
let option = {
tooltip : {
trigger: 'axis',
axisPointer : {
type : 'shadow'
}
},
legend: {
data: re.labels
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value'
},
yAxis: {
type: 'category',
data: categories
},
series: arr
}
groupChart.setOption(option, true);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
})
and here is my codepen

I'm not sure but is this you want? here is jsFiddle
get data of each series by :
let data = [];
categories.forEach((category) => {
let index = re.stacks[category].findIndex(item => {
return item[label];
})
if (index !== -1) {
data.push(re.stacks[category][index][label]);
} else {
data.push(null)
}
})
and if you want stack on each category, the series.stack should remain the same, you can use any string like below:
{
name: label,
type: 'bar',
stack: 'anyString',
label: {
normal: {
show: true,
position: 'insideRight'
}
},
data: data
}

Related

hellp for combin tvjs-xp and trading-vue-js

hi i want charting stock data in web page.
i found sample project in github
https://github.com/tvjsx/tvjs-xp
i change code and connect the binance and receive and charting real time data.
i have some problem after add online receive data chart lagend bouttun not work and i cant add layer.
please help me.
thanks
<trading-vue :data="dc" :width="this.width" :height="this.height"
title-txt="TVJS XP" :key="resetkey"
:chart-config="{DEFAULT_LEN:70}"
ref="tvjs"
:legend-buttons="['display', 'settings', 'up', 'down', 'add', 'remove']"
:toolbar="true"
:index-based="index_based"
:color-back="colors.colorBack"
:color-grid="colors.colorGrid"
:color-text="colors.colorText"
:extensions="ext"
:overlays="ovs"
:x-settings="xsett">
</trading-vue>
<span class="gc-mode">
<input type="checkbox" v-model="index_based">
<label>Index Based</label>
</span>
export default {
name: 'DataHelper',
icon: '⚡',
description: 'Real-time updates. Play with DataCube in the console',
props: ['night', 'ext', 'resetkey'],
components: {
TradingVue
},
mounted() {
window.addEventListener('resize', this.onResize)
this.onResize()
// Load the last data chunk & init DataCube:
let now = Utils.now()
this.load_chunk([now - Const.HOUR4, now]).then(data => {
this.dc = new DataCube({
ohlcv: data['dc.data'],
// onchart: [{
// type: 'EMAx6',
// name: 'Multiple EMA',
// data: []
// }],
offchart: [
// {
// type: 'BuySellBalance',
// name: 'Buy/Sell Balance, $lookback',
// data: [],
// settings: {}
// },
{
name: "RSI, 20",
type: "Range",
data: [],
settings: {
"upper": 70,
"lower": 30,
"backColor": "#9b9ba316",
"bandColor": "#666"
}
},
],
datasets: [{
type: 'Trades',
id: 'binance-btcusdt',
data: []
}]
}, { aggregation: 100 })
// Register onrange callback & And a stream of trades
this.dc.onrange(this.load_chunk)
this.$refs.tvjs.resetChart()
this.stream = new Stream(WSS)
this.stream.ontrades = this.on_trades
window.dc = this.dc // Debug
window.tv = this.$refs.tvjs // Debug
})
},
methods: {
onResize(event) {
this.width = window.innerWidth
this.height = window.innerHeight - 50
},
// New data handler. Should return Promise, or
// use callback: load_chunk(range, tf, callback)
async load_chunk(range) {
let [t1, t2] = range
let x = 'BTCUSDT'
let q = `${x}&interval=1m&startTime=${t1}&endTime=${t2}`
let r = await fetch(URL + q).then(r => r.json())
return this.format(this.parse_binance(r))
},
// Parse a specific exchange format
parse_binance(data) {
if (!Array.isArray(data)) return []
return data.map(x => {
for (var i = 0; i < x.length; i++) {
x[i] = parseFloat(x[i])
}
return x.slice(0,6)
})
},
format(data) {
// Each query sets data to a corresponding overlay
return {
'dc.data': data
// other onchart/offchart overlays can be added here,
// but we are using Script Engine to calculate some:
// see EMAx6 & BuySellBalance
}
},
on_trades(trade) {
this.dc.update({
t: trade.T, // Exchange time (optional)
price: parseFloat(trade.p), // Trade price
volume: parseFloat(trade.q), // Trade amount
'datasets.binance-btcusdt': [ // Update dataset
trade.T,
trade.m ? 0 : 1, // Sell or Buy
parseFloat(trade.q),
parseFloat(trade.p)
],
// ... other onchart/offchart updates
})
}
},
beforeDestroy() {
window.removeEventListener('resize', this.onResize)
if (this.stream) this.stream.off()
},
computed: {
colors() {
return this.$props.night ? {} : {
colorBack: '#fff',
colorGrid: '#eee',
colorText: '#333'
}
},
},
data() {
return {
dc: {},
width: window.innerWidth,
height: window.innerHeight,
index_based: false,
xsett: {
'grid-resize': { min_height: 30 }
},
ovs: Object.values(Overlays),
}
}
}

How to hide the legend in chart.js in a react project?

I am trying to hide the legend of my chart created with Chart.js.
According to the official documentation (https://www.chartjs.org/docs/latest/configuration/legend.html), to hide the legend, the display property of the options.display object must be set to false.
I have tried to do it in the following way:
const options = {
legend: {
display: false,
}
};
But it doesn't work, my legend is still there. I even tried this other way, but unfortunately, without success.
const options = {
legend: {
display: false,
labels: {
display: false
}
}
}
};
This is my full code.
import React, { useEffect, useState } from 'react';
import { Line } from "react-chartjs-2";
import numeral from 'numeral';
const options = {
legend: {
display: false,
},
elements: {
point: {
radius: 1,
},
},
maintainAspectRatio: false,
tooltips: {
mode: "index",
intersect: false,
callbacks: {
label: function (tooltipItem, data) {
return numeral(tooltipItem.value).format("+0,000");
},
},
},
scales: {
xAxes: [
{
type: "time",
time: {
format: "DD/MM/YY",
tooltipFormat: "ll",
},
},
],
yAxes: [
{
gridLines: {
display: false,
},
ticks: {
callback: function(value, index, values) {
return numeral(value).format("0a");
},
},
},
],
},
};
const buildChartData = (data, casesType = "cases") => {
let chartData = [];
let lastDataPoint;
for(let date in data.cases) {
if (lastDataPoint) {
let newDataPoint = {
x: date,
y: data[casesType][date] - lastDataPoint
}
chartData.push(newDataPoint);
}
lastDataPoint = data[casesType][date];
}
return chartData;
};
function LineGraph({ casesType }) {
const [data, setData] = useState({});
useEffect(() => {
const fetchData = async() => {
await fetch("https://disease.sh/v3/covid-19/historical/all?lastdays=120")
.then ((response) => {
return response.json();
})
.then((data) => {
let chartData = buildChartData(data, casesType);
setData(chartData);
});
};
fetchData();
}, [casesType]);
return (
<div>
{data?.length > 0 && (
<Line
data={{
datasets: [
{
backgroundColor: "rgba(204, 16, 52, 0.5)",
borderColor: "#CC1034",
data: data
},
],
}}
options={options}
/>
)}
</div>
);
}
export default LineGraph;
Could someone help me? Thank you in advance!
PD: Maybe is useful to try to find a solution, but I get 'undefined' in the text of my legend and when I try to change the text like this, the text legend still appearing as 'Undefindex'.
const options = {
legend: {
display: true,
text: 'Hello!'
}
};
As described in the documentation you linked the namespace where the legend is configured is: options.plugins.legend, if you put it there it will work:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
}
]
},
options: {
plugins: {
legend: {
display: false
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.js"></script>
</body>
On another note, a big part of your options object is wrong, its in V2 syntax while you are using v3, please take a look at the migration guide
Reason why you get undefined as text in your legend is, is because you dont supply any label argument in your dataset.
in the newest versions this code works fine
const options = {
plugins: {
legend: {
display: false,
},
},
};
return <Doughnut data={data} options={options} />;
Import your options value inside the charts component like so:
const options = {
legend: {
display: false
}
};
<Line data={data} options={options} />

Highchart JS Set data not updating Export: ShowTable on Dropdown Event but chart updates fine

I have an .aspx file which has drop-down lists and on selected index changed a javascript function is being called to update the series data points on a highchart rather than rendering the entire chart again. I have created the below function but this doesnt seem to be updating the highchart table.It works when updating the chart.
Used this example to create the chart and table that synchronize together:
https://www.highcharts.com/blog/tutorials/synchronize-selection-bi-directionally-between-chart-and-table/
But when I click an item on the dropdown which refreshes the points using setData the table is not updating the values!!!
function salesPurchaseScatter() {
console.log("I am in the function");
var scatterData = [];
var xAxisLabels = [];
var scatterDatas;
$.ajax({
type: "POST",
async: false,
url: "Index.aspx/ReturnData",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
scatterDatas = data.d;
}
});
const chart = window.chart;
console.log("CHart: ", chart);
chart.series[0].setData(scatterDatas.map(item => item["bucket5"]));
chart.series[1].setData(scatterDatas.map(item => item["bucket10"]));
chart.series[2].setData(scatterDatas.map(item => item["bucket15"]));
chart.series[3].setData(scatterDatas.map(item => item["bucket20"]));
chart.series[4].setData(scatterDatas.map(item => item["bucket25"]));
chart.series[5].setData(scatterDatas.map(item => item["bucket30"]));
chart.viewData();
}
The above is not updating the data points on the data table!
My original function to create the chart in the first place which works fine is below:
var scatterData = [];
var xAxisLabels = [];
var scatterDatas;
$.ajax({
type: "POST",
async: false,
url: "Index.aspx/ReturnData",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
scatterDatas = data.d;
}
});
let chart = Highcharts.chart('container1', {
chart: {
type: 'scatter',
events: {
selection: selectPointsByDrag,
click: unselectByClick
},
// necesssary to be able to select by dragging
zoomType: 'xy'
},
title: {
text: '(' + minDWT + ' <DWT ' + ' < ' + maxDWT + ')',
style: {
fontWeight: 'bold',
fontSize: '20px'
}
},
plotOptions: {
scatter: {
lineWidth: 2,
dashStyle: 'dot'
},
series: {
connectNulls: true,
allowPointSelect: true,
pointPadding: 0,
point: {
events: {
select: function (e) {
selectTableCell(this, true);
},
unselect: function (e) {
selectTableCell(this, false);
}
}
},
marker: {
states: {
select: {
fillColor: 'tomato',
borderColor: 'green'
}
}
}
}
},
series: [{
name: 'bucket5',
data: scatterDatas.map(item => item["bucket5"]),
turboThreshold: 0,
id: 'Results1',
marker: {
symbol: 'circle'
},
},
{
name: 'bucket10',
data: scatterDatas.map(item => item["bucket10"]),
turboThreshold: 0,
id: 'Results2',
marker: {
symbol: 'circle'
},
},
{
name: 'bucket15',
data: scatterDatas.map(item => item["bucket15"]),
turboThreshold: 0,
id: 'Results3',
marker: {
symbol: 'circle'
},
},
{
name: 'bucket20',
data: scatterDatas.map(item => item["bucket20"]),
turboThreshold: 0,
id: 'Results4',
marker: {
symbol: 'circle'
},
},
{
name: 'bucket25',
data: scatterDatas.map(item => item["bucket25"]),
turboThreshold: 0,
id: 'Results5',
marker: {
symbol: 'circle'
},
}, {
name: 'bucket30',
data: scatterDatas.map(item => item["bucket30"]),
turboThreshold: 0,
id: 'Results6',
marker: {
symbol: 'circle',
fillColor: 'red',
radius: 10
},
}],
xAxis: {
categories: scatterDatas.map(item => item["date"])
},
tooltip: {
formatter: function () {
var s = '<span style="color:' + this.point.color + '">\u25CF</span> ' + this.point.series.name + '<br /><b>Date: ' + this.x + '</b><br/><b>Sales Price: ' + this.y + '</b>';
return s;
}
},
exporting: {
showTable: true
},
});
UPDATE:
I have managed to get a step further. The chart is updating with the new data points but the table is not :
exporting: {
showTable: true
},
The fix i put in place:
const chart = window.chart;
console.log("CHart: ", chart);
for (i = 0; i < chart.series.length; i++) //Added this
chart.series[i].setData([]);
chart.series[0].setData(scatterDatas.map(item => item["bucket5"]));
chart.series[1].setData(scatterDatas.map(item => item["bucket10"]));
chart.series[2].setData(scatterDatas.map(item => item["bucket15"]));
chart.series[3].setData(scatterDatas.map(item => item["bucket20"]));
chart.series[4].setData(scatterDatas.map(item => item["bucket25"]));
chart.series[5].setData(scatterDatas.map(item => item["bucket30"]));
chart.viewData();
chart.redraw(); //Added this
Have i missed something out? Struggling to debug and identify what is going wrong
Found a JSFiddle which is similar to my current set up. http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/export-data/showtable/
The above JS Fiddle has a similar chart and table output. When i click on a drop down item I am trying to setData (the data point values) as per above code and this should update the chart and table. In my case it is only updating the chart and not the table. The function I am calling is salesPurchaseScatter on dropdown selected index changed event.
ATTEMPTED THIS:
const table = window.table;
table.series[0].setData(scatterDatas.map(item => item["saleagebucket5"]));
table.series[1].setData(scatterDatas.map(item => item["saleagebucket10"]));
table.series[2].setData(scatterDatas.map(item => item["saleagebucket15"]));
table.series[3].setData(scatterDatas.map(item => item["saleagebucket20"]));
table.series[4].setData(scatterDatas.map(item => item["saleagebucket25"]));
table.series[5].setData(scatterDatas.map(item => item["imo"]));
chart.redraw();
table.redraw();
but series is not possible using a table. How can i update the data using setData for the table? I tried using chart.viewData() but this doesnt seem to work either.
My guess is: const chart= window.chart; is only referring to the chart but dont know how to re-do the entire high chart canvas just the chart on it own!
A JSFiddle I tried to follow - https://jsfiddle.net/hxgp0yvj/
but same issue happening- Table not updating in this but chart does. I moved the code into my own solution to test it out. What am i missing?
Thank you for sharing it, after digging into I found out that it is a regression. I reported it on the Highcharts GitHub issue channel where you can follow this thread. If you don't need any new functionalities please use the previous version of the Highcharts until the bug will be fixed.
https://github.com/highcharts/highcharts/issues/14320

JavaScript - iterating through an array for checking condition

I am creating a high charts graph that I would like to dynamically give the graph color to depending on the title of an object. I currently have an array graphData that has an object title.
I have 5 possible results of titles:
"LOW", "MEDIUM-LOW", "MEDIUM", "MEDIUM-HIGH", AND "HIGH"
I am now attempting to iterate through my array and assign a color depending on what title the index has.
My entire graph receives one color based off the last title of the array. I would like the color to effect each index of the array seperartely.
For example: if "MEDIUM-HIGH" is the last title in the array, my entire graph gets #DD5F0C
Here is my code:
Array:
graphData: [ […]
​
0: Object { title: "LOW", result: 62582 }
​
1: Object { title: "MEDIUM-LOW", result: 57758 }
​
2: Object { title: "LOW", result: 8795 }
​
3: Object { title: "HIGH", result: 262525 }
​
4: Object { title: "MEDIUM-HIGH", result: 167168 } ]
let graphColor = ""
for (i = 0; i < graphData.length; i++) {
if (graphData[i].title === "LOW") {
graphColor = "#0D6302"
} else if (graphData[i].title === "MEDIUM-LOW") {
graphColor = "#0B7070"
} else if (graphData[i].title === "MEDIUM") {
graphColor = "#DC9603"
} else if (graphData[i].title === "MEDIUM-HIGH") {
graphColor = "#DD5F0C"
} else if (graphData[i].title === "HIGH") {
graphColor = "#C50710"
}
}
HighCharts code :
Highcharts.chart('container', {
chart: {
type: 'bar'
},
title: {
text: "Bar Graph"
},
xAxis: {
},
yAxis: {
min: 0,
formatter: function() {
return this.value + "%";
},
title: {
text: '% of Total'
}
},
legend: {
reversed: false
},
plotOptions: {
series: {
stacking: 'normal'
}
},
series: [{
name: `graphData[0].title`,
color: graphColor,
data: [graphData[0]],
}, {
name: 'graphData[1].title',
color: graphColor,
data: [graphData[1]],
showInLegend: false,
linkedTo: ":previous"
}, {
name: 'graphData[2].title,
color: graphData[0].title,
data: [graphData[2]]
}, {
name: graphData[3].title,
color: '#DC9603',
data: [graphData[3]]
}, {
name: graphData[4].title,
color: graphColor,
data: [graphData[4]]
}, {
name: graphData[5].title,
color: graphColor,
data: [graphData[5]]
}]
});
I am expecting my "color" to be dynamically generated based off of what graphData.title equals for that specific index.
You are having trouble because you have graphData.length number of entries, but only one graphColor variable to hold the color. Your code samples don't look complete so I'll make some assumptions about how the surrounding code must be. I recommend building up your series data in the for-loop directly so you can just use it in the Highcharts.chart call. The code is easier to read that way and probably more flexible too if you need to have more data rows.
// build the series data array here so it's simple to use in the chart call
const series = new Array(graphData.length);
for (let i = 0; i < graphData.length; i++) {
let graphColor = "#000000"; // a default color just in case
// can use if/else or a switch here
if (graphData[i].title === "LOW") {
graphColor = "#0D6302";
} else if (graphData[i].title === "MEDIUM-LOW") {
graphColor = "#0B7070";
} else if (graphData[i].title === "MEDIUM") {
graphColor = "#DC9603";
} else if (graphData[i].title === "MEDIUM-HIGH") {
graphColor = "#DD5F0C";
} else if (graphData[i].title === "HIGH") {
graphColor = "#C50710";
}
series[i] = {
name: graphData[i].title,
color: graphColor,
data: [graphData[i].result]
};
}
// Adjust the series data as needed
series[1].showInLegend = false;
series[1].linkedTo = ":previous";
Highcharts.chart("container", {
chart: { type: "bar" },
title: { text: "Bar Graph" },
xAxis: {},
yAxis: {
min: 0,
formatter: function() {
return this.value + "%";
},
title: { text: "% of Total" }
},
legend: { reversed: false },
plotOptions: { series: { stacking: "normal" } },
series: series
});
Not sure if I've properly understood what are you trying to do, but try this way:
const colorMap = { "LOW":"#0D6302",
"MEDIUM-LOW": "#0B7070",
"MEDIUM": "#DC9603",
"MEDIUM-HIGH": "#DD5F0C",
"HIGH":"#C50710"
}
...
series: [{
name: `graphData[0].title`,
color: colorMap[graphData[0].title],
data: [graphData[0]],
}, {
In the Highchart way - you can iterate through the series after chart initialization and set the wanted colors by particular series.
Demo: https://jsfiddle.net/BlackLabel/6hm4ebna/
chart: {
type: 'bar',
events: {
load() {
let chart = this;
chart.series.forEach(s => {
console.log(s)
if (s.name === 'test1') {
s.update({
color: 'red'
})
}
else if (s.name === 'test3') {
s.update({
color: 'green'
})
}
})
}
}
},
API: https://api.highcharts.com/highcharts/chart.events.load
If this wouldn't help please reproduce your attempt with the sample data on the online editor which I could work on.

How to filter the echarts line chart per week in angular

How to filter echarts line chart per week in angular. Currently it display all records example 2019-10-27 10:15:00, 2019-10-27 10:15:30, 2019-10-27 10:16:00, 2019-10-27 10:19:00. It should be 2019-10-27 if there's 2019-28-10 00:00:15, 2019-28-10 00:10:00 the output should be 2019-10-27, 2019-10-28.
here's the code
list.component.html
<button nz-button nzType="default" (click)="dataFilter('prevWeek')">Previous week</button>
<button nz-button nzType="default" (click)="dataFilter('currWeek')">Current week</button>
<button nz-button nzType="default" (click)="dataFilter('all')">All</button>
<div echarts [options]="trendOption" id="trendChart" [autoResize]="true" style="height: 280px;"></div>
list.component.ts
dataFilter(event: any) {
switch (event) {
case 'prevWeek':
console.log('diplay the previous/last week');
break;
case 'currWeek':
console.log('display current week list')
break;
case 'all':
console.log('display all records');
break;
default: break;
}
}
getRoomTrend() {
const _THIS = this;
const dateTime: any = [];
const tempY: any = [];
const humidY: any = [];
this.global
.getData(`/conditions?length=100&sensor=${this.roomTitle}`)
.pipe(take(1))
.subscribe((res: any) => {
const record = res['data'];
for (let i = record.length - 1; i >= 0; i--) {
const date = format(record[i].date, 'MM/DD/YYYY[\n]HH:mm');
const temperature = parseFloat(record[i].temperature);
const humidity = parseFloat(record[i].humidity);
dateTime.push(date);
tempY.push(temperature);
humidY.push(humidity);
}
if (this.initialLoad.trendStatus) {
this.trendOption = {
tooltip: {
trigger: 'axis',
axisPointer: {
animation: false
}
},
legend: {
top: '10',
data: ['Temperature', 'Humidity']
},
grid: {
left: '3%',
bottom: '15%',
containLabel: true
},
dataZoom: [
{
minValueSpan: 4,
startValue: record.length - 3
},
{
type: 'inside'
}
],
xAxis: {
type: 'category',
boundaryGap: false,
splitLine: {
show: false
},
data: dateTime
},
yAxis: [
{
type: 'value',
boundaryGap: [0, '100%'],
axisLabel: {
formatter: '{value} °'
},
splitLine: {
show: false
}
},
{
type: 'value',
boundaryGap: [0, '100%'],
position: 'right',
axisLabel: {
formatter: '{value} °'
},
splitLine: {
show: false
}
}
],
series: [
{
name: 'Temperature',
type: 'line',
color: '#006ec7',
data: tempY
},
{
name: 'Humidity',
type: 'line',
color: '#8c0000',
data: humidY
}
]
};
}
});
}
example I have 30,000 record and the date is same but different time. the output should be only ```2019-15-10, 2019-18-10, 2019-22-10.
Thanks in advance.
let uniqueDates = new Set();
record.forEach(value => {
let date = new Date(value.date.getFullYear(), value.date.getMonth(), value.date.getDate());
uniqueDates.add(date);
});
Set by definition is a set of unique values. So you get the date without the time from the records and add them into the set. You will end up with a list of unique dates.

Categories

Resources