I draw a diagram, after collecting the parameters in a loop ($.each). The string is assembled, but does not work like that
var PieData = company;
And when I copy the line and paste directly it works fine.
var PieData = [{value: 14, color: '#2bea4f', highlight:'#2bea4f', label: 'Cts group'},{value: 4, color: '#411820', highlight:'#411820', label: 'СБЕРГРУЗ'},{value: 18, color: '#3b53a4', highlight:'#3b53a4', label: 'Фаворит Экспресс'},{value: 3, color: '#698bb4', highlight:'#698bb4', label: 'Бечехан'},];
How to make it work?
Source code below
//-------------
//- PIE CHART -
//-------------
// Get context with jQuery - using jQuery's .get() method.
var pieChartCanvas = $('#pieChart').get(0).getContext('2d')
var pieChart = new Chart(pieChartCanvas)
var company = "[";
$.each( obj, function( key, value ) {
var col = randColor();
company += "{value: " + value.countShip + ", color: '" + col + "', highlight:'" + col + "', label: '" + value.name + "'},";
});
company += "]";
//var PieData = company;
var PieData = [{value: 14, color: '#2bea4f', highlight:'#2bea4f', label: 'Cts group'},{value: 4, color: '#411820', highlight:'#411820', label: 'СБЕРГРУЗ'},{value: 18, color: '#3b53a4', highlight:'#3b53a4', label: 'Фаворит Экспресс'},{value: 3, color: '#698bb4', highlight:'#698bb4', label: 'Бечехан'},];
var pieOptions = {
//Boolean - Whether we should show a stroke on each segment
segmentShowStroke : true,
//String - The colour of each segment stroke
segmentStrokeColor : '#fff',
//Number - The width of each segment stroke
segmentStrokeWidth : 2,
//Number - The percentage of the chart that we cut out of the middle
percentageInnerCutout: 50, // This is 0 for Pie charts
//Number - Amount of animation steps
animationSteps : 100,
//String - Animation easing effect
animationEasing : 'easeOutBounce',
//Boolean - Whether we animate the rotation of the Doughnut
animateRotate : true,
//Boolean - Whether we animate scaling the Doughnut from the centre
animateScale : false,
//Boolean - whether to make the chart responsive to window resizing
responsive : true,
// Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
maintainAspectRatio : true,
//String - A legend template
legendTemplate : '<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'
}
//Create pie or douhnut chart
// You can switch between pie and douhnut using the method below.
pieChart.Doughnut(PieData, pieOptions);
Your question is a bit unclear, though from a brief look into your code I see that
you tried to use a String as a JSON object.
Try replacing
var PieData = company;
with
var PieData = JSON.parse(company);
Related
I am in the development of some graphs with the help of the Chart.js library and among them I am making use of a pie chart or better known with Pie Chart and I am looking for some way to add their respective percentages on the graph as well as the image that I add as an example at the end of the snippet.
Currently the graph is shown but I cannot show their respective percentages.
const pieData = [
{
value: 72,
color: "#4EADEB",
// highlight: "#FF5A5E",
label: "Avance"
},
{
value: 28,
color: "#3F86CB",
//highlight: "#5AD3D1",
label: "Pendiente"
}
];
const pieOptions = {
//Boolean - Whether we should show a stroke on each segment
segmentShowStroke: true,
//String - The colour of each segment stroke
segmentStrokeColor: "#fff",
//Number - The width of each segment stroke
segmentStrokeWidth: 2,
//Number - The percentage of the chart that we cut out of the middle
percentageInnerCutout: 0, // This is 0 for Pie charts
//Number - Amount of animation steps
animationSteps: 100,
//String - Animation easing effect
animationEasing: "easeOutBounce",
//Boolean - Whether we animate the rotation of the Doughnut
animateRotate: true,
//Boolean - Whether we animate scaling the Doughnut from the centre
animateScale: false,
//String - A legend template
legendTemplate:
'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'
};
const pieCtx = document.getElementById("myPieGraph").getContext("2d");
const myPieChart = new Chart(pieCtx).Pie(pieData, pieOptions);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.1.1/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.1.1/Chart.js"></script>
<canvas id="myPieGraph" height="120" width="240"></canvas>
Example Image:
Note:
Before the question closes for possible duplication, in this question it seeks to add the percentages but the version they use here is 0.4.0, the version that I am using of ChartJS is 1.1.1.
The use of its properties are different.
Background info:
I am trying to create a multi series doughnut chart with the data labels positioned in the center of each slice like this (see below) however I want the data labels to reposition itself if the div is resized:
Problem:
I am struggling to reposition the data labels accurately when the div is resized.
I need to get the current doughnut chart plot size in percentage with which I could calculate accurate distance from doughnut edges to place the data labels.
Example Fiddle
Here's a mockup in fiddle: http://jsfiddle.net/simkus/bo2eumkd/30/
$(function() {
var container = $('#container')[0];
$('#resizer').resizable({
// On resize, set the chart size to that of the
// resizer minus padding. If your chart has a lot of data or other
// content, the redrawing might be slow. In that case, we recommend
// that you use the 'stop' event instead of 'resize'.
// TODO we need to calculate the distance of dataLabels from the edges of the
// doughnut chart. The main thing is that the chart might be resized, to e.g. 200pxx200px
// and then the labels now gets scatared by the current algorythm where we calculate `distance`
// the `distance` should be calculated I think not in pixels by % of the current
// chart placeholder size. The chart it self has a `size` of 80% for all series.
// the inner size is also measured in %, so the distance somehow has to be done
// similary, but at this point, the `distance` doesn't work with % as size and innerSize
resize: function() {
chart.setSize(
this.offsetWidth - 20,
this.offsetHeight - 20,
false
);
}
});
let seriesData = [{
"base": 1949,
"data": [106, 105, 26, 43, 55, 136],
"name": "Total",
},
{
"base": 871,
"data": [38, 44, 14, 20, 25, 75],
"name": "Male",
},
{
"base": 1063,
"data": [65, 61, 12, 23, 31, 60],
"name": "Female",
}
]
let categories = [
"Don't know",
"Australia",
"India",
"Japan",
"Brazil",
"I don’t know"
]
let series = [];
let plotArea = 350;
let centerInnerSize = 40; // 40%
for (let i = 0; i < seriesData.length; i++) {
var showInLegend = false,
data = [],
innerSize = centerInnerSize + ((100 - centerInnerSize) / seriesData.length) * i,
width = (plotArea / 2) * ((1 - centerInnerSize / 100) / seriesData.length),
distance = (plotArea / 2) * (1 - innerSize / 100) - width / 2;
if (i == 0) {
showInLegend = true;
}
for (let j = 0; j < categories.length; j++) {
data.push({
'name': categories[j],
'y': seriesData[i].data[j]
})
}
series.push({
name: seriesData[i].name,
data: data,
innerSize: innerSize + '%',
size: "80%",
showInLegend: true,
dataLabels: {
enabled: true,
distance: -distance,
}
})
}
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
plotBackgroundColor: null,
plotBorderWidth: 1,
plotShadow: false,
type: 'pie',
events: {
render() {
let chart = this;
chart.series.forEach(s => {
s.points.forEach(p => {
let label = p.dataLabel;
p.dataLabel.translate(label.translateX, label.translateY)
})
})
}
}
},
subtitle: {
text: 'Drag the handle in the lower right to resize'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.2f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: false,
cursor: 'pointer',
minSize: 1,
dataLabels: {
enabled: true,
color: '#000000',
format: '{percentage:.2f} %',
}
}
},
series: series,
});
});
Any ideas how I can resolve this problem?
I need to get the current doughnut chart plot size in pixels with which I could calculate accurate distance from doughnut edges to place the data labels.
I am not sure what is your idea to place the data labels, but you should be able to achieve it by using the render callback where you can get access to each point and his label.
Demo: http://jsfiddle.net/BlackLabel/5m41p986/
events: {
render() {
let chart = this;
chart.series.forEach(s => {
s.points.forEach(p => {
let label = p.dataLabel;
p.dataLabel.translate(label.translateX, label.translateY)
})
})
}
}
API: https://api.highcharts.com/highcharts/chart.events.render
Updated the distance calculation using percentage and now it works.
http://jsfiddle.net/4g1pxvqb/36/
for (let i = 0; i < seriesData.length; i++) {
var showInLegend = false,
data = [],
innerSize = centerInnerSize + ((100 - centerInnerSize) / seriesData.length) * i,
width = (100 - centerInnerSize) / 3;
distance = '-' + (10 + width * (2 - i)) + '%';
I made a line chart using Chart.js version 2.1.3.
var canvas = $('#gold_chart').get(0);
var ctx = canvas.getContext('2d');
var fillPatternGold = ctx.createLinearGradient(0, 0, 0, canvas.height);
fillPatternGold.addColorStop(0, '#fdca55');
fillPatternGold.addColorStop(1, '#ffffff');
var goldChart = new Chart(ctx, {
type: 'line',
animation: false,
data: {
labels: dates,
datasets: [{
label: '',
data: prices,
pointRadius: 0,
borderWidth: 1,
borderColor: '#a97f35',
backgroundColor: fillPatternGold
}]
},
title: {
position: 'bottom',
text: '\u7F8E\u5143 / \u76CE\u53F8'
},
options: {
legend: {
display: false
},
tooltips: {
callback: function(tooltipItem) {
return tooltipItem.yLabel;
}
},
scales: {
xAxes: [{
ticks: {
maxTicksLimit: 8
}
}]
}
}
});
The output is as follow:
As you can see, I limited the maximum count of ticks to 8 via maxTicksLimit. However, the distribution is not even. How can I make the ticks distribute evenly?
p.s. there are always 289 records in the dataset, and the data is recorded every 5 minutes. Sample values of prices variable are:
[
{"14:10", 1280.3},
{"14:15", 1280.25},
{"14:20", 1282.85}
]
I tried different values of maxTicksLimit, and the results are still not distributed evenly.
Chart.js uses an integral skipRatio (to figure out how many labels to skip). With Chart.js v2.1.x, you can write your own plugin to use a fractional skipRatio
Preview
Script
Chart.pluginService.register({
afterUpdate: function (chart) {
var xScale = chart.scales['x-axis-0'];
if (xScale.options.ticks.maxTicksLimit) {
// store the original maxTicksLimit
xScale.options.ticks._maxTicksLimit = xScale.options.ticks.maxTicksLimit;
// let chart.js draw the first and last label
xScale.options.ticks.maxTicksLimit = (xScale.ticks.length % xScale.options.ticks._maxTicksLimit === 0) ? 1 : 2;
var originalXScaleDraw = xScale.draw
xScale.draw = function () {
originalXScaleDraw.apply(this, arguments);
var xScale = chart.scales['x-axis-0'];
if (xScale.options.ticks.maxTicksLimit) {
var helpers = Chart.helpers;
var tickFontColor = helpers.getValueOrDefault(xScale.options.ticks.fontColor, Chart.defaults.global.defaultFontColor);
var tickFontSize = helpers.getValueOrDefault(xScale.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
var tickFontStyle = helpers.getValueOrDefault(xScale.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
var tickFontFamily = helpers.getValueOrDefault(xScale.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
var tl = xScale.options.gridLines.tickMarkLength;
var isRotated = xScale.labelRotation !== 0;
var yTickStart = xScale.top;
var yTickEnd = xScale.top + tl;
var chartArea = chart.chartArea;
// use the saved ticks
var maxTicks = xScale.options.ticks._maxTicksLimit - 1;
var ticksPerVisibleTick = xScale.ticks.length / maxTicks;
// chart.js uses an integral skipRatio - this causes all the fractional ticks to be accounted for between the last 2 labels
// we use a fractional skipRatio
var ticksCovered = 0;
helpers.each(xScale.ticks, function (label, index) {
if (index < ticksCovered)
return;
ticksCovered += ticksPerVisibleTick;
// chart.js has already drawn these 2
if (index === 0 || index === (xScale.ticks.length - 1))
return;
// copy of chart.js code
var xLineValue = this.getPixelForTick(index);
var xLabelValue = this.getPixelForTick(index, this.options.gridLines.offsetGridLines);
if (this.options.gridLines.display) {
this.ctx.lineWidth = this.options.gridLines.lineWidth;
this.ctx.strokeStyle = this.options.gridLines.color;
xLineValue += helpers.aliasPixel(this.ctx.lineWidth);
// Draw the label area
this.ctx.beginPath();
if (this.options.gridLines.drawTicks) {
this.ctx.moveTo(xLineValue, yTickStart);
this.ctx.lineTo(xLineValue, yTickEnd);
}
// Draw the chart area
if (this.options.gridLines.drawOnChartArea) {
this.ctx.moveTo(xLineValue, chartArea.top);
this.ctx.lineTo(xLineValue, chartArea.bottom);
}
// Need to stroke in the loop because we are potentially changing line widths & colours
this.ctx.stroke();
}
if (this.options.ticks.display) {
this.ctx.save();
this.ctx.translate(xLabelValue + this.options.ticks.labelOffset, (isRotated) ? this.top + 12 : this.options.position === "top" ? this.bottom - tl : this.top + tl);
this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1);
this.ctx.font = tickLabelFont;
this.ctx.textAlign = (isRotated) ? "right" : "center";
this.ctx.textBaseline = (isRotated) ? "middle" : this.options.position === "top" ? "bottom" : "top";
this.ctx.fillText(label, 0, 0);
this.ctx.restore();
}
}, xScale);
}
};
}
},
});
Fiddle - http://jsfiddle.net/bh63pe1v/
A simpler solution until this is permanently fixed by the Chart JS contributors is to include a decimal in maxTicksLimit.
For example:
maxTicksLimit: 8,
produces a huge gap at the end.
maxTicksLimit: 8.1,
Does not produce a huge gap at the end.
Depending on what you want to set your maxTicksLimit to, you need to play around with different decimals to see which one produces the best result.
Just do this:
yAxes: [{
ticks: {
stepSize: Math.round((Math.max.apply(Math, myListOfyValues) / 10)/5)*5,
beginAtZero: true,
precision: 0
}
}]
10 = the number of ticks
5 = rounds tick values to the nearest 5 - all y values will be incremented evenly
Similar will work for xAxes too.
I want to limit the maximum width of a bar chart
My CODE:
<script>
// bar chart data
var a=[];
a.push('kalai 2015-04-11');
var b=[];
b.push('300');
var barData = {
labels : a,
datasets : [
{
fillColor : "#48A497",
strokeColor : "#48A4D1",
data : b
}
]
}
// get bar chart canvas
var income = document.getElementById("income").getContext("2d");
// draw bar chart
new Chart(income).Bar(barData, {scaleGridLineWidth : 1});
<!--new Chart(income).Bar(barData);-->
</script>
What is the way to do so
It looks like this for single value
The size of the bar reduces as the number of bar increases How can i set maximum bar size to make it more viewable
You can add new options, which are not available by default.But you need to edit chart.js
In Chart.js add these lines of code
Step 1:
//Boolean - Whether barwidth should be fixed
isFixedWidth:false,
//Number - Pixel width of the bar
barWidth:20,
Add these two line in defaultConfig of Bar Chart
Step 2:
calculateBarWidth : function(datasetCount){
**if(options.isFixedWidth){
return options.barWidth;
}else{**
//The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing);
return (baseWidth / datasetCount);
}
Add this condition in calculateBarWidth function of barchart
Now you can set barWidth in custom js file as option by setting
isFixedWidth:true,
barWidth:xx
If you don't want to specify fixed barwidth, just change isFixedWidth:false
Its kinda late to answer this but hope this helps someone out there... play around with barDatasetSpacing [ adds spacing after each bar ] and barValueSpacing [ adds spacing before each bar ] to be able to achieve your desired bar width.. example below when initiating your bar chart
... barDatasetSpacing:10, barValueSpacing:30, ...
Hope it helps..
I did it by extending Bar chart, and calculating barValueSpacing dynamically. I use angular chartjs
var MAX_BAR_WIDTH = 50;
Chart.types.Bar.extend({
name: "BarAlt",
draw: function(){
var datasetSize = n // calculate ur dataset size here
var barW = this.chart.width / datasetSize;
if(barW > MAX_BAR_WIDTH){
this.options.barValueSpacing = Math.floor((this.chart.width - (MAX_BAR_WIDTH * datasetSize)) / datasetSize);
}
Chart.types.Bar.prototype.draw.apply(this, arguments);
}
});
Did you tried following options?
{
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
scaleBeginAtZero : true,
//Boolean - Whether grid lines are shown across the chart
scaleShowGridLines : true,
//String - Colour of the grid lines
scaleGridLineColor : "rgba(0,0,0,.05)",
//Number - Width of the grid lines
scaleGridLineWidth : 1,
//Boolean - Whether to show horizontal lines (except X axis)
scaleShowHorizontalLines: true,
//Boolean - Whether to show vertical lines (except Y axis)
scaleShowVerticalLines: true,
//Boolean - If there is a stroke on each bar
barShowStroke : true,
//Number - Pixel width of the bar stroke
barStrokeWidth : 2,
//Number - Spacing between each of the X value sets
barValueSpacing : 5,
//Number - Spacing between data sets within X values
barDatasetSpacing : 1,
//String - A legend template
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
}
I am using flot to generate bar graphs.
Here is my code bar graph code
I need to make the y axis tick to disappear.
I need to put some label on the top of each bar
How to do it?
Okay, after a lot of mucking around with Flot and downloading the source, I finally figured out a good starting point for you.
The jsFiddle demo is here.
The guts of the code is using a hook for drawSeries which draws the label:
function drawSeriesHook(plot, canvascontext, series) {
var ctx = canvascontext,
plotOffset = plot.offset(),
labelText = 'TEST', // customise this text, maybe to series.label
points = series.datapoints.points,
ps = series.datapoints.pointsize,
xaxis = series.xaxis,
yaxis = series.yaxis,
textWidth, textHeight, textX, textY;
// only draw label for top yellow series
if (series.label === 'baz') {
ctx.save();
ctx.translate(plotOffset.left, plotOffset.top);
ctx.lineWidth = series.bars.lineWidth;
ctx.fillStyle = '#000'; // customise the colour here
for (var i = 0; i < points.length; i += ps) {
if (points[i] == null) continue;
textWidth = ctx.measureText(labelText).width; // measure how wide the label will be
textHeight = parseInt(ctx.font); // extract the font size from the context.font string
textX = xaxis.p2c(points[i] + series.bars.barWidth / 2) - textWidth / 2;
textY = yaxis.p2c(points[i + 1]) - textHeight / 2;
ctx.fillText(labelText, textX, textY); // draw the label
}
ctx.restore();
}
}
See the comments for where you can customise the label.
To remove the y-axis ticks, that is just a simple option setting. In addition, you can work out the maximum y-value for each of the bar stacks and then add about 100 to that to set a maximum Y value that will allow for the space taken up by the labels. The code for all of that then becomes:
// determine the max y value from the given data and add a bit to allow for the text
var maxYValue = 0;
var sums = [];
$.each(data,function(i,e) {
$.each(this.data, function(i,e) {
if (!sums[i]) {
sums[i]=0;
}
sums[i] += this[1]; // y-value
});
});
$.each(sums, function() {
maxYValue = Math.max(maxYValue, this);
});
maxYValue += 100; // to allow for the text
var plot = $.plot($("#placeholder"), data, {
series: {
stack: 1,
bars: {
show: true,
barWidth: 0.6,
},
yaxis: {
min: 0,
tickLength: 0
}
},
yaxis: {
max: maxYValue, // set a manual maximum to allow for labels
ticks: 0 // this line removes the y ticks
},
hooks: {
drawSeries: [drawSeriesHook]
}
});
That should get you started. You can take it from here, I'm sure.