How to hide values that are false ? ( 0, null or undefined)
I have tried to do something like
new Chart(this.barCanvas.nativeElement, {
...
data: {
datasets: [{
data: [
value < 1 ? null : value,
value2 < 1 ? null : value2,
valueX < 1 ? null : valueX,
],
}],
},
options: {
skipNull: true,
}
...
}
But it doesn't work.
I've found some similar post on SOF with no answers or working solution
Inspired on LeeLenalee answer and zhulien comment I have created a variable chartData that I filter before passing it.
But passing the variable chartData make a type error on data (to copy past the object of chartData and passing it directly does not make a type error, but the view of the graph does not load)
indexToRemove is an array of index based on data that are to 0
var chartData = {
labels: ['Batterie faible', 'Maintenance', 'HS', 'Place libre', 'Place occupée'].filter((v, i) => indexToRemove.includes(i)),
datasets: [{
label: '',
data: data.filter((v, i) => indexToRemove.includes(i)),
backgroundColor: [
'#F6741A',
'#dc2625',
'#B91C1B',
'#22c55e',
'#FACC14'
].filter((v, i) => indexToRemove.includes(i)),
borderRadius: 4,
borderSkipped: false,
}]
}
new Chart(this.barCanvas.nativeElement, {
type: 'bar',
data: chartData, // <- Type error (But replacing by the object correct the type error but still does not work as said above)
...
}
You can filter your data beforeHand and use object notation togehter with it:
let initialData = [{
"x": "label1",
"y": 9
},
{
"x": "label2",
"y": 0
},
{
"x": "label3",
"y": 5
},
{
"x": "label4",
"y": 10
},
{
"x": "label6",
"y": null
},
{
"x": "label7",
"y": 3
},
{
"x": "label8",
"y": undefined
}
];
let data = initialData.filter(e => e.y);
const options = {
type: 'bar',
data: {
datasets: [{
label: '# of Votes',
data: data,
backgroundColor: 'pink',
}]
},
options: {}
}
const 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.7.0/chart.js"></script>
</body>
Related
So I'm trying to make a JS function that uses ChartJS, the variable/data the fucntion gets, is a JSON object. The reason why I use try/catch is because the two lines under here:
let labels = json_data.data.map(e => e.StartTime);
let data = json_data.data.map(e => e.StatusId);
Isn't always set if there is any data they are set, but if not is the only one set
let data = json_data.message.map(e => e.message);
Unless on page load, then nothing is set.
The JSON object change when a <Select> dropdown is changed, and if there is data in one then the canvas is loaded, but if the user then select one with no data, I want the graft to be empty/destroyed, but I cant do this because I'm in a try catch, and if I define it in the catch too, then it says that the ID already is in use. What do I have to do to "reset/destroy" it in the catch?
function chartJSLoad(json_data) {
try {
let labels = json_data.data.map(e => e.StartTime);
let data = json_data.data.map(e => e.StatusId);
console.log(labels);
console.log(data);
var ctx = document.getElementById('canvaschartjs').getContext('2d');
var myChart = new Chart(ctx, {
data: {
datasets: [{
type: 'bar',
label: 'Bar Dataset',
data: data,
backgroundColor: 'rgba(0, 150, 90)',
borderColor: 'rgba(0, 255, 90)',
order: 2
}, {
type: 'line',
label: 'Line Dataset',
data: data,
backgroundColor: 'rgba(150, 0, 90)',
borderColor: 'rgba(255, 0, 90)',
order: 1
}],
labels: labels
},
options: {
maintainAspectRatio: false,
responsive: true,
scales: {
x: {
stacked: true,
},
y: {
stacked: true
}
}
}
});
} catch (error) {
if (typeof json_data !== 'undefined') {
myChart.destroy();
alert(json_data.message);
}
}
}
You can use the static method getChart to check if a chart with that context already exists, if it does you get that chart instance which you can destroy:
catch (error) {
if (typeof json_data !== 'undefined') {
let chart = Chart.getChart('canvaschartjs');
if (typeof chart !== 'undefined') {
chart.destroy()
}
alert(json_data.message);
}
}
Live example:
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'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange'
}
]
},
options: {}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
let myChart = new Chart(ctx, options);
let chart = Chart.getChart('chartJSContainer');
if (typeof chart !== 'undefined') {
chart.destroy() // Does not show anything because of this line, comment it out to show again
}
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.js"></script>
</body>
I'm making a Vertical Bar Chart using react-chartjs-2.
and I have array of lots of float numbers stored.
I tried to use chartjs callback option to display only the last value on a graph.
But the value in the callback is an integer, so I can't take the value I want.
for example,
const xAsisData = [ 1.11, 4.23, 7.34, ... , 403.78 ] // includes hundreds
scales: {
x: {
ticks: {
autoSkip: false,
callback: (value) => {
// if value === last ? value : null
// ! but last value is 309, not 403.78
},
},
Is there any other option I can use?
You get the index and ticks array as well in your callback so you can just check if the index is not the final one like so:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
y: {
ticks: {
callback: (val, i, ticks) => (i < ticks.length - 1 ? val : null) // Replace null by empty string to still show the gridLine
}
}
}
}
}
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.3.2/chart.js"></script>
</body>
I have some python code which sucessfully passes two array to my html template
#app.route('/line')
def line():
df= av_query(av_start_date,av_end_date,'44201')
df['dt']=pd.to_datetime(df['Date'])
df['RawValue']=np.where(df['Units']=='007',df['RawValue']*1000,df['RawValue'] )
temp_df=df[df['Site']=='SM']
dates = temp_df['dt']
values = temp_df['RawValue']
return render_template('line.html', title='Ozone Data',dates=dates[:5], values=values[:5], max_n=100)
and in my html template I have tested this plotting code
<center>
<h1>{{ title }}</h1>
<canvas id="myChart" width="600" height="400"></canvas>
<script>
var s1 = {
label: 's1',
borderColor: 'blue',
data: [
{ x: '2017-01-06 18:39:30', y: 100 },
{ x: '2017-01-07 18:39:28', y: 101 },
]
};
var s2 = {
label: 's2',
borderColor: 'red',
data: [
{ x: '2017-01-07 18:00:00', y: 90 },
{ x: '2017-01-08 18:00:00', y: 105 },
]
};
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: { datasets: [s1, s2] },
options: {
scales: {
xAxes: [{
type: 'time'
}]
}
}
});
</script>
</center>
How do I replace the dummy data in s1 and s2 with my data?
I tried to push each line to the dataset but that did not seem work.
var s1 = {
label: 's1',
borderColor: 'blue',
dates=dates
values=values
data: []
for (i=0; i<=dates.length; i++){
data.push({x:dates[i], y:values[i]})
}
};
I found the easiest way to do this is render a variable in the page using the template.
If your data is in an array or dictionary, make sure to convert it to json before passing it to the template, then pass it to the javascript when the template renders like so:
<script>
const data = {{ data|safe }};
</script>
JSON will natively render as Javascript and you can do with it what you will then.
Make sure you pass it through the safe filter or it will just be escaped.
I want to show the x values of a array as time stamp. The x value was generated by x = Date.now()
var test = {
"datasets": [{
"data": [{
"x": 1609753734252,
"y": 44.82420388241937
}, {
"x": 1609753735263,
"y": 46.02068615892796
}, {
"x": 1609753741254,
"y": 53.21622091958411
}]
}, {
"data": [{
"x": 1609753734252,
"y": 129.77634259930292
}, {
"x": 1609753735263,
"y": 129.86789675071483
}, {
"x": 1609753741254,
"y": 129.9137373479274
}]
},
"labels": [1609753734252, 1609753735263, 1609753741254]
}
The options
var config = {
type: 'line',
options: {
responsive: true,
responsiveAnimatinDuration: 500,
animation: {
duration: 0
},
elements: {
point: {
radius: 0
},
line: {
borderWidth: 2,
fill : false
}
},
legend : {
display : false
},
scales: {
xAxes: [{
type : 'time',
time : {
format : "HH:MM",
unit : "hour"
}
}]
}
}
};
The javascript code:
config.data = test;
window.myLine = new Chart(ctx.getContext('2d'), config);
I want to show the time in format hh:mm? What is wrong?
The data will be updated all 500 ms. Can I hide the transitions?
You don't have that option format as you're using it
You can use the unit and the parser, this last one accepts the same format options as moment accepts.
You can try using as a string like the following:
MM-DD-YYYY
Or sending a function, like this
parser: (tickValue) => {
// just as an example
if (tickValue > 0)
return moment(tickValue).format('MM-DD-YYYY');
}
Can you please try the following way mentioned here in the documentation to formate date
https://www.chartjs.org/docs/latest/axes/cartesian/time.html#display-formats.
I tried it with the following:
scales: {
xAxes: [{
type: 'time',
time: {
displayFormats: {
second: 'hh:mm:ss'
}
// unit : 'minute'
}
}]
Now I get all the years from 1971 to today. But I want to have the x-scaling set auto. Without displayFormat all times are displayed. But unfortunately as long int.
I also tried it with "unit". After that I get an exception: isAMomemtObject
I need to plot some information that the X-axis is the time and the Y-axis is the a numerical value. The structure is similar to the next table,
Name Date Result
N1 9:00 88
N1 9:10 84
N1 9:16 83
N1 9:23 83
N1 9:29 85
N2 9:03 87
N2 9:07 87
N2 9:18 87
N2 9:25 86
N2 9:29 86
Thus, what I need with this example, are two independent lines that each one work with it data.
To show this info I'm using chart.js. My first idea was to use the scatter type graph, but this is not possible because it only works with numerical values. Therefore, I thought about using the line type graph, but the problem with this is that by default you can only define a single label and how you can see I need each information to be independent since they don't have to match the hours.
Is it possible to add another label? I've tried to define two lists but it doesn't work and I don't know how to deal with it.
let ctx = document.getElementById("my_chart").getContext("2d");
my_chart = new Chart(ctx, {
type: 'line',
data: {
labels: [
['9:00','9:10','9:16','9:23','9:29'],
['9:03','9:07','9:18','9:25','9:29']
],
datasets: [{
data: [88,84,83,83,85],
label: "N1",
borderColor: "#8e5ea2",
fill: false
}, {
data: [87,87,87,86,86],
label: "N2",
borderColor: "#c45850",
fill: false
}]
},
options: {
title: {
display: true,
text: 'Info'
}
}
});
EDIT: My modifications with the help of #alonas and #HeadhunterKev
This is what I have now, is not working I suppose the format is wrong but I don't know what. Maybe I need seconds? Probably is a silly question but I'm lost with this...
var sData = {
datasets: [{
label: 'Dataset1',
data: [{
x: '09:00',
y: 88
}, {
x: '09:10',
y: 89
}, {
x: '09:13',
y: 86
}, {
x: '09:23',
y: 86
}, {
x: '09:26',
y: 85
}, {
x: '09:29',
y: 83
}]
}, {
label: 'Dataset2',
data: [{
x: '09:02',
y: 88
}, {
x: '09:13',
y: 89
}, {
x: '09:14',
y: 86
}, {
x: '09:20',
y: 86
}, {
x: '09:24',
y: 85
}, {
x: '09:29',
y: 83
}]
}]
}
sData.datasets[0].data = formatData(sData.datasets[0].data)
sData.datasets[1].data = formatData(sData.datasets[1].data)
function formatData(oldData) {
var newData = []
for (var i = 0; i < oldData.length; i++) {
var currentData = {}
currentData.x = moment(oldData[i].x, "hh:mm").format('HH:mm')
currentData.y = oldData[i].y
newData.push(currentData)
}
return newData
}
var data = sData
var options = {
responsive: true,
scales: {
xAxes: [{
type: 'time',
}]
},
tooltips: {
callbacks: {
title: function(tooltipItem, data){
return moment(tooltipItem[0].label).format('hh:mm')
}
}
}
}
var ctx = document.getElementById('bateria_graf');
let chart = new Chart(ctx, {
type: 'line',
data: data,
options: options
});
Can somebody help me? Thank you very much.
You can provide data as a list of x,y:
datasets: [{
data: [{y:88,x:`${timestamp of 9:00}` },...],
...
}, {
data: [{y:87, x:`${timestamp of 9:03}`},...],
...
}]
like here https://www.chartjs.org/docs/latest/charts/line.html#point
And then in options define how to display the x value (timestamp) as hour:minutes
{
scales: {
xAxes: [{
ticks: {
callback = (label, index, labels) => {
return moment.unix(label).format('HH:mm');
}
}
}]
}
}