Bar chart with one dataset but multiple labels - javascript

I'm trying to create a graph based on data from database using Chart.js, and I'm running into issues with making multiple labels for the data. One label is the month that the data is a part of, and the second label is the type of visit.
Here's what I have at the moment.
I'm doing this by adding in another label just for this one case:
xAxes: [{
position: 'top',
offset: 1,
ticks: {
fontColor: 'black',
beginAtZero: true,
fontSize: 35,
},
gridLines: {
display: false
},
},
{
labels: ["M SP W/I B", "M SP W/I B"],
position: 'bottom',
offset: 1,
ticks: {
fontColor: 'black',
beginAtZero: true,
fontSize: 35,
},
gridLines: {
display: false
},
}
]
Problem is it's too McGyvery. My plan is to add another Label for the dataset, besides the Month/Year and put the visit types there. This will deal with the problem where there's more or less than two months on the graph.
What I would really like to do is make it so that each bar has the label underneath it (I've already tried with the label on the bar next to the number, and it does not look good). And also I would like to get rid of the empty spaces left by the 0 value bars that would be amazing, which has already been asked.
Here is an example of what I'm trying to get at.
Is there any way to do this with Chart.js?

Related

Chart.js 3.x migration problem – thin white border / padding appears around chart on first load

I'm using Chart.js with a React wrapper (react-chartjs-2). I want to upgrade to the latest major version of Chart.js (3.x) to remove the dependency on moment, among other benefits. There are lots of breaking changes in 3.x, and I've gotten nearly everything working again with all the breaking changes, except for this one infuriatingly small thing.
There is a tiny white border around the whole chart that I cannot for the life of me get rid of. The weird part is that it disappears when the data for the chart changes and it causes a re-render. This is what it looks like:
And this is what it's supposed to look like (seamlessly disappearing into the next div on the page):
It's probably one line in options that I need to change, but I can't figure out which line it would be. I thought it might be scale.[id].grid.zeroLineColor because the 3.x upgrade guide says this: "scales.[x/y]Axes.zeroLine* options of axes were removed. Use scriptable scale options instead." But I set color using the scriptable options like this:
grid: {
color: () => "transparent"
}
and that only fixed part of the issue. Because now the "zero line" isn't grey, but there still seems to be 1px of padding or something around the whole chart, on the bottom and on the right side.
I've set every other property I can think of.
Here's what the options look like right now:
const options = {
hover: { intersect: false },
borderWidth: 0,
clip: 0,
plugins: {
legend: {
position: "bottom",
align: "center",
display: false,
},
tooltip: {
intersect: false,
mode: "index",
callbacks: {
//This removes the tooltip title
// title: function () {},
label: ({ raw }) => {
return `$${formatNumber(raw)}`;
},
},
//this removes legend color
displayColors: false,
padding: 15,
position: "average",
pointHitRadius: 20,
pointRadius: 30,
caretSize: 10,
backgroundColor: "rgba(255,255,255,.9)",
borderColor: rgbaStringFromRGBObj(palette.Vibrant.rgb, 0.35),
borderWidth: 2,
bodyFont: {
family: "Satoshi",
size: 18,
},
bodyColor: "#303030",
titleFont: {
family: "Satoshi",
},
titleColor: "rgba(0,0,0,0.6)",
},
},
scales: {
y: {
ticks: {
backdropPadding: 0,
display: false,
},
stacked: false,
grid: {
drawBorder: false,
borderWidth: 0,
drawTicks: false,
color: "transparent",
width: 0,
},
drawBorder: false,
drawTicks: false,
},
x: {
padding: 0,
ticks: {
display: false,
padding: 0,
mirror: true,
backdropPadding: 0,
},
grid: {
drawBorder: false,
drawTicks: false,
display: false,
},
drawBorder: false,
drawTicks: false,
},
},
maintainAspectRatio: false,
}
and here's a pull request with all the code in context.
This problem was happening for me when responsive was set to true in the chart's options because the width and height that the chart assumes is set to the "ones" place - it doesn't include decimals. Example:
vs.
The canvas rendered by ChartJS ignores the decimal-level specificity of its parent wrapper... Whether by bug or by design.
Solution
In my case, the aforementioned bug resulted in a small white line at the bottom of the chart.
I got around the problem by setting the parent's style to display: flex; and flexing the chart to the end with flex-direction: column; and justify-content: flex-end. Since the chart was slightly shorter than the parent, flexing it to the end (bottom) of its parent wrapper effectively "removed" the white line.
Generally: Experiment with positioning the chart with knowledge that it's probably a fraction of a pixel less wide/less tall than its parent.

How do I implement the 'autoskip' feature in chartjs?

Example
I am trying to use the autoSkip feature found here in the chart.js documentation:
https://www.chartjs.org/docs/latest/axes/cartesian/?h=autoskip
The issue I am having is my x-axes labels are overlapping (see above example).
Everything I have read says this autoSkip feature should automatically skip overlapping labels. However, when setting this to both true or false, nothing seems to change in my chart.
<Line
data={this.state.chartData}
options={{
elements: {
point: {
radius: 2
}
},
tooltips: {
mode: 'nearest',
intersect: false
},
scales: {
yAxes: [{
ticks: {
stepSize: 1, //sets the interval that our y axis counts by
beginAtZero: false, //starts our graph at 0 if true
},
gridLines: {
drawOnChartArea: false
}
}],
xAxes: [{
ticks: {
minRotation: 88,
autoskip: true,
autoSkipPadding: 50
},
gridLines: {
drawOnChartArea: false
},
type: 'time',
distribution: 'series',
time: {
unit: 'day',
displayFormats: {
day: 'MMM D',
},
tooltipFormat: 'MMM D h:mm a',
},
},
]
},
responsive: true, //lets us resize our chart
maintainAspectRatio: true, //lets us resize our chart
}
}
/>
In case anyone is wondering, please update to 2.9. Confirmed that the issue is resolved there.
https://github.com/chartjs/Chart.js/issues/6591
I noticed your autoskip is in lower case where in the documentation its in camlcase (ie. autoSkip) - from my experience with Chartjs, I've found that it might make a difference to try and fix that and see if that does the trick
You could try changing
distribution: series
to
distribution: linear
It looks to me like its trying to space the data evenly, despite the fact that you're missing data for 3 days (the weekend maybe?). It really shouldn't break your labels... but I bet the labels know there's enough space for n labels on the graph, but they don't realize that three of the labels are being squished together.
The default distribution is linear, so you could also just remove it. (https://www.chartjs.org/docs/latest/axes/cartesian/time.html#scale-distribution)
For anyone wondering, a chartjs dev has replied to my post here: https://github.com/chartjs/Chart.js/issues/6591
Looks like there are some issues in the current Chart.js version. Should be fixed in 2.9.

When using chart.js, custom tooltips disappear immediately after rendering

I'm using chart js 2 to display several Line graphs. I want to set a custom tooltip to allow me to view additional data when the user hovers over a point on the graph. However, every time I add a callback function (no matter what the function returns), it causes the tooltip to disappear. It properly renders my custom text for a brief moment, but then it disappears. I have to move my mouse around constantly to be able to read the tooltips. Here's the documentation on this function https://www.chartjs.org/docs/latest/configuration/tooltip.html#label-callback
I've tried changing virtually every chart option I can. I'm currently using the callback function 'label', but I've tried beforeLabel and afterLabel as well. One thing that I noticed had an effect is when I changed the value of "animation: { duration } ". It's currently set to 0 because I don't want any of the other animations when the charts change, because they update frequently. I set it to 1000 and I noticed that the tooltip persisted for slightly longer and had a darker background, but the overall chart rendering seemed to slow down. I've also changed the callback function's format from an arrow function to a regular function.
Here are my chart options, with the relevant portion spaced out more towards the end:
const chartOptions = {
legend: {
labels: {
fontColor: NUMBER_COLOR,
fontSize: 12
}
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: "Frame",
fontColor: SCALE_LABEL_COLOR,
fontSize: 14
},
stepSize: ystep,
ticks: {
min: XMIN,
max: XMAX,
stepSize: (XMAX - XMIN) / TICK_NUMS,
maxRotation: 0,
minRotation: 0,
fontColor: NUMBER_COLOR,
fontSize: 12
},
type: "linear"
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: this.props.yAxisUnits,
fontColor: SCALE_LABEL_COLOR,
fontSize: 14
},
ticks: {
id: "0",
min: yChartMin,
max: yChartMax,
stepSize: Number(((yChartMax - yChartMin) / TICK_NUMS).toFixed(DECIMAL_NUM)),
maxRotation: 0,
minRotation: 0,
display: true,
fontColor: NUMBER_COLOR,
fontSize: 13
}
}]
},
animation: {
duration: 0
},
tooltips: {
intersect: true,
mode: "nearest",
enabled: true,
callbacks: {
label: (tooltipItems, data) => {
const labelText = [
data.datasets[tooltipItems.datasetIndex].label + ": " + data.datasets[tooltipItems.datasetIndex].data[tooltipItems.index].y,
"Time: " + data.datasets[tooltipItems.datasetIndex].data[tooltipItems.index].time
];
return labelText;
}
}
}
};
The data points themselves each follow the format:
{
x: xValue,
y: yValue,
time: timeValue
}
and my chart is displayed via:
<Line
data={chartData}
options={chartOptions}
width={DEFAULT_WIDTH}
height={DEFAULT_HEIGHT}
getElementAtEvent={(e: any) => this.clickedElement(e)}
/>
When I delete the callback function "label", the tooltip persists and displays as expected. Please let me know if you can offer help in any way.
Thanks!

How to change the fontFamily of the labels and remove the grid in chart.js

I would like to customize the labels in chart.js, but don't seem to find the right way. Where do I need to put the styling options? What goes around it?
Is there a way to remove the Grid lines all together?
options: {
scale: {
gridLines: {
display: false
},
scaleLabel: {
fontColor: 'green',
fontSize: '24px',
fontFamily: "Montserrat"
},
ticks: {
maxTicksLimit: 1,
display: false,
},
}
},
I would expect the font color to change to green and get bigger, but it does not effect the font at all.
The same goes for the GridLines. I would expect that both vertical and horizontal lines would be removed, but the vertical Lines stay unaffected.
enter image description here
The radar chart uses a Linear Radial Axis. That documentation details all of the customization you have available for your chart axis.
Font
To configure your font as you have it above, you would want to have those settings on your options under the pointLabels property:
options: {
scale: {
pointLabels: {
fontColor: 'green',
fontSize: 24,
fontFamily: "Montserrat"
}
}
}
As a note, the fontSize property is supposed to be a number, not a string.
Angle Lines
There are two different settings for the axis lines (gridLines and angleLines). The angleLines are the lines that radiate out from the center of the chart and what you are wanting to additionally hide. To hide the angleLines, you would want to do the following:
options: {
scale: {
angleLines: {
display: false
}
}
}

Is it possible to have different colored graphs in a single series in HighCharts?

I have a single series column graph with x-axis as datetime and y-axis as some constant value. I would like to show the columns in different colors based on some information I have , is this possible ?
e.g. I have dynamic data coming in to plot my graph,I use series.addPoint({x:x,y:value,extra:info}, false, false) to plot the same. Based on the info, how can I vary the colors?
I am pretty new to javascript and highcharts. So pardon my limited knowledge, any help in the right direction would be appreciated.
Updated code:
if(type=='a')
color='#7cb5ec';
else
if(type=='b')
color='#f45b5b';
else
if(type=='c')
color='#8085e9';
else
if(type=='d')
color='#2b908f';
else
color='#e4d354';
series.addPoint({x:x,y:value,extra:info,marker:{fillColor:color}}, false, false);
I have also set the colorByPoint: true option. The series.addPoint function runs in a loop which runs as and when I get my data.
Try out the following
plotOptions: {
column: {
colorByPoint: true
}
},
colors: [
'#7cb5ec', '#434348', '#90ed7d', '#f7a35c', '#8085e9',
'#f15c80', '#e4d354', '#2b908f', '#f45b5b', '#91e8e1'
],
Fiddle link :)
Update 1:
Dynamic series fiddle:)
Update 2:
Use the following code to have specific color for specific bar
chart.series[0].addPoint({y: Math.random() * 100, color:'#659355'}, true, true);
You also can put colorByPoint: true in series option.
This way I do in my project, share for whom concern.
plotOptions: {
series: {
pointWidth: 30,
colorByPoint: true,
dataLabels: {
format: '{point.y:.0f}억원',
enabled: true,
align: 'right',
color: '#FFFFFF',
x: -5,
y: 3,
style: {
fontSize: "16px",
color: '#fff',
fontWeight: '500',
}
}
}
},
colors: Array(3).fill().map(()=>`#${Math.floor(Math.random()*16777215).toString(16)}`)

Categories

Resources