Datalabels plugin throws error when using scriptable option - chart.js

I have a doughnut chart. I'm using chartjs-plugin-datalabels. For the backgroundColor I'm using the following config:
plugins: {
datalabels: {
backgroundColor: function(context) {
return context.dataset.backgroundColor;
}
}
Based on the docs, the background color property should permit scriptable options.
I am receiving the below error:
error TS2322: Type '(context: Context) => string | string[] | CanvasGradient | CanvasPattern | ChartColor[]' is not assignable to type 'string | CanvasGradient | CanvasPattern | (string | CanvasGradient | CanvasPattern)[] | ((context: Context) => string | CanvasGradient | CanvasPattern)'.
I'm using the following libraries versions:
"chart.js": "^2.8.0",
"chartjs-plugin-datalabels": "^0.6.0",

Since the pie chart defines an array of backgroundColor for each dataset in it and the function is called for each datalabel on the chart, you will need a way to tell which color in the array the function should use, probably using the index will do the trick.
Try something like this:
return context.dataset.backgroundColor[context.dataIndex];

Related

ChartJS 4 migration: access other datasets from tooltip callback

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}%)`
}
}

change color of single dataLabel in ApexCharts

I want to change dataLabel color for specific value in my bar chart.
documentation says:
Also, if you are rendering a bar/pie/donut/radialBar chart, you can pass a function which returns color based on the value.
I know this is for bar colors but I tried to use it in dataLabel colors. of course it didn't work. any idea how to do it?
my codepen: https://codepen.io/osmanyasircankaya/pen/gOXELmB
style: {
colors: [
function ({ w }) {
if (w.config.series[0].data[4] > 3) {
return "#ff0014";
} else {
return "#1f52b0";
}
},
],
},
docs:
https://apexcharts.com/docs/options/colors/
https://apexcharts.com/docs/options/datalabels/
In your function you checking value of single dataPoint over and over data[4]. What you need to do is checking current series and dataPoint like this:
function ({ seriesIndex,dataPointIndex, w }) {
if (w.config.series[seriesIndex].data[dataPointIndex] > 3) {
return "#ff0014";
} else {
return "#1f52b0";
}
},

ChartJS Tooltip - Change Data Format Displayed

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;
},
},
},
}

Type error when processing graphql result

I just started playing with reasonML and graphql and have built a simple react component that retrieves data from a world cup API. My code is below:
[#bs.module] external gql: ReasonApolloTypes.gql = "graphql-tag";
module GetMatches = [%graphql
{|
query getMatches($id: ID!){
matches(id: $id) {
date
homeTeam {name}
awayTeam {name}
homeScore
awayScore
goals {
scorer {
name
}
time
}
}
}
|}
];
module GetMatchesQuery = ReasonApollo.CreateQuery(GetMatches);
let component = ReasonReact.statelessComponent("Matches");
let make = _children => {
...component,
render: _self => {
let matchParam = GetMatches.make(~id="300331511", ());
<GetMatchesQuery variables=matchParam##variables>
...{
({result}) =>
switch (result) {
| Loading => <div> {ReasonReact.string("Loading")} </div>
| Error(error) =>
<div> {ReasonReact.string(error##message)} </div>
| Data(response) => <Matches matches=response##matches />
}
}
</GetMatchesQuery>;
},
};
Matches Component
let component = ReasonReact.statelessComponent("Matches");
let make = (~matches, _children) => {
...component,
render: _self =>
<div>
{
matches
|> Js.Array.map(match => <Match match key=match##id />)
|> ReasonReact.array
}
</div>,
};
But I'm getting this error:
This has type:
option(Js.Array.t(option({. "awayScore": option(int),
"awayTeam": option({. "name": option(string)}),
"date": option(string),
"goals": option(Js.Array.t(option({. "scorer":
option(
{. "name":
option(
string)}),
"time":
option(
string)}))),
"homeScore": option(int),
"homeTeam": option({. "name": option(string)})})))
But somewhere wanted:
Js.Array.t(Js.t(({.. id: string} as 'a))) (defined as array(Js.t('a)))
I added Js.log(response##matches); and got this in the console
I'm pretty sure there's some context missing here, and that you have something like open Belt at the top of your file.
The type error says response##matches is an array in an option, but also that the array elements themselves are in options, which is super weird. So my theory is that the code generated by graphql-ppx uses something like array indexing, which translates to a call to Array.get that in the standard library throws an exception if out of bounds, but in Belt, and many other standard libraries replacements, returns an option.
This is one of many problems with using ppxs. It generates code not in isolation and can interact weirdly with the rest of your code, and it's not easy to debug.

Obtain max value of y axis of line chart rendered with Chart.js

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];