Highcharts: Multiple Columnrange with point inside of each of them - highcharts

Let's say I am doing temperature graph for 2 cities. I want to have minimum and maximum temperature for each month and average month temperature in one bar.
I have found (and changed a bit) an example which works perfectly for one city (jsfiddle here). That's the result I want.
Stackoverflow wants me to put some code here because of jsfiddle,
but I really don't know if it is good idea to paste here allt that
long JS code
However I need it for two (or more) cities for each month. For now, I have this (jsfiddle here), but the average points are not placed inside of bars, instead the appear somewhere in the middle.
Is there a way how to have multiple cities with average points placed inside of each bar ? I don't know what I am missing.
Thanks in advance.

Not a perfect solution, but should be good starting point:
(function(H) {
H.wrap(H.seriesTypes.columnrange.prototype, 'drawPoints', function(p) {
var s = this,
chart = s.chart,
xAxis = s.xAxis,
yAxis = s.yAxis,
path, x, y,
r = chart.renderer,
radius = s.barW / 2;
p.call(this);
H.each(this.points, function(p) {
if(p.options.avg) {
y = yAxis.toPixels(p.options.avg * (-1), true);
x = p.plotX + s.columnMetrics.offset + radius;
path = [
'M', x - radius, y - radius,
'L', x + radius, y - radius,
'L', x + radius, y + radius,
'L', x - radius, y + radius,
'Z'
];
if(p.avgShape) {
p.avgShape.attr({
d: path
});
} else {
p.avgShape = r.path(path).attr({
fill: s.options.avgColor
}).add(s.group);
}
}
});
});
})(Highcharts)
Demo: http://jsfiddle.net/r6fha9he/3/
One hacky thing to mention - values are multiplied by *(-1), because toPixels() won't recognize inverted chart, and I would like to avoid using axis.translate(). The same is not necessary for non-inverted chart. In case you are more interested in translate, search source code for:
/**
* Translate from axis value to pixel position on the chart, or back
*
*/
translate: function (val, backwards, cvsCoord, old, handleLog, pointPlacement) {

Related

How to add line which runs through origin (from positive to negative) on a scatterplot - highchart

I am trying to create a reference line that runs through the origin and passes from negative to positive. See an example of what i am trying to achieve - see the threshold line. This threshold line must run through all three x, y coordinates (-1,-45,000), (0.0), (1, 45,000).
enter image description here
Below is my work so far.
http://jsfiddle.net/catio6/rhf6yre5/1/
I've looked at this for reference but have had had no luck after several hours of attempts of replicating this with all three x, y coordinates (-1,-45,000), (0.0), (1, 45,000): http://jsfiddle.net/phpdeveloperrahul/XvjfL/
$(function () {
$('#container').highcharts({
xAxis: {
categories: ['Jan', 'Feb', 'Mar']
},
series: [{
data: [29.9, 71.5, 256]
}]
}, function(chart) { // on complete
console.log("chart = ");
console.log(chart);
//chart.renderer.path(['M', 0, 0, 'L', 100, 100, 200, 50, 300, 100])
chart.renderer.path(['M', 75, 223.5,'L', 259, 47])//M 75 223.5 L 593 223.5
.attr({
'stroke-width': 2,
stroke: 'red'
})
.add();
});
});
So Highcharts doesn't have, as far as I know, a way to define a line that goes from/to infinity.
One idea I had to solve this issue for you is dynamically calculate the values for the line series based on your data. The idea is simple: Given the maximum values for X and Y you want to plot, we just need to limit the axis to a certain value that makes sense and calculate the values for the asymptote series in order to make it seems infinite. My algorithm looks like this:
// Get all your other data in a well formated way
let yourData = [
{x: 0.57, y: 72484},
{x: 0.57, y: 10000}
];
// Find which are the maximum x and y values
let maxX = yourData.reduce((max, v) => max > v.x ? max : v.x, -999999999);
let maxY = yourData.reduce((max, v) => max > v.y ? max : v.y, -999999999);
// Now you will limit you X and Y axis to a value that makes sense due the maximum values
// Here I will limit it to 10K above or lower on Y and 2 above or lower on X
let maxXAxis = maxX + 2;
let minXAxis = - (maxX + 2);
let maxYAxis = maxY + 10000;
let minYAxis = -(maxY + 10000);
// Now you need to calculate the values for the Willingness to pay series
let fn = (x) => 45000 * x; // This is the function that defines the Willingness to pay line
// Calculate the series values
let willingnessSeries = [];
for(let i = Math.floor(minXAxis); i <= Math.ceil(maxXAxis); i++) {
willingnessSeries.push([i, fn(i)]);
}
Here is a working fiddle: http://jsfiddle.net/n5xg1970/
I tested with several values for your data and all of them seem to be working ok.
Hope it helps
Regards

Using forio contour to plot points on a sphere

Can forio contour be used to plot points on a sphere so that the sphere can be rotated and zoomed? Or do I need to do this in d3.js? Or possibly some Juila package? I would like to integrate this into a forio epicenter project and also make it interactive with the underlying data.
I'm not exactly sure what you mean by 'plot points on a sphere', in any case, the 'sphere chart' is not part of the base functionality of Contour, but you can write an extension that does what you want. One important point is that Contour (and d3 in general) has native support for 2d shapes but not 3d shapes, so you'd have to implement projecting the sphere into 2d screen space.
If you can tell me a bit more about what you're trying to do, maybe I can be of more help. In the meantime, here's a simple example of an extension that plots points on a 2d circle (data is angles in this case)
http://jsfiddle.net/tmzsudv5/
Contour.export('round', function (data, layer, options) {
var r = 100;
var theta = 2 * Math.PI / 180;
var centerX = options.chart.width / 2;
var centerY = options.chart.height / 2;
layer.selectAll('circle').data(data[0].data).enter()
.append('circle')
.attr('class', 'dot')
.attr('r', 1)
.attr('cx', function(d, i) { return r * Math.cos(d.y * theta) + centerX; })
.attr('cy', function(d, i) { return r * Math.sin(d.y * theta) + centerY; });
});
var data = _.range(100).map(function(n) { return Math.floor(Math.random() * 360); });
new Contour({
el: '.chart',
})
.round(data)
.render();

URL Link in Tooltip

I have a url link in the tooltip, however, if the tooltip goes outside of the chart area and you try to click on the url, the tooltip disappears.
Any work-arounds for this?
Thanks!
I've found in cases like these, it's best to position the tooltip manually:
http://api.highcharts.com/highcharts#tooltip.positioner
That way, unwanted hiding is controllable.
EDIT:
If you extend the tooltip prototype, you can manipulate the X and Y
Tooltip.prototype.move = function (x, y, anchorX, anchorY) {
var tooltip = this,
now = tooltip.now,
animate = tooltip.options.animation !== false && !tooltip.isHidden;
if(x > ?????)
{
x = x - 50; // or how ever many pixels you want to move it to
}
// get intermediate values for animation
extend(now, {
x: animate ? (2 * now.x + x) / 3 : x,
y: animate ? (now.y + y) / 2 : y,
anchorX: animate ? (2 * now.anchorX + anchorX) / 3 : anchorX,
anchorY: animate ? (now.anchorY + anchorY) / 2 : anchorY
});
// move to the intermediate value
tooltip.label.attr(now);
// run on next tick of the mouse tracker
if (animate && (mathAbs(x - now.x) > 1 || mathAbs(y - now.y) > 1)) {
// never allow two timeouts
clearTimeout(this.tooltipTimeout);
// set the fixed interval ticking for the smooth tooltip
this.tooltipTimeout = setTimeout(function () {
// The interval function may still be running during destroy, so check that the chart is really there before calling.
if (tooltip) {
tooltip.move(x, y, anchorX, anchorY);
}
}, 32);
}
}

Highcharts tooltip always on right side of cursor

I want to show the tooltip on the right side of the cursor.
I looked in the documentation/examples but I can't find a way to force the tooltips to stay on the right side of the cursor.
Can anyone tell me how to do it?
With tooltip positioner I only can set a default position.
Tooltip positioner is much more than just default position. The function arguments contain info about your point position & tooltip dimensions, using which it should be fairly simple to position it to the right.
Highchart/stock allows you to define your alternate positioner as follows
tooltip:{
positioner:function(boxWidth, boxHeight, point){
...
}
}
Note that you have three arguments (boxWidth, boxHeight, point) at your disposal, these seem to be sufficient for most of the use cases to calculate a desired tooltip position. boxWidth and boxHeight are the width and height that your tooltip will require, hence you can use them for edge cases to adjust your tooltip and prevent it from spilling out of the chart or even worse getting clipped.
The default tooltip positioner that comes with highstock is as follows (Source)
/**
* Place the tooltip in a chart without spilling over
* and not covering the point it self.
*/
getPosition: function (boxWidth, boxHeight, point) {
// Set up the variables
var chart = this.chart,
plotLeft = chart.plotLeft,
plotTop = chart.plotTop,
plotWidth = chart.plotWidth,
plotHeight = chart.plotHeight,
distance = pick(this.options.distance, 12), // You can use a number directly here, as you may not be able to use pick, as its an internal highchart function
pointX = point.plotX,
pointY = point.plotY,
x = pointX + plotLeft + (chart.inverted ? distance : -boxWidth - distance),
y = pointY - boxHeight + plotTop + 15, // 15 means the point is 15 pixels up from the bottom of the tooltip
alignedRight;
// It is too far to the left, adjust it
if (x < 7) {
x = plotLeft + pointX + distance;
}
// Test to see if the tooltip is too far to the right,
// if it is, move it back to be inside and then up to not cover the point.
if ((x + boxWidth) > (plotLeft + plotWidth)) {
x -= (x + boxWidth) - (plotLeft + plotWidth);
y = pointY - boxHeight + plotTop - distance;
alignedRight = true;
}
// If it is now above the plot area, align it to the top of the plot area
if (y < plotTop + 5) {
y = plotTop + 5;
// If the tooltip is still covering the point, move it below instead
if (alignedRight && pointY >= y && pointY <= (y + boxHeight)) {
y = pointY + plotTop + distance; // below
}
}
// Now if the tooltip is below the chart, move it up. It's better to cover the
// point than to disappear outside the chart. #834.
if (y + boxHeight > plotTop + plotHeight) {
y = mathMax(plotTop, plotTop + plotHeight - boxHeight - distance); // below
}
return {x: x, y: y};
}
With all the above information, I think you have sufficient tools to implement your requirement by simply modifying the function to make float to right instead of the default left.
I will go ahead and give you the simplest implementation of positioning tooltip to right, you should be able to implement the edge cases based on the aftermentioned default tooltip positioner's code
tooltip: {
positioner: function(boxWidth, boxHeight, point) {
return {x:point.plotX + 20,y:point.plotY};
}
}
Read more # Customizing Highcharts - Tooltip positioning
The better solution to get your tooltip always on the right side of the cursor is the following:
function (labelWidth, labelHeight, point) {
return {
x: point.plotX + labelWidth / 2 + 20,
y: point.plotY + labelHeight / 2
};
}

How to calculate distance between two rectangles? (Context: a game in Lua.)

Given two rectangles with x, y, width, height in pixels and a rotation value in degrees -- how do I calculate the closest distance of their outlines toward each other?
Background: In a game written in Lua I'm randomly generating maps, but want to ensure certain rectangles aren't too close to each other -- this is needed because maps become unsolvable if the rectangles get into certain close-distance position, as a ball needs to pass between them. Speed isn't a huge issue as I don't have many rectangles and the map is just generated once per level. Previous links I found on StackOverflow are this and this
Many thanks in advance!
Not in Lua, a Python code based on M Katz's suggestion:
def rect_distance((x1, y1, x1b, y1b), (x2, y2, x2b, y2b)):
left = x2b < x1
right = x1b < x2
bottom = y2b < y1
top = y1b < y2
if top and left:
return dist((x1, y1b), (x2b, y2))
elif left and bottom:
return dist((x1, y1), (x2b, y2b))
elif bottom and right:
return dist((x1b, y1), (x2, y2b))
elif right and top:
return dist((x1b, y1b), (x2, y2))
elif left:
return x1 - x2b
elif right:
return x2 - x1b
elif bottom:
return y1 - y2b
elif top:
return y2 - y1b
else: # rectangles intersect
return 0.
where
dist is the euclidean distance between points
rect. 1 is formed by points (x1, y1) and (x1b, y1b)
rect. 2 is formed by points (x2, y2) and (x2b, y2b)
Edit: As OK points out, this solution assumes all the rectangles are upright. To make it work for rotated rectangles as the OP asks you'd also have to compute the distance from the corners of each rectangle to the closest side of the other rectangle. But you can avoid doing that computation in most cases if the point is above or below both end points of the line segment, and to the left or right of both line segments (in telephone positions 1, 3, 7, or 9 with respect to the line segment).
Agnius's answer relies on a DistanceBetweenLineSegments() function. Here is a case analysis that does not:
(1) Check if the rects intersect. If so, the distance between them is 0.
(2) If not, think of r2 as the center of a telephone key pad, #5.
(3) r1 may be fully in one of the extreme quadrants (#1, #3, #7, or #9). If so
the distance is the distance from one rect corner to another (e.g., if r1 is
in quadrant #1, the distance is the distance from the lower-right corner of
r1 to the upper-left corner of r2).
(4) Otherwise r1 is to the left, right, above, or below r2 and the distance is
the distance between the relevant sides (e.g., if r1 is above, the distance
is the distance between r1's low y and r2's high y).
Actually there is a fast mathematical solution.
Length(Max((0, 0), Abs(Center - otherCenter) - (Extent + otherExtent)))
Where Center = ((Maximum - Minimum) / 2) + Minimum and Extent = (Maximum - Minimum) / 2.
Basically the code above zero's axis which are overlapping and therefore the distance is always correct.
It's preferable to keep the rectangle in this format as it's preferable in many situations ( a.e. rotations are much easier ).
Pseudo-code:
distance_between_rectangles = some_scary_big_number;
For each edge1 in Rectangle1:
For each edge2 in Rectangle2:
distance = calculate shortest distance between edge1 and edge2
if (distance < distance_between_rectangles)
distance_between_rectangles = distance
There are many algorithms to solve this and Agnius algorithm works fine. However I prefer the below since it seems more intuitive (you can do it on a piece of paper) and they don't rely on finding the smallest distance between lines but rather the distance between a point and a line.
The hard part is implementing the mathematical functions to find the distance between a line and a point, and to find if a point is facing a line. You can solve all this with simple trigonometry though. I have below the methodologies to do this.
For polygons (triangles, rectangles, hexagons, etc.) in arbitrary angles
If polygons overlap, return 0
Draw a line between the centres of the two polygons.
Choose the intersecting edge from each polygon. (Here we reduce the problem)
Find the smallest distance from these two edges. (You could just loop through each 4 points and look for the smallest distance to the edge of the other shape).
These algorithms work as long as any two edges of the shape don't create angles more than 180 degrees. The reason is that if something is above 180 degrees then it means that the some corners are inflated inside, like in a star.
Smallest distance between an edge and a point
If point is not facing the face, then return the smallest of the two distances between the point and the edge cornerns.
Draw a triangle from the three points (edge's points plus the solo point).
We can easily get the distances between the three drawn lines with Pythagorean Theorem.
Get the area of the triangle with Heron's formula.
Calculate the height now with Area = 12⋅base⋅height with base being the edge's length.
Check to see if a point faces an edge
As before you make a triangle from an edge and a point. Now using the Cosine law you can find all the angles with just knowing the edge distances. As long as each angle from the edge to the point is below 90 degrees, the point is facing the edge.
I have an implementation in Python for all this here if you are interested.
This question depends on what kind of distance. Do you want, distance of centers, distance of edges or distance of closest corners?
I assume you mean the last one. If the X and Y values indicate the center of the rectangle then you can find each the corners by applying this trick
//Pseudo code
Vector2 BottomLeftCorner = new Vector2(width / 2, heigth / 2);
BottomLeftCorner = BottomLeftCorner * Matrix.CreateRotation(MathHelper.ToRadians(degrees));
//If LUA has no built in Vector/Matrix calculus search for "rotate Vector" on the web.
//this helps: http://www.kirupa.com/forum/archive/index.php/t-12181.html
BottomLeftCorner += new Vector2(X, Y); //add the origin so that we have to world position.
Do this for all corners of all rectangles, then just loop over all corners and calculate the distance (just abs(v1 - v2)).
I hope this helps you
I just wrote the code for that in n-dimensions. I couldn't find a general solution easily.
// considering a rectangle object that contains two points (min and max)
double distance(const rectangle& a, const rectangle& b) const {
// whatever type you are using for points
point_type closest_point;
for (size_t i = 0; i < b.dimensions(); ++i) {
closest_point[i] = b.min[i] > a.min[i] ? a.max[i] : a.min[i];
}
// use usual euclidian distance here
return distance(a, closest_point);
}
For calculating the distance between a rectangle and a point you can:
double distance(const rectangle& a, const point_type& p) const {
double dist = 0.0;
for (size_t i = 0; i < dimensions(); ++i) {
double di = std::max(std::max(a.min[i] - p[i], p[i] - a.max[i]), 0.0);
dist += di * di;
}
return sqrt(dist);
}
If you want to rotate one of the rectangles, you need to rotate the coordinate system.
If you want to rotate both rectangles, you can rotate the coordinate system for rectangle a. Then we have to change this line:
closest_point[i] = b.min[i] > a.min[i] ? a.max[i] : a.min[i];
because this considers there is only one candidate as the closest vertex in b. You have to change it to check the distance to all vertexes in b. It's always one of the vertexes.
See: https://i.stack.imgur.com/EKJmr.png
My approach to solving the problem:
Combine the two rectangles into one large rectangle
Subtract from the large rectangle the first rectangle and the second
rectangle
What is left after the subtraction is a rectangle between the two
rectangles, the diagonal of this rectangle is the distance between
the two rectangles.
Here is an example in C#
public static double GetRectDistance(this System.Drawing.Rectangle rect1, System.Drawing.Rectangle rect2)
{
if (rect1.IntersectsWith(rect2))
{
return 0;
}
var rectUnion = System.Drawing.Rectangle.Union(rect1, rect2);
rectUnion.Width -= rect1.Width + rect2.Width;
rectUnion.Width = Math.Max(0, rectUnion.Width);
rectUnion.Height -= rect1.Height + rect2.Height;
rectUnion.Height = Math.Max(0, rectUnion.Height);
return rectUnion.Diagonal();
}
public static double Diagonal(this System.Drawing.Rectangle rect)
{
return Math.Sqrt(rect.Height * rect.Height + rect.Width * rect.Width);
}
Please check this for Java, it has the constraint all rectangles are parallel, it returns 0 for all intersecting rectangles:
public static double findClosest(Rectangle rec1, Rectangle rec2) {
double x1, x2, y1, y2;
double w, h;
if (rec1.x > rec2.x) {
x1 = rec2.x; w = rec2.width; x2 = rec1.x;
} else {
x1 = rec1.x; w = rec1.width; x2 = rec2.x;
}
if (rec1.y > rec2.y) {
y1 = rec2.y; h = rec2.height; y2 = rec1.y;
} else {
y1 = rec1.y; h = rec1.height; y2 = rec2.y;
}
double a = Math.max(0, x2 - x1 - w);
double b = Math.max(0, y2 - y1 - h);
return Math.sqrt(a*a+b*b);
}
Another solution, which calculates a number of points on the rectangle and choses the pair with the smallest distance.
Pros: works for all polygons.
Cons: a little bit less accurate and slower.
import numpy as np
import math
POINTS_PER_LINE = 100
# get points on polygon outer lines
# format of polygons: ((x1, y1), (x2, y2), ...)
def get_points_on_polygon(poly, points_per_line=POINTS_PER_LINE):
all_res = []
for i in range(len(poly)):
a = poly[i]
if i == 0:
b = poly[-1]
else:
b = poly[i-1]
res = list(np.linspace(a, b, points_per_line))
all_res += res
return all_res
# compute minimum distance between two polygons
# format of polygons: ((x1, y1), (x2, y2), ...)
def min_poly_distance(poly1, poly2, points_per_line=POINTS_PER_LINE):
poly1_points = get_points_on_polygon(poly1, points_per_line=points_per_line)
poly2_points = get_points_on_polygon(poly2, points_per_line=points_per_line)
distance = min([math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2) for a in poly1_points for b in poly2_points])
# slower
# distance = min([np.linalg.norm(a - b) for a in poly1_points for b in poly2_points])
return distance

Resources