C3 js : large axis label - javascript

For example:
var chart = c3.generate({
data: {
x : 'x',
columns: [
['x', 'www.site1.com11111111111111111111111111111111111111111111111111111', 'www.site2.com11111111111111111111111111111111111111111111111111111111', 'www.site3.com11111111111111111111111111111111111111111111111111111111111111', 'www.site4.com11111111111111111111111111111111111111111111111111111111111111111111111111'],
['download', 30, 200, 100, 400],
['loading', 90, 100, 140, 200],
],
groups: [
['download', 'loading']
],
type: 'bar'
},
axis: {
x: {
type: 'category', // this needed to load string x value
tick: {
rotate: 25
}
}
}
})
;
and it looks like
How can I hide the long title while keeping the ability for the user to see the full name (maybe when hovering the mouse). Or maybe better way?

You can change the text with the tick.format configuration, but actually getting the value of the text because these are category values is a bit of a PITA, see the solution below:
the tick.format function shortens the axes label text (and this is carried over into the bar chart tooltip too)
the .onrendered function adds title elements to the axes labels that show the full axes label as a basic tooltip when you mouseover them
var chart = c3.generate({
data: {
x : 'x',
columns: [
['x', 'www.site1.com11111111111111111111111111111111111111111111111111111', 'www.site2.com11111111111111111111111111111111111111111111111111111111', 'www.site3.com11111111111111111111111111111111111111111111111111111111111111', 'www.site4.com11111111111111111111111111111111111111111111111111111111111111111111111111'],
['download', 30, 200, 100, 400],
['loading', 90, 100, 140, 200],
],
groups: [
['download', 'loading']
],
type: 'bar'
},
axis: {
x: {
type: 'category', // this needed to load string x value
tick: {
rotate: 25,
format: function (d) {
var catName = this.api.categories()[d];
if (catName.length > 20) {
catName = catName.slice(0,20)+"…";
}
return catName;
}
},
}
},
onrendered: function () {
var self = this;
d3.select(this.config.bindto)
.selectAll(".c3-axis-x .tick text")
.each(function (d) {
var title = d3.select(this).select("title");
if (title.empty()) {
title = d3.select(this).append("title");
}
title.text (self.api.categories()[d]);
})
;
}
});
http://jsfiddle.net/ajh0q2e7/

Related

How to show more than one "dataMax" in Highcharts?

Currently, I'm showing a max point in the line chart. But I want to change dataMax to top 5 max value points in chart.How can I achieve this in Highcharts?
var defaultData = 'urlto.csv';
var urlInput = document.getElementById('fetchURL');
var pollingCheckbox = document.getElementById('enablePolling');
var pollingInput = document.getElementById('pollingTime');
function createChart() {
Highcharts.chart('closed5', {
chart: {
type: 'area',
zoomType: 'x'
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
style: {},
formatter: function() {
if (this.y === this.series.dataMax) {
return this.y;
}
}
}
}
},
title: {
text: 'Chart for charting'
},
data: {
csvURL: urlInput.value,
enablePolling: pollingCheckbox.checked === true,
dataRefreshRate: parseInt(pollingInput.value, 10)
}
});
if (pollingInput.value < 1 || !pollingInput.value) {
pollingInput.value = 1;
}
}
urlInput.value = defaultData;
// We recreate instead of using chart update to make sure the loaded CSV
// and such is completely gone.
pollingCheckbox.onchange = urlInput.onchange = pollingInput.onchange = createChart;
// Create the chart
createChart();
As #ewolden rightly noticed, you can sort your data and show only the five highest values:
var data = [11, 22, 33, 44, 55, 66, 15, 25, 35, 45, 55, 65],
sortedData = data.slice().sort(function(a, b){
return b - a
});
Highcharts.chart('container', {
series: [{
data: data,
dataLabels: {
enabled: true,
formatter: function() {
if (sortedData.indexOf(this.y) < 5) {
return this.y;
}
}
}
}]
});
Live demo: http://jsfiddle.net/BlackLabel/xkf2w5tb/
API: https://api.highcharts.com/highmaps/series.mapbubble.dataLabels.formatter
As far as I know formatter callback is the way to format the data labels. If you want to show the top N points you should sort the data in a new array and pull the top 5 values. This is an example of how to clone and sort the array and extract the top 5 elements in the formatter call.
let data = [32, 10, 20, 99, 30, 54, 85, 56, 11, 26, 15, 45, 55, 65];
//Copy the array
let temp = data.slice();
// Sort the temp array in descending order
temp.sort((a, b) => b - a);
Highcharts.chart('closed5', {
chart: {
type: 'area',
zoomType: 'x'
},
title: {
text: 'Chart for charting'
},
series: [{
data: data,
dataLabels: {
enabled: true,
formatter: function() {
if (temp.indexOf(this.y) < 5) {
return this.y;
}
},
},
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="closed5"></div>

Change highcharts data label position

This is my jsfiddle link http://jsfiddle.net/bb1m6xyk/1/
I want that all my labels like my data: 0 etc are positioned at the base and in center of each zone.
$('#container').highcharts({
chart: {
type: 'area'
},
yAxis: {
title: {
text: 'Percent'
}
},
plotOptions: {
area: {
enableMouseTracking: false,
showInLegend: false,
stacking: 'percent',
lineWidth: 0,
marker: {
enabled: false
},
dataLabels: {
className:'highlight',
enabled: true,
formatter: function () {
console.log(this);
return this.point.myData
}
}
}
},
series: [{
name: 'over',
color: 'none',
data: overData
}, {
id: 's1',
name: 'Series 1',
data: data,
showInLegend: true,
zoneAxis: 'x',
zones: zones
}]
});
Is this possible? I tried it using className on dataLabels but it doesn't take that into effect.
Any help is appreciated.
There are a few ways to render labels on a chart.
The Renderer
Live example: http://jsfiddle.net/11rj6k6p/
You can use Renderer.label to render the label on the chart - this is a low level approach but it gives you full control how the labels will be rendered. You can loop the zones and set x and y attributes of the labels, e.g. like this:
const labels = ['l1', 'l2', 'l3', 'l4', 'l5']
function drawLabels() {
const zonesLabels = this.zonesLabels
const series = this.get('s1')
const { yAxis, xAxis } = series
const y = yAxis.toPixels(0) - 20 // -20 is an additional offset in px
series.zones.reduce((prev, curr, i) => {
if (curr.value !== undefined) {
const x = (xAxis.toPixels(prev.value) + xAxis.toPixels(curr.value)) / 2
if (!zonesLabels[i]) {
zonesLabels.push(
this.renderer.label(labels[i], x, y).add().attr({
align: 'center',
zIndex: 10
})
)
} else {
zonesLabels[i].attr({ x, y })
}
}
return curr
}, { value: series.dataMin })
}
Then set the function on load - to render the labels, and on redraw - to reposition the labels if the chart size changed.
chart: {
type: 'area',
events: {
load: function() {
this.zonesLabels = []
drawLabels.call(this)
},
redraw: drawLabels
}
},
The annotations module
Live example: http://jsfiddle.net/a5gb7aqz/
If you do not want to use the Renderer API, you can use the annotations module which allows to declare labels in a chart config.
Add the module
<script src="https://code.highcharts.com/modules/annotations.js"></script>
Map zones to the labels config object
const labels = ['l1', 'l2', 'l3', 'l4', 'l5']
function annotationsLabels() {
const zonesLabels = []
zones.reduce((prev, curr, i) => {
zonesLabels.push({
text: labels[i],
point: {
x: (prev.value + curr.value) / 2,
y: 0,
xAxis: 0,
yAxis: 0
}
})
return curr
}, { value: 0 })
return zonesLabels
}
Set the annotations options
annotations: [{
labels: annotationsLabels(),
labelOptions: {
shape: 'rect',
backgroundColor: 'none',
borderColor: 'none',
x: 0,
y: 0
}
}],
Data labels and a new series
Live example: http://jsfiddle.net/wpk1495g/
You can create a new scatter series which will not respond to mouse events and it won't be visible in the legend. The labels can be displayed as data labels.
Map zones to series points
const labels = ['l1', 'l2', 'l3', 'l4', 'l5']
function seriesData() {
const points = []
zones.reduce((prev, curr, i) => {
points.push( {
x: (prev.value + curr.value) / 2,
y: 50,
dataLabels: {
enabled: true,
format: labels[i]
}
})
return curr
}, { value: 0 })
return points
}
Set the series options in the chart config
, {
type: 'scatter',
enableMouseTracking: false,
showInLegend: false,
data: seriesData(),
zIndex: 10,
color: 'none',
dataLabels: { style: { textOutline: false }, x: 0, y: 0 }
}
Output

"Play with this data!" not showing up for my plotly.js plot

I was under the assumption the "Play with this data!" link was supposed the show up by default. Any ideas on why it may not appear? I am just working with a basic scatter plot.
Note that this code below is not standalone as is, it is just the excerpt that does the plotly work.
var xData = [];
var yData = [];
var h = results;
for(var k in h) {
var localdate = k;
var plotdate = moment(localdate).format('YYYY-MM-DD HH:mm:ss');
xData.push(plotdate);
if (currentPort === "t") {
yData.push(CtoF(h[k]));
} else {
yData.push(h[k]);
};
}
var plotdata = [
{
x: xData,
y: yData,
type: 'scatter',
mode: 'markers+lines',
line: {
'color': HELIUM_BLUE
},
marker: {
'symbol': 'circle',
'color': HELIUM_PINK,
'maxdisplayed': 50
}
}
];
var layout = {
title: currentData,
xaxis: {
'title': 'Date / Time'
},
yaxis: {
'title': title
}
};
Plotly.newPlot(plotHolder, plotdata, layout);
You would need to add {showLink: true} as the fourth argument (after layout). I guess the default value changed from true to false.
If you want to change the caption of the button, use {showLink: true, "linkText": "Play with this data"}
var xData = [1, 2, 3, 4, 5];
var yData = [10, 1, 25, 12, 9];
var plotdata = [
{
x: xData,
y: yData,
type: 'scatter',
mode: 'markers+lines',
}
];
var layout = {
title: 'Edit me',
xaxis: {
'title': 'x'
},
yaxis: {
'title': 'y'
}
};
Plotly.newPlot(plotHolder, plotdata, layout, {showLink: true, "linkText": "Play with this data"});
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id='plotHolder'>
</div>

C3JS tooltip remains its position without mouseover behaviour

on c3js i need that the tooltip have a disable mouseover behaviour and when i make click on the data point and i've set this option in the chart but i don't get it how work exactly.
this set the position but its not a dynamic position depending of the data point
tooltip: {
position: function (data, width, height, element) {
return {top: 0, left: 0}
}
}
the chart
var chart = c3.generate({
data: {
xs: {
'data1': 'x1'
},
columns: [
['x1', 10, 20, 30],
['data1', 190, 200, 190]
],
types: {
'data1' : 'area-spline',
},
onmouseover: function (d, i) {
// alert('Hovering over');
},
selection:{
multiple:true
}
},
tooltip: {
position: function (data, width, height, element) {
return {top: 10, left: 10}
},
show: true
}
});
this tooltip remain its position next to the data point only is this possible?

ChartJS New Lines '\n' in X axis Labels or Displaying More Information Around Chart or Tooltip with ChartJS V2

I'm using chart.js (V2) to try to build a bar chart that has more information available to user without having to hover over or click anywhere. I've provided two examples of how I hope to edit my chart.
Two edited versions of what I hope to achieve
As can be seen, I hope to place (somewhere), some extra information outside of the labels. I had hope that by adding '\n' to the labels I might have been able to get what I was looking for similar to option A.
Some edited code is provided blow:
var barChartData = {
labels: playerNames,
datasets: [{
label: 'Actual Score/Hour',
backgroundColor: "rgba(0, 128, 0,0.5)",
data: playerScores
}, {
label: 'Expected Score/Hour',
backgroundColor: "rgba(255,0,0,0.5)",
data: playerExpected
}]
};
function open_win(linktosite) {
window.open(linktosite)
}
canvas.onclick = function(evt){
var activePoints = myBar.getElementsAtEvent(evt);
console.log(activePoints);
linktosite = 'https://www.mytestsite.com/' + activePoints[1]['_model']['label'];
open_win(linktosite);
};
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
title:{
display:true,
text:"Player Expected and Actual Score per Hour"
},
tooltips: {
mode: 'label'
},
responsive: true,
scales: {
xAxes: [{
stacked: false,
}],
yAxes: [{
stacked: false
}]
},
animation: {
onComplete: function () {
var ctx = this.chart.ctx;
ctx.textAlign = "center";
Chart.helpers.each(this.data.datasets.forEach(function (dataset) {
Chart.helpers.each(dataset.metaData.forEach(function (bar, index) {
// console.log("printing bar" + bar);
ctx.fillText(dataset.data[index], bar._model.x, bar._model.y - 10);
}),this)
}),this);
}
}
}
});
// Chart.helpers.each(myBar.getDatasetMeta(0).data, function(rectangle, index) {
// rectangle.draw = function() {
// myBar.chart.ctx.setLineDash([5, 5]);
// Chart.elements.Rectangle.prototype.draw.apply(this, arguments);
// }
// }, null);
};
At this point I'd be satisfied with having the extradata anywhere on the bar. Any help would be appreciated. Thanks~
Chart.js v2.1.5 allows for multi-line labels using nested arrays (v2.5.0 fixes it for radar graphs):
...
data: {
labels: [["Jake", "Active: 2 hrs", "Score: 1", "Expected: 127", "Attempts: 4"],
["Matt", "Active: 2 hrs", "Score: 4", "Expected: 36", "Attempts: 4"]],
...
However, this does mean that you will have to pre-calculate the label values.
var config = {
type: 'line',
data: {
labels: [["January","First Month","Jellyfish","30 of them"], ["February","Second Month","Foxes","20 of them"], ["March","Third Month","Mosquitoes","None of them"], "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
data: [65, 40, 80, 81, 56, 85, 45],
backgroundColor: "rgba(255,99,132,0.2)",
}, {
label: "My Second dataset",
data: [40, 80, 21, 56, 85, 45, 65],
backgroundColor: "rgba(99,255,132,0.2)",
}]
},
scales : {
xAxes : [{
gridLines : {
display : false,
lineWidth: 1,
zeroLineWidth: 1,
zeroLineColor: '#666666',
drawTicks: false
},
ticks: {
display:true,
stepSize: 0,
min: 0,
autoSkip: false,
fontSize: 11,
padding: 12
}
}],
yAxes: [{
ticks: {
padding: 5
},
gridLines : {
display : true,
lineWidth: 1,
zeroLineWidth: 2,
zeroLineColor: '#666666'
}
}]
},
spanGaps: true,
responsive: true,
maintainAspectRatio: true
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, config);
<div class="myChart">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
<canvas id="myChart"></canvas>
</div>
If a label is an array as opposed to a string i.e. [["June","2015"], "July"] then each element is treated as a separate line. The appropriate calculations are made to determine the correct height and width, and rotation is still supported.
charJS version 2.7.2 used
this also works in https://github.com/jtblin/angular-chart.js
If you are using Chart.js v2.7.1, the above solution might not work.
The solution that actually worked for us was adding a small plugin right in the data and options level:
const config = {
type: 'bar',
data: {
// ...
},
options: {
// ...
},
plugins: [{
beforeInit: function (chart) {
chart.data.labels.forEach(function (label, index, labelsArr) {
if (/\n/.test(label)) {
labelsArr[index] = label.split(/\n/)
}
})
}
}]
};
A full description of how to fix this issue can be found here.
With Chart.js v2.1, you can write a chart plugin to do this
Preview
Script
Chart.pluginService.register({
beforeInit: function (chart) {
var hasWrappedTicks = chart.config.data.labels.some(function (label) {
return label.indexOf('\n') !== -1;
});
if (hasWrappedTicks) {
// figure out how many lines we need - use fontsize as the height of one line
var tickFontSize = Chart.helpers.getValueOrDefault(chart.options.scales.xAxes[0].ticks.fontSize, Chart.defaults.global.defaultFontSize);
var maxLines = chart.config.data.labels.reduce(function (maxLines, label) {
return Math.max(maxLines, label.split('\n').length);
}, 0);
var height = (tickFontSize + 2) * maxLines + (chart.options.scales.xAxes[0].ticks.padding || 0);
// insert a dummy box at the bottom - to reserve space for the labels
Chart.layoutService.addBox(chart, {
draw: Chart.helpers.noop,
isHorizontal: function () {
return true;
},
update: function () {
return {
height: this.height
};
},
height: height,
options: {
position: 'bottom',
fullWidth: 1,
}
});
// turn off x axis ticks since we are managing it ourselves
chart.options = Chart.helpers.configMerge(chart.options, {
scales: {
xAxes: [{
ticks: {
display: false,
// set the fontSize to 0 so that extra labels are not forced on the right side
fontSize: 0
}
}]
}
});
chart.hasWrappedTicks = {
tickFontSize: tickFontSize
};
}
},
afterDraw: function (chart) {
if (chart.hasWrappedTicks) {
// draw the labels and we are done!
chart.chart.ctx.save();
var tickFontSize = chart.hasWrappedTicks.tickFontSize;
var tickFontStyle = Chart.helpers.getValueOrDefault(chart.options.scales.xAxes[0].ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
var tickFontFamily = Chart.helpers.getValueOrDefault(chart.options.scales.xAxes[0].ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
var tickLabelFont = Chart.helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
chart.chart.ctx.font = tickLabelFont;
chart.chart.ctx.textAlign = 'center';
var tickFontColor = Chart.helpers.getValueOrDefault(chart.options.scales.xAxes[0].fontColor, Chart.defaults.global.defaultFontColor);
chart.chart.ctx.fillStyle = tickFontColor;
var meta = chart.getDatasetMeta(0);
var xScale = chart.scales[meta.xAxisID];
var yScale = chart.scales[meta.yAxisID];
chart.config.data.labels.forEach(function (label, i) {
label.split('\n').forEach(function (line, j) {
chart.chart.ctx.fillText(line, xScale.getPixelForTick(i + 0.5), (chart.options.scales.xAxes[0].ticks.padding || 0) + yScale.getPixelForValue(yScale.min) +
// move j lines down
j * (chart.hasWrappedTicks.tickFontSize + 2));
});
});
chart.chart.ctx.restore();
}
}
});
and then
...
data: {
labels: ["January\nFirst Month\nJellyfish\n30 of them", "February\nSecond Month\nFoxes\n20 of them", "March\nThird Month\nMosquitoes\nNone of them", "April", "May", "June", "July"],
...
Note - we assume that the maximum content of one line will fit between the ticks (i.e. that no rotation logic is needed. I'm sure it's possible to incorporate rotation logic too, but it would be a tad more complicated)
You should format the tooltips to not show the x axis label, or format it to show a shorter version of the label.
Fiddle - http://jsfiddle.net/m0q03wpy/

Categories

Resources