I've created a horizontal floating bar chart using ChartJS. The data I am passing in is formatted as:
[
{
rowName: 'Project 1',
startDate: '2021-03-15',
endDate: '2021-04-20',
}
]
Where my x axis shows a month/year and my y axis shows the rowName. I've added chartjs-adapater-date-fns but in order to get the floating bars to work, I've had to convert the startDate and endDate into new dates and then use the .getTime() function to retrieve a number for the data the chart expects. E.g. [new Date(startDate).getTime(), new Date(endDate).getTime()].
On my tooltip, it shows the label as rowName which is what I'm wanting, however the data value shows as the two number values being passed in.
I'm wanting to show the tooltip in the following format:
Project 1
Start Date: 05/03/2021
End Date: 20/04/2021
What is the best way of doing this?
Note: I have consoled the context and found that data.raw provides me with 2021-05-03,2021-04-20 if that is of any use?
Instead of new date pass your input date , Tooltip will show with formatted date value.
var barOption = {
tooltips: {
callbacks: {
label: function(t, d) {
this.date=new Date();
let formated_date = this.datepipe.transform(this.date, 'dd/MM/yyy');
return formated_date;
},
},
},
}
Related
I'm migrating from ChartJS 2.9.3 to 4.2.1 (current). By following the 3.x and 4.x migration guides, I've sorted most things out, but I've come across a problem that I don't see a solution for.
One of my charts is a stacked bar chart. There are two datasets for it:
let chartData = {
// other stuff...
datasets: [
{ label: "Has thing", data: [200, 250, etc] },
{ label: "Does not has thing", data: [10, 4, etc] },
]
}
In my tooltips, I was accessing both datasets to create a custom tooltip with the percent representation of each part of each stack. For instance, the tooltips for the first stack might say: "Has thing: 200 (95.2%)" and "Does not has thing: 10 (4.8%)". My callback function looked like this:
// other stuff
callbacks: {
label: function(tooltipItem, data) {
let dataset = data.datasets[tooltipItem.datasetIndex];
let count_with = data.datasets[0].data[tooltipItem.index]
let count_without = data.datasets[1].data[tooltipItem.index]
let total = count_with + count_without
let this_dataset_count = dataset.data[tooltipItem.index]
let this_dataset_perc = (this_dataset_count / total * 100).toFixed(1)
let label = dataset.label + ": "
label += this_dataset_count + " (" + this_dataset_perc + "%)"
return label;
}
}
Looking at the 3.x migration guide, it appears they removed the data parameter from the tooltip callback, opting instead to add the item's dataset directly to the tooltipItem. Unfortunately, they don't seem to specify how I can access other datasets.
Has this functionality simply been removed completely, or is there a different way to access it?
As #kikon pointed out, data is accessible via context.chart.data. For some reason, that doesn't show up for me when I console.dir() the context object so I was just completely overlooking it.
Anyway, for anyone this might help in the future, here's the working version:
callbacks: {
label: function(context) {
const datasets = context.chart.data.datasets
const countWith = datasets[0].data[context.dataIndex]
const countWithout = datasets[1].data[context.dataIndex]
const perc = (context.raw / (countWith + countWithout) * 100).toFixed(1)
return `${context.dataset.label}: ${context.formattedValue} (${perc}%)`
}
}
I have a problem with my x-axis in chart.js.
My objective is to display stock prices in a graph. I want my users to be able to toggle multiple timeframes and modify the graph in consequence. For example, by default the graph displays the daily prices (measured from 9:30 to 16:00). If a user wants to see the weekly prices, then the graph changes and display all my data measures from 7 days ago to today.
The problem arises here. Since the weekend I take no measures of the price (the stock market is closed), my x-axis still displays all 7 days (including weekend days). I want to know if there is a way to discriminate against weekends in my x-axis.
Here's a picture of my problem:
As you can see, October 30th and 31st collapse on top of each other because , while I have no data for them they are still included in my axis.
Here is a copy of my code:
I receive the data by an ajax call (named 'data')
var min_x = new Date();
var max_x = new Date();
min_x.setDate(min_x.getDate() - 8);
myChart.options.scales.xAxes[0].time.unitStepSize = 1;
myChart.options.scales.xAxes[0].time.isoWeekday = true;
myChart.options.scales.xAxes[0].ticks.maxTicksLimit = 8;
myChart.options.scales.xAxes[0].time.unit = 'day';
myChart.options.scales.xAxes[0].distribution = 'timeseries';
myChart.options.scales.xAxes[0].ticks.autoSkip = true;
myChart.options.scales.xAxes[0].ticks.min = min_x;
myChart.options.scales.xAxes[0].ticks.max = max_x;
myChart.update();
for (var k = 1; k < data.datapoints.length; k++){
var point = data.datapoints[data.datapoints.length - k].latest_price;
var date = data.datapoints[data.datapoints.length - k].time;
label_list.push(date);
datalist_list.push(data.datapoints[k].latest_price);
var new_small_dict = {'x':data.datapoints[k].time, 'y':data.datapoints[k].latest_price};
dictionary_list.push(new_small_dict);
}
myChart.data.labels = label_list;
myChart.data.datasets[0].data = dictionary_list;
myChart.update();
If anybody has an idea on how to solve this issue, that would help me greatly. Thank you very much.
Finally found it. It was surprisingly easy solution for my issue, I hope it'll be for yours either.
In my answer I am using latest version, of Chart.js 3, but timeseries should be present in older versions as well.
The time series scale extends from the time scale and supports all the same options. However, for the time series scale, each data point is spread equidistant.
https://www.chartjs.org/docs/latest/axes/cartesian/timeseries.html
I had
scales: {
x: {
type: 'time'
}
}
Then I changed it to timeseries:
scales: {
x: {
type: 'timeseries'
}
}
And it works now. I just noticed bug with overlapping weekend dates, but that's another issue. :)
I had the same issue here is what I did.
Since I am using object data and providing [{x: "", y: ""}...]
I needed to add "source": "data" to the ticks object for the axis with the issue.
{
"scales": {
"x": {
"ticks": {
**"source": "data"**
},
"time": {
"displayFormats": {
"day": "MMM D ddd"
},
"unit": "day"
},
"type": "timeseries",
"title": {
"display": true,
"text": "Date"
}
}
}
I have created a group bar chart using chartJs.
While showing tooltip on bar, i want to show some part of tooltip string in double quotes ("").
I applied below code:
tooltips: {
displayColors: false,
mode: 'label',
callbacks: {
title: function() {},
label: function(tooltipItem, data) {
var tooltipLabel1 = 'Series '+ '"'+data['datasets'][0]['label']+'" '+
'Point ' + '"'+tooltipItem.label.split(" ")[1] + " " + tooltipItem.label.split(" ")[0]+'"';
var tooltipLabel2 = 'Value: ' + tooltipItem.value;
console.log([tooltipLabel1, tooltipLabel2]); // screenshot attached for this output
return [tooltipLabel1, tooltipLabel3];
}
}
},
It working fine but it is showing one of double quote at start and end double quote is removing.
Attached screenshot for this, what exactly it is showing on mouse-hover as well as in screenshot of console.
As well as, when I write console for this, because of json string, it add output in ""
What I can do? really clueless now.
I have a little puzzle that annoys me in PowerBI/DAX. I'm not looking for workarounds - I am looking for an explanation of what is going on.
I've created some sample data to reconstruct the problem.
Here are my two sample tables written in DAX:
Events =
DATATABLE (
"Course", STRING,
"WeekNo", INTEGER,
"Name", STRING,
"Status", STRING,
{
{ "Python", 1, "Joe", "OnSite" },
{ "Python", 1, "Donald", "Video" },
{ "DAX", 2, "Joe", "OnSite" },
{ "DAX", 2, "Hillary", "Video" },
{ "DAX", 3, "Joe", "OnSite" },
{ "DAX", 3, "Hillary", "OnSite" },
{ "DAX", 3, "Donald", "OnSite" }
}
)
WeekNumbers =
DATATABLE ( "WeekNumber", INTEGER, { { 1 }, { 2 }, { 3 }, { 4 } } )
I have a table with events and another table with all weeknumbers and there is a (m:1) relation between them on the weekNo/weeknumber (I've given them different names to easily distinguish them in this example). I have a slicer in PowerBI on the weeknumber. And I have a table which shows aggregation and counts the participants based on the status with the following measures:
#OnSite = COUNTROWS(FILTER(events,Events[Status]="OnSite"))
#Video = COUNTROWS(FILTER(events,Events[Status]="Video"))
I visualize the two measures in a table together with the Course and the weekNo. With the slicer on weekNumber 3 there are nobody with status video so #video is blank. See screenshot.
Then I decided to create a new measure which should show a 0 instead of blank for the #video:
#VideoWithZero = VAR counter=COUNTROWS(FILTER(events,Events[Status]="Video"))
RETURN IF(ISBLANK(counter),0,counter)
I add the #VideoWithZero to the table and get a lot of extra rows in the table for the other weekNo's:
So my question is - Why do I get the extra rows for week 1 and 2 in the table? I would expect my filter on WeekNumber to filter them out.
The filter is being applied to the context of the query executed, and then the measures are calculated. Now the issue is that one of your measures is always returning a value (0), so regardless of your context it will always show a result, thus making it seem that it is ignoring the filter.
One way I tend to get implement this is by providing some additional context to when I might want to show 0 instead of blank. In your case it would be when one of the counts is not blank:
#OnSite =
VAR video = COUNTROWS(FILTER(events,Events[Status]="Video"))
VAR onsite = COUNTROWS(FILTER(events,Events[Status]="OnSite"))
RETURN IF(ISBLANK(video), onsite, onsite + 0) //+0 will force it not to be blank
#Video =
VAR video = COUNTROWS(FILTER(events,Events[Status]="Video"))
VAR onsite = COUNTROWS(FILTER(events,Events[Status]="OnSite"))
RETURN IF(ISBLANK(onsite), video, video + 0)
So on the OnSite measure it will check if there are Videos and if so, it adds +0 to the result of the OnSite count to force it not to be blank (and vice versa)
One other way could be to count total rows and subtract the ones different to the status you need:
#OnSite =
VAR total= COUNTROWS(Events[Status])
VAR notOnsite = COUNTROWS(FILTER(events,Events[Status]<>"OnSite"))
RETURN total - notOnsite
#Video =
VAR total= COUNTROWS(Events[Status])
VAR notVideo= COUNTROWS(FILTER(events,Events[Status]<>"Video"))
RETURN total - notVideo
I use Chart.js to render a scattered line chart, which works pretty well.
For the rendering algorithm I need to find out the highest value shown on the y-axis, so let's say my "largest" point in the dataset has y = 248, so the y-axis shows 250 as the largest value. I need to find out that it's 250.
I tried to inspect the chart object at runtime, like so:
lineChart.options.scales[0].ticks.??
but it seems that I can only find out the settings I set myself programmatically.
Also looking at the comprehensive Chart.js docs did not point me to the solution.
Any advice how to figure out this value?
There is callback method in which you can get the array of values which will show on yAxes.
The first element of that array will be the highest value for the yAxes. Below is the sample code for the same.
var yAxesticks = [];
var highestVal;
var chartInstanceHoverModeNearest = new Chart(ctx, {
type: 'bar',
data: data,
options:{
scales: {
yAxes : [{
ticks : {
beginAtZero : true,
callback : function(value,index,values){
yAxesticks = values;
return value;
}
}
}]
}
}
});
highestVal = yAxesticks[0];