Multiple Shape annotations on D3plus line plot - d3.js

I have a line plot created using d3plus, and I need to have multiple line annotations (one horizontal and two vertical) with Shape labels to identify them. I am able to get the lines to show properly, but I am unable to get multiple labels to show up on the graph.
Here is my set of data:
[
{"id":"line","myDate":"Sep 2011","value":8303269},
{"id":"line","myDate":"Jul 2012","value":8389066},
{"id":"line","myDate":"Sep 2012","value":8632844},
{"id":"line","myDate":"Mar 2013","value":8926414},
{"id":"line","myDate":"Jun 2013","value":9169985},
{"id":"line","myDate":"Mar 2014","value":9273689},
{"id":"line","myDate":"Sep 2014","value":9343712},
{"id":"line","myDate":"Dec 2014","value":9416974},
{"id":"line","myDate":"May 2015","value":9546380},
{"id":"line","myDate":"Sep 2015","value":10484320},
{"id":"line","myDate":"Sep 2015","value":11455165},
{"id":"line","myDate":"Dec 2015","value":11997581},
{"id":"line","myDate":"Apr 2016","value":12104931},
{"id":"line","myDate":"May 2016","value":12111915},
{"id":"line","myDate":"Jun 2016","value":12127119},
{"id":"line","myDate":"Jul 2016","value":12800226},
{"id":"line","myDate":"Mar 2017","value":12915303},
{"id":"line","myDate":"Nov 2017","value":12947360},
{"id":"line","myDate":"Nov 2018","value":12957309}
]
and here is my LinePlot annotations array.
new LinePlot()
.select("#demo")
.height(500)
.config({
data: vm.plotData,
x: 'myDate',
y: 'value',
groupBy: 'id',
annotations: [
{
data: [
{id: "start", x: "Jul 2012", y: 8000000},
{id: "start", x: "Jul 2012", y: 20000000},
{id: "end", x: "Nov 2017", y: 8000000},
{id: "end", x: "Nov 2017", y: 20000000},
{id: "dotted", x: "Sep 2011", y: this.item.ceilingValue},
{id: "dotted", x: "Nov 2018", y: this.item.ceilingValue}
],
shape: "Line",
stroke: function(d) {
return d.id === "box" ? "blue" : "green";
},
strokeDasharray: "10",
strokeWidth: 2
},
{
data: [
{
x: 'Jul 2012',
y: 20000000,
width: 100,
height: 25
}
],
fill: "#0c1971",
label: "Start Date",
labelConfig: {
textAnchor: "middle",
verticalAlign: "middle"
},
shape: "Rect"
},
{
data: [
{
x: 'Nov 2017',
y: 20000000,
width: 10,
height: 25
}
],
fill: "#255832",
label: "End Date",
labelConfig: {
textAnchor: "middle",
verticalAlign: "middle"
},
shape: "Rect"
}
]
})
.render()
What happens is that when I just have the Start Date item, it works fine, but when I add the End Date object, the first one disappears, and the second one isn't fully rendered.
According to the docs, annotations accepts
custom config objects for the Shape class, either a single config object or an array of config objects.`,
which is what I've provided, so I'm not sure where the problem is. What do I need to change to get all of my labels to appear properly?

I was able to figure it out based on this comment. The gist is that you have to combine all items of a particular Shape into one object:
annotations: [
{
data: [
{id: "start", x: "Jul 2012", y: 8000000},
{id: "start", x: "Jul 2012", y: 20000000},
{id: "end", x: "Nov 2017", y: 8000000},
{id: "end", x: "Nov 2017", y: 20000000},
{id: "dotted", x: "Sep 2011", y: this.item.ceilingValue},
{id: "dotted", x: "Nov 2018", y: this.item.ceilingValue}
],
shape: "Line",
stroke: function(d) {
return d.id === "box" ? "blue" : "green";
},
strokeDasharray: "10",
strokeWidth: 2
},
{
data: [
{
id: 'start',
label: 'Start Date',
x: 'Jul 2012',
y: 20000000,
width: 100,
height: 25
},
{
id: 'end',
label: 'End Date',
x: 'Nov 2017',
y: 20000000,
width: 100,
height: 25
}
],
fill: function(d) {
let result;
switch (d.id) {
case 'start':
result = "#0c1971";
break;
case 'end':
result = "#255832";
break;
}
return result;
},
label: function (d) {
let result;
switch (d.id) {
case 'start':
result = "Start Date";
break;
case 'end':
result = "End Date";
break;
}
return result;
},
labelConfig: {
textAnchor: "middle",
verticalAlign: "middle"
},
shape: "Rect"
}
]

Related

ChartJS: How to center monthly bars against a daily line chart?

I'm trying to display total monthly sales and daily stock level. This way you could easily see that you didn't have any sales a particular month because you had low stock. Monthly sales is a bar chart that should be in the center of each month (in between the ticks).
In order to get it close to the middle my data is using the 15th of each month as the date to center it. I would want to know if there is a better way to achieve this?
JSFiddle to play around with: https://jsfiddle.net/8Lydhpqc/3/
const dailyStock = [
{ x: "2017-08-02", y: 1 },
{ x: "2017-08-25", y: 3 },
{ x: "2017-09-10", y: 7 },
{ x: "2017-09-28", y: 0 },
{ x: "2017-10-02", y: 3 },
{ x: "2017-10-24", y: 2 },
{ x: "2017-11-01", y: 1 },
{ x: "2017-11-30", y: 0 },
];
//using the 15th of each month to center it
const monthlyTotal = [
{ x: "2017-08-15", y: 1 },
{ x: "2017-09-15", y: 10 },
{ x: "2017-10-15", y: 5 },
{ x: "2017-11-15", y: 5 },
];
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: ["2017-08", "2017-09", "2017-10", "2017-11"],
datasets: [
{
label: "sales",
data: data,
backgroundColor: "green",
borderColor: "black",
borderWidth: 1,
order: 2,
},
{
label: "stock",
type: "line",
data: dailyStock,
backgroundColor: "orange",
borderColor: "orange",
fill: false,
order: 1,
},
],
},
options: {
scales: {
xAxes: [
{
type: "time",
time: {
unit: "month",
displayFormats: {
month: "MMM",
},
},
distribution: "linear",
},
],
yAxes: [
{
ticks: {
beginAtZero: true,
},
},
],
},
},
});
Welcome to Stackoverflow!
It seems that there is a way better than using the 15th of the month.
You need to add another axis for the bar that is a category type axis. Also its pretty critical that you have "offset: true" on that axis as well. Otherwise it will not center.
In the code below I named that category "bar" and the existing one "line"
I also created a fiddle: https://jsfiddle.net/jyf8ax3e/
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: ["2017-08", "2017-09", "2017-10", "2017-11"],
datasets: [
{
barPercentage: .7,
xAxisID: "bar",
label: "sales",
data: monthlyTotal,
backgroundColor: "green",
borderColor: "black",
borderWidth: 1,
width: 55,
order: 2,
},
{
label: "stock",
type: "line",
data: dailyStock,
backgroundColor: "orange",
borderColor: "orange",
fill: false,
order: 1,
},
],
},
options: {
scales: {
xAxes: [
{
id: "line",
type: "time",
time: {
unit: "month",
displayFormats: {
month: "MMM",
},
},
distribution: "linear",
},
{
id: "bar",
offset: true,
type: "category",
distribution: "series",
}
],
yAxes: [
{
ticks: {
beginAtZero: true,
},
},
],
},
},
});

canvasjs in decimal format with suffix is not working properly

I use canvasJS to make a line graph report, the issue now is it didn't show properly in tooltip using yValueFormatString.
my goal is to display the value:
{
type:"stepLine",
name: "title",
showInLegend: true,
connectNullData: true,
yValueFormatString: "##.## %",
dataPoints: [
{ x: new Date(2019, 1, 20), y: 12.78 },
{ x: new Date(2019, 1, 19), y: 12.79 },
{ x: new Date(2019, 1, 18), y: 12.80 },
]
}
in tooltip, it shows
1278 %
1279 %
1280 %
I think there's something wrong with it, I wanted to display like:
12.78 %
12.79 %
12.80 %
any idea?
According to documentation, "%" Multiplies a number by 100 i.e. 12.78("##.## %") => 1278%. Instead setting yValueFormatString to "##.#0 '%'" should work fine in this case.
Here is an example:
var chart = new CanvasJS.Chart("chartContainer", {
data: [{
type:"stepLine",
name: "title",
showInLegend: true,
connectNullData: true,
yValueFormatString: "##.#0 '%'",
dataPoints: [
{ x: new Date(2019, 1, 20), y: 12.78 },
{ x: new Date(2019, 1, 19), y: 12.79 },
{ x: new Date(2019, 1, 18), y: 12.80 },
]
}]
});
chart.render();
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<div id="chartContainer" style="width: 100%; height: 260px"></div>

Custom label values for Y axis in amcharts

Can I set Custom label values for Y axis in amcharts js?
example : convert 10,20,30,... y-axis value to 'very low','low','high'
There are two solutions here.
The first solution uses a labelFunction in your valueAxis to specify what label you want given the value being drawn on the chart, i.e
valueAxes: [
{
minimum: 0,
maximum: 50,
strictMinMax: true,
labelFunction: function(value, valueText, valueAxis) {
switch (value) {
case 10:
valueText = "Very Low";
break;
case 20:
valueText = "Low";
break;
case 30:
valueText = "Average";
break;
case 40:
valueText = "Above Average";
break;
case 50:
valueText = "High";
break;
default:
valueText = "";
}
return valueText;
}
}
],
Demo:
var chart = AmCharts.makeChart("chartdiv", {
type: "serial",
theme: "light",
valueAxes: [
{
minimum: 0,
maximum: 50,
strictMinMax: true,
labelFunction: function(value, valueText, valueAxis) {
switch (value) {
case 10:
valueText = "Very Low";
break;
case 20:
valueText = "Low";
break;
case 30:
valueText = "Average";
break;
case 40:
valueText = "Above Average";
break;
case 50:
valueText = "High";
break;
default:
valueText = "";
}
return valueText;
}
}
],
dataProvider: [
{
category: "cat-1",
value: 32
},
{
category: "cat-2",
value: 41
},
{
category: "cat-3",
value: 27
},
{
category: "cat-4",
value: 29
},
{
category: "cat-5",
value: 22
},
{
category: "cat-6",
value: 11
},
{
category: "cat-7",
value: 46
},
{
category: "cat-8",
value: 18
},
{
category: "cat-9",
value: 32
},
{
category: "cat-10",
value: 32
}
],
graphs: [
{
fillAlphas: 0.9,
lineAlpha: 0.2,
type: "column",
valueField: "value"
}
],
categoryField: "category"
});
#chartdiv {
width: 100%;
height: 300px;
}
<script src="//www.amcharts.com/lib/3/amcharts.js"></script>
<script src="//www.amcharts.com/lib/3/serial.js"></script>
<script src="//www.amcharts.com/lib/3/themes/light.js"></script>
<div id="chartdiv"></div>
Note that this solution is slightly brittle in that you're depending on the value axis to generate the correct scale (increments of 10, for instance) and there isn't a guaranteed way to control that.
The better solution is to use guides instead to draw your axis labels, lines and ticks at the appropriate points on the axis, while disabling the ones generated by the axis to ensure that you get the correct lines:
valueAxes: [
{
minimum: 0,
maximum: 50,
strictMinMax: true,
//disable the axis' labels, gridAlpha and tickLength so you can
//draw them using guides
labelsEnabled: false,
gridAlpha: 0,
tickLength: 0,
guides: [{
value: 10,
tickLength: 5,
lineAlpha: .15,
label: "Very Low"
},{
value: 20,
tickLength: 5,
lineAlpha: .15,
label: "Low"
},{
value: 30,
tickLength: 5,
lineAlpha: .15,
label: "Average"
},{
value: 40,
tickLength: 5,
lineAlpha: .15,
label: "Above Average"
},{
value: 50,
tickLength: 5,
lineAlpha: .15,
label: "High"
}]
}
]
Demo:
var chart = AmCharts.makeChart("chartdiv", {
type: "serial",
theme: "light",
valueAxes: [
{
minimum: 0,
maximum: 50,
strictMinMax: true,
labelsEnabled: false,
gridAlpha: 0,
tickLength: 0,
guides: [{
value: 10,
tickLength: 5,
lineAlpha: .15,
label: "Very Low"
},{
value: 20,
tickLength: 5,
lineAlpha: .15,
label: "Low"
},{
value: 30,
tickLength: 5,
lineAlpha: .15,
label: "Average"
},{
value: 40,
tickLength: 5,
lineAlpha: .15,
label: "Above Average"
},{
value: 50,
tickLength: 5,
lineAlpha: .15,
label: "High"
}]
}
],
dataProvider: [
{
category: "cat-1",
value: 32
},
{
category: "cat-2",
value: 41
},
{
category: "cat-3",
value: 27
},
{
category: "cat-4",
value: 29
},
{
category: "cat-5",
value: 22
},
{
category: "cat-6",
value: 11
},
{
category: "cat-7",
value: 46
},
{
category: "cat-8",
value: 18
},
{
category: "cat-9",
value: 32
},
{
category: "cat-10",
value: 32
}
],
graphs: [
{
fillAlphas: 0.9,
lineAlpha: 0.2,
type: "column",
valueField: "value"
}
],
categoryField: "category"
});
#chartdiv {
width: 100%;
height: 300px;
}
<script src="//www.amcharts.com/lib/3/amcharts.js"></script>
<script src="//www.amcharts.com/lib/3/serial.js"></script>
<script src="//www.amcharts.com/lib/3/themes/light.js"></script>
<div id="chartdiv"></div>
In v4, you can use adapters to achieve this.
var chart = AmCharts.makeChart("chartdiv", {
type: "serial",
theme: "light",
valueAxes: [
{
minimum: 0,
maximum: 100,
strictMinMax: true,
labelsEnabled: false,
gridAlpha: 0,
tickLength: 0,
guides: [{
value: 10,
tickLength: 2,
lineAlpha: .15,
label: "Very Low"
},{
value: 20,
tickLength: 2,
lineAlpha: .15,
label: "Low"
},{
value: 30,
tickLength: 2,
lineAlpha: .15,
label: "Average"
},{
value: 40,
tickLength:2,
lineAlpha: .15,
label: "Above Average"
},{
value: 50,
tickLength: 2,
lineAlpha: .15,
label: "High"
}]
}
],
dataProvider: [
{
category: "cat-1",
value: 32
},
{
category: "cat-2",
value: 41
},
{
category: "cat-3",
value: 27
},
{
category: "cat-4",
value: 29
},
{
category: "cat-5",
value: 22
},
{
category: "cat-6",
value: 11
},
{
category: "cat-7",
value: 46
},
{
category: "cat-8",
value: 18
},
{
category: "cat-9",
value: 32
},
{
category: "cat-10",
value: 32
}
],
graphs: [
{
fillAlphas: 0.9,
lineAlpha: 0.1,
type: "column",
valueField: "value"
}
],
categoryField: "category"
});
#chartdiv {
width: 100%;
height: 300px;
}
<script src="//www.amcharts.com/lib/3/amcharts.js"></script>
<script src="//www.amcharts.com/lib/3/serial.js"></script>
<script src="//www.amcharts.com/lib/3/themes/light.js"></script>
<div id="chartdiv"></div>

Generate an array of charts

I want to generate an array of charts and insert them into the DOM.
(I want to use these charts as templates and insert them at the right time)
like that:
Var array = [];
array[0].kendoChart ({// .........});
array[1].kendoChart ({// .........});
array.forEach (function (el) {
$('body').append(el);
})
Tell me how to be?
I would keep an array of the data used to generate the charts, and then generate them at the time of insert.
In HTML provide a container for the charts to be inserted (could be body as in your example):
<div id="chartsContainer" ></div>
Then in script have an array of the data needed to generate the multiple charts, e.g. :
var charts = [
{
chartid: "id1", title: "Chart 1",
data: [{ x: "item1", y: 2}, { x: "item2", y: 4},{ x: "item3", y: 1}]
},
{
chartid: "id2", title: "Chart 2",
data: [{ x: "item1", y: 8}, { x: "item2", y: 3},{ x: "item3", y: 7},{ x: "item4", y: 2}]
},
{
chartid: "id3", title: "Chart 3",
data: [{ x: "item1", y: 1}, { x: "item2", y: 2},{ x: "item3", y: 4} ]
},
];
Finally loop through the array, insert DIVs in the container and create a chart in each DIV:
$("#chartsContainer").empty();
var arrayLength = charts.length;
for (var i = 0; i < arrayLength; i++) {
var div = $('<div id="' + charts[i].chartid + '"></div>');
$("#chartsContainer").append(div);
div.kendoChart({
theme: "Flat",
chartArea: { height: 200 },
dataSource: {data: charts[i].data },
title: { text: charts[i].title},
seriesDefaults: {type: "column"},
series: [{field: "y" }],
categoryAxis: {
field: "x",
majorGridLines: {visible: false },
}
});
}
Working DEMO

canvasJS x axis change between different screen

I use canvasJS to paint chart,but when the page change different window, the X axis will show different. when page open in little window show right like this enter image description here,but when page show big window show wrong like thisenter image description here
var chart = new CanvasJS.Chart("chartContainer", {
zoomEnabled: false,
animationEnabled: false,
title: {
text: "BJS Site Record Item QTY"
},
axisY2: {
valueFormatString: "0",
maximum: 50,
interval: 5,
interlacedColor: "#F5F5F5",
gridColor: "#D7D7D7",
tickColor: "#D7D7D7"
},
axisX:{
//title: "BJS Site Record Item QTY",
interval: 1
},
theme: "theme2",
toolTip: {
shared: true
},
legend: {
verticalAlign: "bottom",
horizontalAlign: "center",
fontSize: 15,
fontFamily: "Lucida Sans Unicode"
},
data: [
{
type: "line",
lineThickness: 3,
axisYType: "secondary",
showInLegend: true,
name: "BJSC",
dataPoints: [
{ x: new Date(2016,11,08), y:11 },
{ x: new Date(2016,11,09), y:0 },
{ x: new Date(2016,11,10), y:0 },
{ x: new Date(2016,11,11), y:0 },
{ x: new Date(2016,11,12), y:0 },
{ x: new Date(2016,11,13), y:0 },
{ x: new Date(2016,11,14), y:0 },
]
},
],
legend: {
cursor: "pointer",
itemclick: function (e) {
if (typeof (e.dataSeries.visible) === "undefined" || e.dataSeries.visible) {
e.dataSeries.visible = false;
}
else {
e.dataSeries.visible = true;
}
chart.render();
}
}
});
chart.render();
}
</script>
Scott,
intervalType defaults to “number” when you set the interval. If you prefer interval to be 1 day, set intervalType to "day" along with setting interval to 1.
Check this code.
var chart = new CanvasJS.Chart("chartContainer", {
zoomEnabled: false,
animationEnabled: false,
title: {
text: "BJS Site Record Item QTY"
},
axisY2: {
valueFormatString: "0",
maximum: 50,
interval: 5,
interlacedColor: "#F5F5F5",
gridColor: "#D7D7D7",
tickColor: "#D7D7D7"
},
axisX: {
//title: "BJS Site Record Item QTY",
interval: 1,
intervalType: "day"
},
theme: "theme2",
toolTip: {
shared: true
},
legend: {
verticalAlign: "bottom",
horizontalAlign: "center",
fontSize: 15,
fontFamily: "Lucida Sans Unicode"
},
data: [
{
type: "line",
lineThickness: 3,
axisYType: "secondary",
showInLegend: true,
name: "BJSC",
dataPoints: [
{ x: new Date(2016, 11, 08), y: 11 },
{ x: new Date(2016, 11, 09), y: 0 },
{ x: new Date(2016, 11, 10), y: 0 },
{ x: new Date(2016, 11, 11), y: 0 },
{ x: new Date(2016, 11, 12), y: 0 },
{ x: new Date(2016, 11, 13), y: 0 },
{ x: new Date(2016, 11, 14), y: 0 }
]
},
],
legend: {
cursor: "pointer",
itemclick: function(e) {
if (typeof(e.dataSeries.visible) === "undefined" || e.dataSeries.visible) {
e.dataSeries.visible = false;
} else {
e.dataSeries.visible = true;
}
chart.render();
}
}
});
chart.render();
<script type="text/javascript" src="http://canvasjs.com/assets/script/canvasjs.min.js"></script>
<div id="chartContainer" style="height: 250px; width: 100%;"></div>

Resources