Amcharts place labels at certain x y position - javascript

I'm trying to place some label in certain x,y position inside an AmCharts xy chart.
Here's my code that add labels:
var firstChart = AmCharts.makeChart("chartdiv", config);
var i1x = firstChart.xAxes[0].getCoordinate(parseFloat(data[0].i1x));
var i1y = firstChart.yAxes[0].getCoordinate(parseFloat(data[0].i1y));
var i2x = firstChart.xAxes[0].getCoordinate(parseFloat(data[0].i2x));
var i2y = firstChart.yAxes[0].getCoordinate(parseFloat(data[0].i2y));
var iMainx = firstChart.xAxes[0].getCoordinate(parseFloat(data[0].iMainx));
var iMainy = firstChart.yAxes[0].getCoordinate(parseFloat(data[0].iMainy));
var i4x = firstChart.xAxes[0].getCoordinate(parseFloat(data[0].i4x));
var i4y = firstChart.yAxes[0].getCoordinate(parseFloat(data[0].i4y));
var i5x = firstChart.xAxes[0].getCoordinate(parseFloat(data[0].i5x));
var i5y = firstChart.yAxes[0].getCoordinate(parseFloat(data[0].i5y));
firstChart.addLabel(i1x, i1y, 'rpm', 'center', 16, 'black', 0, 1, true);
firstChart.addLabel(i2x, i2y, 'rpm', 'center', 16, 'black', 0, 1, true);
firstChart.addLabel(iMainx, iMainy, 'rpm', 'center', 16, 'black', 0, 1, true);
firstChart.addLabel(i4x, i4y, 'rpm', 'center', 16, 'black', 0, 1, true);
firstChart.addLabel(i5x, i5y, 'rpm', 'center', 16, 'black', 0, 1, true);
The problem is that i have all the Y points that are ok but the X axis is not, all the labels shouls stay on the left of the graph.
Here a screenshot

The issue involves the use of center, which doesn't quite work correctly. If you want to center-align text, try middle, which will also place the labels correctly to the left as desired.
I also highly recommend against using undocumented properties - xAxes and yAxes are internal properties that are managed by the library itself. If an update is released that changes how those properties are managed, your code may break. Use the valueAxes array instead, which is documented, and reference the desired axis by index from your config.
Demo using middle

Related

Apache Echarts: dataZoom's miniature misrepresents data in a managed plot (the plot drawn over the slider doesn't match the main plot's data)

When I create simple line plot/chart using Apache Echarts I also can add built-in data scaling mechanism: dataZoom. It reaches its main goal, but there is a question to scaled data representation, made by dataZoom. By default, dataZoom doesn't take into account the chart scale limits ticks or/and the minimum and maximum allowable values (range of a function, represented by the plot). Instead, the thumbnail of the chart is drawn on the specific value range passed to the plot in series section. In addition, everytime a small indent is added from the minimum and maximum values ​​to the borders of the graphic element.
As a result, the representation of the visualised data looks inconsistent with reality: null is not null, max is not max (because they don't match the lower and higher bounds of the coordinate area of ​​the thumbnail plot, respectively), the amplitude of the chart fluctuations does not correspond to the scale of real data fluctuations.
Screenshot
Is there a way (documented or undocumented) to remove the indents and force the plot to use the minimum and maximum values ​​allowed for the yAxis ticks?
I drawn a small example, it may be pasted to Echarts online editor.
let x = [];
let y = [];
let scaled = [];
/*y = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 300, 300,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0
];*/
for (let i = 1; i < 300; i++) {
x.push(i);
element = Math.random() * 40 + 50;
y.push(element);
scaled.push(element * 6 - 250);
}
option = {
xAxis: {
data: x
},
yAxis: {
min: 0,
max: 300
},
dataZoom: [
{
start: 50,
end: 58.5
}
],
series: [
{
name: 'Fake Data',
type: 'line',
symbol: 'none',
data: y
},
{
name: 'Simulated Scaling',
type: 'line',
symbol: 'none',
lineStyle: {
opacity: 0.3
},
data: scaled
}
]
};
As you can see, the magnitude of the fluctuations of the graph, drawn by dataZoom doesn't correspond rather to the main data, but to some kind of artificial transformation of them (light green graph). Then try to comment 11st line and uncomment lines from 4 to 7. At the start of the plot you'll see main graph touching y zero line, but not on the thumbnail.
I didn't find any params for dataZoom that make them to look like expected.

Trying to use HighCharts to build solidgauge chart with multiple layer

I'm trying to build some chart like this one:
Chart Visual
But the main struggle is to add two different series that complement each other.
I really appreciate any help that someone could give me.
Many thanks in advance.
You can achieve it, but the process of implementation is not so easy. I prepared the example which shows how to do that, and I will try to explain what I did, step by step.
First, you need to define your data array just like that:
var data = [40, 30, 10, 20]
Then define your chart configuration, and inside of chart.events.load function handler put whole logic of creating desired effect.
Next step is iterate on all data positions, and create its own specific point, series, yAxis and pane, basing on calculations like below:
load() {
var chart = this,
series = [],
panes = [],
yAxes = [],
radius = 112,
innerRadius = 88,
pointAngle,
prevPointAngle = 0,
pointPadding = (radius - innerRadius) / 4,
colors = Highcharts.getOptions().colors,
additionalPointPadding = 2;
data.forEach(function(p, i) {
pointAngle = (p * 360) / 100 // Calculate point angle
// Prepare pane for each point
panes.push({
startAngle: prevPointAngle + pointPadding + additionalPointPadding,
endAngle: (pointAngle + prevPointAngle) - pointPadding - additionalPointPadding,
background: [{
backgroundColor: '#fff',
borderWidth: 0
}]
})
// Prepare yAxis for specific pane
yAxes.push({
min: 0,
max: 100,
lineWidth: 0,
tickPositions: [],
pane: i
})
// Prepare series with specific point
series.push({
name: 'Exercise ' + i,
data: [{
color: colors[i],
radius: radius + '%',
innerRadius: innerRadius + '%',
y: 100,
percents: p
}],
yAxis: i
})
prevPointAngle += pointAngle
})
And finally, update our chart by new objects:
chart.update({
pane: panes,
yAxis: yAxes,
series: series
},true, true)
Last thing you have to know, that your chart configuration should have the same amount of empty objects in pane array, like the data positions, e.g:
var data = [10, 80, 10]
(...)
pane: [{},{},{}]
Here is the example which shows the final effect: https://jsfiddle.net/yamu5z9r/
Kind regards!

How to remove paddings in Bar chart? (Chart.JS)

Is it possible to remove paddings inside bar chart?
<canvas id="weeksChartFallout" width="660" height="200"></canvas>
var falloutArray = [12, 24, 20, 15, 18, 20, 22, 10, 10, 12, 14, 10, 16, 16];
var dataWeeksFallouts = {
labels: ["16.02", "17.02", "18.02", "19.02", "20.02", "21.02", "22.02", "23.02", "24.02", "25.02", "26.02", "27.02", "28.02", "01.03"],
datasets: [
{
label: "Fallouts",
fillColor: "rgba(63,107,245,0.67)",
data: falloutArray
}
]
};
var fc = document.getElementById('weeksChartFallout').getContext('2d');
window.weeksChartFallout = new Chart(fc).Bar(dataWeeksFallouts,{
barShowStroke : false,
barValueSpacing : 4, //distance between bars
barValueWidth: 20,
scaleShowLabels: false,
scaleFontColor: "transparent",
tooltipEvents: []
});
I mean space between first bar and left line and, especially space between last Bar and end of the chart (screenshot).
Here is my Fiddle
The x scale left and right paddings are calculated in the calculateXLabelRotation. If you have only these kind of charts you could simply replace this function to return no padding, like below
var originalCalculateXLabelRotation = Chart.Scale.prototype.calculateXLabelRotation
Chart.Scale.prototype.calculateXLabelRotation = function () {
originalCalculateXLabelRotation.apply(this, arguments);
this.xScalePaddingRight = 0;
this.xScalePaddingLeft = 0;
}
Fiddle - http://jsfiddle.net/ov9p5qhz/
Note that there is still some spacing on the left and right - that comes from your barValueSpacing: 4 option.
If you have other charts on the page that you don't want to keep separate, use Chart.noConflict()

Style specific bar column with Flot

I'm working with Flot to create a bar chart. However, I need to add special styling to certain columns. Is this possible at all?
My HTML looks like this:
<div id="monthly-usage" style="width: 100%; height: 400px;"></div>
And my JS like this:
somePlot = null;
$(function() {
//Data from this year and last year
var thisYear = [
[3, 231.01],
[4, 219.65],
[5, 222.47],
[6, 223.09],
[7, 248.43],
[8, 246.22]
];
var lastYear = [
[3, 171.7],
[4, 130.62],
[5, 163.03],
[6, 166.46],
[7, 176.16],
[8, 169.04]
];
var usageData = [{
//Usage this year
label: "2014",
data: thisYear,
bars: {
show: true,
barWidth: .3,
fill: true,
lineWidth: 0,
order: 1,
fillColor: 'rgba(194, 46, 52, .85)'
},
color: '#c22e34'
}, {
//Usage last year to compare with current usage
label: "2013",
data: lastYear,
bars: {
show: true,
barWidth: .3,
fill: true,
lineWidth: 0,
order: 2,
fillColor: 'rgba(73, 80, 94, .85)'
},
color: '#49505e'
}];
//X-axis labels
var months = [
[0, "Jan"],
[1, "Feb"],
[2, "Mar"],
[3, "Apr"],
[4, "Maj"],
[5, "Jun"],
[6, "Jul"],
[7, "Aug"],
[8, "Sep"],
[9, "Okt"],
[10, "Nov"],
[11, "Dec"]
];
//Draw the graph
somePlot = $.plot(('#monthly-usage'), usageData, {
grid: {
color: '#646464',
borderColor: 'transparent',
hoverable: true
},
xaxis: {
ticks: months,
color: '#d4d4d4'
},
yaxis: {
tickSize: 50,
tickFormatter: function(y, axis) {
return y + " kWh";
}
},
legend: {
show: false
}
});
var ctx = somePlot.getCanvas().getContext("2d"); // get the context from plot
var data = somePlot.getData()[0].data; // get your series data
var xaxis = somePlot.getXAxes()[0]; // xAxis
var yaxis = somePlot.getYAxes()[0]; // yAxis
var offset = somePlot.getPlotOffset(); // plots offset
var imageObj = new Image(); // create image
imageObj.onload = function() { // when finish loading image add to canvas
xPos = xaxis.p2c(data[4][0]) + offset.left;
yPos = yaxis.p2c(data[4][1]) + offset.top;
ctx.drawImage(this, xPos, yPos);
xPos = xaxis.p2c(data[5][0]) + offset.left;
yPos = yaxis.p2c(data[5][1]) + offset.top;
ctx.drawImage(this, xPos, yPos);
};
imageObj.src = 'path/to/file.png'; // set it's source to kick off load
});
});
Optimally, I would like to insert an icon in bar 5 and 6 that warns the user. Alternatively, I'd like to change the color of bars 5 and 6. Any ideas on how to fix this?
EDIT: I've updated my JS according to Mark's answer which works.
#Mark, how can I position the images correctly. They are a bit off. I need the image inside the red bar and not besides the bar. I'm trying to finetune this but it doesn't seem as if I can use for instance "0.5". I use side by side bars which is different from your version.
xPos = xaxis.p2c(data[4][0]) + offset.left;
yPos = yaxis.p2c(data[4][1]) + offset.top;
You can't do exactly what you ask with standard options, but there are a couple of possible approaches:
Write your own draw method and use the hooks to install it in place of the standard flot drawing code. This obviously entails a lot of work, but you'll have complete control over how to render your data. (That said, I wouldn't recommend it.)
Break your data into two different data sets. One data set would have dummy values (e.g. 0, or whatever your minimum is) for bars 5 and 6. The second data set would have dummy values for all bars except 5 and 6. You could then style the "two" data sets independently, giving each, for example a different color. Graph the two sets as a stacked bar chart with whatever additional styling tweaks are appropriate for your chart.
(As a FYI, there's a fair bit of information and examples at jsDataV.is. Look at the "Book" section; chapter 2 is dedicated to flot.)
flot gives you access to the HTML5 Canvas it's drawing on; so you just add your icon on there yourself. Borrowing from my own answer here.
var ctx = somePlot.getCanvas().getContext("2d"); // get the context from plot
var data = somePlot.getData()[0].data; // get your series data
var xaxis = somePlot.getXAxes()[0]; // xAxis
var yaxis = somePlot.getYAxes()[0]; // yAxis
var offset = somePlot.getPlotOffset(); // plots offset
$.get("someImage.txt", function(img) { // grad some image, I'm loading it from a base64 resource
var imageObj = new Image(); // create image
imageObj.onload = function() { // when finish loading image add to canvas
var xPos = xaxis.p2c(data[4][0]) + offset.left;
var yPos = yaxis.p2c(data[4][2]) + offset.top;
ctx.drawImage(this, xPos, yPos);
xPos = xaxis.p2c(data[5][0]) + offset.left;
yPos = yaxis.p2c(data[5][3]) + offset.top;
ctx.drawImage(this, xPos, yPos);
};
imageObj.src = img; // set it's source to kick off load
});
Example here.
Looks like:

correct positioning with Highcharts renderer on a bar chart

I have a Highcharts bar chart that I'm trying to add custom shapes to based on the bar values and position. To start with, I'm just trying to use highcharts.renderer.path, to add a line for each bar, as tall as the bar, positioned on the x axis based on a hard coded value. Here's a picture of what I mean:
This should be easy, and it is when the chart.type = "column". In the highcharts callback, I would use getBBox() on each bar, and translate() to convert the x axis value to a pixel value.
However, I've run into several problems when trying to do this with chart.type = "bar". First, all x and y values are switched (I assume this is how the author created the bar chart from a column chart in the first place). This is true for all the properties of the chart as well: plotLeft is now the top, plotTop is now the left.
This should work:
function (chart) {
$.each(chart.series[0].data, function (pointIndex, point) {
var plotLine = {},
elem = point.graphic.element.getBBox(),
yStart,
xStart,
newline;
yStart = chart.plotTop+elem.x;
xStart = chart.plotLeft+elem.height;
plotLine.path = ["M", xStart, yStart+1, "L", xStart, yStart+point.pointWidth];
plotLine.attr = {
'stroke-width': 1,
stroke: point.color,
zIndex: 5
};
newline = chart.renderer.path(plotLine.path).attr(plotLine.attr).add();
});
});
Full example: http://jsfiddle.net/Bh3J4/9/
The second issue may be a bug that can't be overcome. It appears that when there is more than one data point, all of the x and y values get mixed up between the points. Notice in the fiddle that the colors don't match the positions. I've created an issue on GitHub.
When there's just one point, it's not a problem. When there are two points, I could easily switch the values to get the right positioning. However when there are 3 or more points, I can't seem to figure out the logic for how the values get mixed up.
The third issue, is that the translate function doesn't seem to work on the xAxis for a bar chart, even though it does on the yAxis.
chart.yAxis[0].translate(4); // correct for bottom axis
chart.xAxis[0].translate(1); // incorrect for side axis
Is there another way to achieve what I'm looking for? Am I missing something in that Fiddle that's not actually a bug?
I was able to achieve the result I wanted, but I don't know if it's coincidental or a workaround for an actual bug. Regardless, it seems that using the x value from the reverse sorted array helped me line everything up correctly. Here's the callback function for highcharts:
function (chart) {
var benchmarks = { A: 1.5, B: 3.6, C: 2 },
reverseData = _.clone(chart.series[0].data).reverse();
_.each(chart.series[0].data, function (point, pointIndex) {
var plotLine = {},
elem = point.graphic.element.getBBox(),
reverseElem = reverseData[pointIndex].graphic.element.getBBox(),
benchmark = benchmarks[point.category],
yStart = chart.plotTop+reverseElem.x,
xStart = chart.plotLeft+chart.yAxis[0].translate(benchmark),
yEnd = yStart+point.pointWidth-1;
plotLine.path = ["M", xStart, yStart+1, "L", xStart, yEnd];
plotLine.attr = {
'stroke-width': 1,
stroke: "red",
zIndex: 5
};
chart.renderer.path(plotLine.path).attr(plotLine.attr).add();
var margin = 5,
xPadding = 10,
yPadding = 5,
xSplit = xPadding/2,
ySplit = yPadding/2,
text,
box;
text = chart.renderer.text("Top Perf Avg " + benchmark, xStart, yEnd+margin+16).attr({
color: "#646c79",
align: "center",
"font-family": "Arial, sans-serif",
"font-size": 9,
"font-weight": "bold",
style: "text-transform: uppercase",
zIndex: 7
}).add();
box = text.getBBox();
chart.renderer.path(["M", box.x-xSplit, box.y-ySplit,
"l", (box.width/2)+xSplit-margin, 0,
margin, -margin,
margin, margin,
(box.width/2)+xSplit-margin, 0,
0, box.height+yPadding,
-(box.width+xPadding), 0,
0, -(box.height+yPadding)])
.attr({
'stroke-width': 1,
stroke: "#cccccc",
fill: "#ffffff",
zIndex: 6
}).add();
});
}
See the complete working graph here: http://jsfiddle.net/Bh3J4/18/
In the fact, Highcharts rotate everything using transform, so use the same to rotate these lines, see example: http://jsfiddle.net/Bh3J4/19/
function (chart) {
var d = chart.series[0].data,
len = d.length;
for(var i =0; i < len; i++){
var point = d[i],
plotLine = {},
elem = point.graphic.element.getBBox(),
yStart,
xStart,
newline;
console.log(point,point.color);
xStart = point.plotX - point.pointWidth / 2;
yStart = point.plotY;
plotLine.path = ["M", xStart, yStart, "L", xStart+point.pointWidth, yStart];
plotLine.attr = {
transform: 'translate(491,518) rotate(90) scale(-1,1) scale(1 1)',
'stroke-width': 1,
stroke: point.color,
zIndex: 5
};
newline = chart.renderer.path(plotLine.path).attr(plotLine.attr).add();
};
}
Slight adjustment that seems to give precise alignment:
Pls note: changes to calc of xStart/yStart and change to transform translate parameter.
My approach was to make it work for column chart and then get translate refined.
The only unsatisfactory part is that xStart needs: xStart = elem.x+chart.plotLeft; in 'column' mode vs xStart = elem.x; in 'bar' mode...
function (chart) {
var d = chart.series[0].data,
len = d.length;
for(var i =0; i < len; i++){
var point = d[i],
plotLine = {},
elem = point.graphic.element.getBBox(),
yStart,
xStart,
newline;
console.log(point,point.color);
xStart = elem.x;
yStart = chart.plotHeight - (elem.height/2) + chart.plotTop;
plotLine.path = ["M", xStart, yStart, "L", xStart+point.pointWidth, yStart];
plotLine.attr = {
transform: 'translate(542.5,518) rotate(90) scale(-1,1) scale(1 1)',
'stroke-width': 5,
stroke: 'blue',
zIndex: 5
};
newline = chart.renderer.path(plotLine.path).attr(plotLine.attr).add();
};
}

Categories