Logarithmic Axis issue with HighCharts - highcharts

We are comparing multiple series using logarithmic scale. Most of the time the chart looks fine and scales correctly to min/max of the data. In the example below the top series is cut off. The only thing that changes is the data. If we change the time period to any of the other options, it will re-scale correctly, going back to 1Y has the same problem. Is there a way to resolve this issue?
The second question I have is about the logic of the grid lines/labels when in log scale. Shouldn't by default the steps be based on Log(10) for example [0.10%, 1%, 10%, 100%, 1000%]? Is there a config option to set this? In the example below the default [0.10, 0.20, 0.40, 1.00] doesn't make much sense.
This is what the labels/ticks should always look like: jsfiddle.net/TeTMw/1
EDIT:
Here is the highcharts code that looks like is causing this bug. Would be great if you could help fix this issue.
// Second case: We need intermediary ticks. For example
// 1, 2, 4, 6, 8, 10, 20, 40 etc.
} else if (interval >= 0.08) {
var roundedMin = mathFloor(min),
intermediate,
i,
j,
len,
pos,
lastPos,
break2;
if (interval > 0.3) {
intermediate = [1, 2, 4];
} else if (interval > 0.15) { // 0.2 equals five minor ticks per 1, 10, 100 etc
intermediate = [1, 2, 4, 6, 8];
} else { // 0.1 equals ten minor ticks per 1, 10, 100 etc
intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
}
for (i = roundedMin; i < max + 1 && !break2; i++) {
len = intermediate.length;
for (j = 0; j < len && !break2; j++) {
pos = log2lin(lin2log(i) * intermediate[j]);
if (pos > min && lastPos <= max) {
positions.push(lastPos);
}
if (lastPos > max) {
break2 = true;
}
lastPos = pos;
}
}

There's a known issue that log axes may be cut off in Highcharts 1.3.0. This will be fixed with 1.3.1, released later this week. See https://github.com/highslide-software/highcharts.com/issues/1666 .
For the Y axis tick interval, see http://api.highcharts.com/highcharts#yAxis.tickInterval. By default, the tickInterval is null, so the layout of the ticks is determined by tickPixelInterval. In your specific chart for example, if we skipped 0.20 and 0.40, the ticks would become too widespread for the default tickPixelInterval of 72.

Related

Image registration and focus stacking

Background:
I am looking to align images for a focus stacking application using a smartphone. Links to images:
First in stack: 1, Last in stack: 2, Final stacked images: 3
I.e. images are nominally the same, BUT contain:
Systematic change in FOCUS as the focal plane shifts between images
Magnification changes slightly (smartphone feature as focus changes!)
Camera moves slightly due to random vibrations.
Images need to be aligned for the focus-stacking APP to work.
Progress to date:
I use OpenCV's findTransformECC() to get alignment. It works well after some experimentation i.e. see cv2.MOTION_EUCLIDEAN for the warp_mode in ECC image alignment method which was useful to improve the initialization of the Warp matrix:
Images aligned at pixel level
60secs to process 8Mpix image (1sec for 0.5Mpix image) (on 3 year old portable PC with OpenCV release libraries)
See stacked image link above.
I briefly investigated a feature detector (SIFT). It did not align the images well, presumably due to the change in focus between images.
Code:
int scale = 1;
int scaleSmall = 4;
float scaleDiff = scaleSmall / scale;
for (i = 0; i< numImages; i++) {
file = dir + image + to_string(i) + ".jpg";
col[i] = imread(file);
resize(col[i], z[i], Size(col[i].cols/scale, col[i].rows/scale));
cvtColor(z[i], zg[i], CV_BGR2GRAY);
resize(zg[i], zgSmall[i], Size(col[i].cols / scaleSmall, col[i].rows / scaleSmall));
}
// Set a 2x3 or 3x3 warp matrix depending on the motion model.
// See https://www.learnopencv.com/image-alignment-ecc-in-opencv-c-python/
// Define the motion model
const int warp_mode = MOTION_HOMOGRAPHY;
// Initialize the matrix to identity
if (warp_mode == MOTION_HOMOGRAPHY) {
warp_init = Mat::eye(3, 3, CV_32F);
warp_matrix = Mat::eye(3, 3, CV_32F);
warp_matrix_prev = Mat::eye(3, 3, CV_32F);
scaleTX = (Mat_<float>(3, 3) << 1, 1, scaleDiff, 1, 1, scaleDiff, 1 / scaleDiff, 1 / scaleDiff, 1);
}
else {
warp_init = Mat::eye(2, 3, CV_32F);
scaleTX = Mat::eye(2, 3, CV_32F);
warp_matrix = Mat::eye(2, 3, CV_32F);
warp_matrix_prev = Mat::eye(2, 3, CV_32F);
scaleTX = (Mat_<float>(2, 3) << 1, 1, scaleDiff, 1, 1, scaleDiff);
}
// Specify the number of iterations.
int number_of_iterations = 5000;
// Specify the threshold of the increment
// in the correlation coefficient between two iterations
double termination_eps = 1e-8;
// Define termination criteria
TermCriteria criteria(TermCriteria::COUNT + TermCriteria::EPS, number_of_iterations, termination_eps);
for (i = 1; i < numImages; i++) {
// Check images right size
if (zg[0].rows < 10 || zg[1].rows < 10)
return;
// Run the ECC algorithm at start to get an initial guess. The results are stored in warp_matrix.
if (i == 1) {
findTransformECC(zgSmall[0], zgSmall[i], warp_init, warp_mode, criteria );
// See https://stackoverflow.com/questions/45997891/cv2-motion-euclidean-for-the-warp-mode-in-ecc-image-alignment-method
warp_matrix = warp_init * scaleTX;
}
// Warp Matrix from previous iteration is used as initialisation
findTransformECC(zg[0], zg[i], warp_matrix, warp_mode, criteria);
if (warp_mode != MOTION_HOMOGRAPHY) {
warpAffine(zg[i], ag[i], warp_matrix, zg[i].size(), INTER_LINEAR + WARP_INVERSE_MAP);
warpAffine(z[i], acol[i], warp_matrix, zg[i].size(), INTER_LINEAR + WARP_INVERSE_MAP);
}
else {
// Use warpPerspective for Homography
warpPerspective(z[i], acol[i], warp_matrix, z[i].size(), INTER_LINEAR + WARP_INVERSE_MAP);
warpPerspective(zg[i], ag[i], warp_matrix, zg[i].size(), INTER_LINEAR + WARP_INVERSE_MAP);
}
}
}
Question:
Can the image registration speed be significantly improved (using the same hardware)?
there are at least 3 improvements that can be done:
5000 iterations may be unnecessary. Try to limit it to 500. Moreover transforming images to gradient domain may help. See GetGradient function from this tutorial.
You can assume that perspective effects are negligible so you can change warp_mode to MOTION_AFFINE to limit the degrees of freedom from 8 to 6.
You can also try another, much faster approach that is based on phase correlation (frequency domain). In the standard way it only estimates translation between images but you can transfer them to the log-polar space to get translation, rotation and scale invariance. This code implements the third approach.

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

Logarithmic axis not showing appropriate ticks for small numbers

To preface, I am using the extended logarithm functions for negative and small numbers here:
/**
* Custom Axis extension to allow emulation of negative values on a
logarithmic
* Y axis. Note that the scale is not mathematically correct, as a true
* logarithmic axis never reaches or crosses zero.
*/
(function (H) {
// Pass error messages
H.Axis.prototype.allowNegativeLog = true;
// Override conversions
H.Axis.prototype.log2lin = function (num) {
var isNegative = num < 0,
adjustedNum = Math.abs(num),
result;
if (adjustedNum < 10) {
console.log('adjustedNum: ', adjustedNum);
adjustedNum += (10 - adjustedNum) / 10;
}
result = Math.log(adjustedNum) / Math.LN10;
if (adjustedNum < 10) console.log('result: ', result);
return isNegative ? -result : result;
};
H.Axis.prototype.lin2log = function (num) {
var isNegative = num < 0,
absNum = Math.abs(num),
result = Math.pow(10, absNum);
if (result < 10) {
result = (10 * (result - 1)) / (10 - 1);
}
return isNegative ? -result : result;
};
}(Highcharts));
So if I have a y-axis with a dataMin of 0.22 and a dataMax of 2.34 using a log scale, the only ticks I get back are [0,1] designating 0 and 10, the bottom and top of the chart, with no tick marks in between.
1) Is there a way I can specify how many ticks I want in a log chart (tickAmount: 5 would not work)?
2) Is there a way I can tighten the range over which ticks fall? (like in this case, it sets the axis with data values between 0 and 10 even though my data series only falls between 0.22 and 2.34).
Thanks!
1.
tickPositions and tickPositioner options allow you to control where exactly the ticks will fall.
2.
You can try adjusting the tickInterval option: http://jsfiddle.net/BlackLabel/8v3xuyot/
yAxis: {
type: 'logarithmic',
tickInterval: 0.2
}
API references:
https://api.highcharts.com/highcharts/yAxis.tickInterval
https://api.highcharts.com/highcharts/yAxis.tickPositioner
https://api.highcharts.com/highcharts/yAxis.tickPositions

Enforce 0 on axis in HighCharts bubblecharts

I want to enforce that the axis of my bubble chart to starts at 0. In any other chart type I would set
yAxis: {
min:0
}
But this can cause bubbles with an y value near zero to be clipped.
All I could come up with so far is to add an invisible dummy series to force the axis to start at 0.
See http://jsfiddle.net/kzoon/jd3c9/ for my problem and workaround.
Has anyone a better solution to this problem?
How about using tick positioner? It allows you to programmatically set tick positions. Take a look into the docs: http://api.highcharts.com/highcharts#yAxis.tickPositioner
Sample function can work like this:
Find axis min and max values
If min is greater than 0, use 0 as min:
Add ticks every "20" unless we achieve max value
Here you can find the code:
yAxis: {
tickPositioner: function () {
var positions = [],
min = Math.floor(this.min / 10) * 10,
max = Math.ceil(this.max / 10) * 10,
step = 20,
tick;
if (min > 0)
min = 0;
tick = min;
while (tick < max + step) {
positions.push(tick);
tick += step;
}
return positions;
}
},
and working demo on jsfiddle: http://jsfiddle.net/2ABFW/
You can use startWithTick: http://jsfiddle.net/jd3c9/8/
yAxis: {
startWithTick: true
}
Now your y-axis will display the next tick under 0 (-20 in this case) and no bubble will be clipped.

Calculating the position of QR Code alignment patterns

I need to know how to calculate the positions of the QR Code alignment patterns as defined in the table of ISO/IEC 18004:2000 Annex E.
I don't understand how it's calculated. If you take the Version 16, for example, the positions are calculated using {6,26,50,74} and distance between the points are {20,24,24}. Why isn't it {6,28,52,74}, if the distances between the points, {22,24,22}, is distributed more equally?
I would like to know how this can be generated procedurally.
While the specification does provide a table of the alignment, this is a reasonable question (and one I found myself with :-)) - the possibility of generating the positions procedurally has its merits (less typo-prone code, smaller code footprint, knowing pattern/properties of the positions).
I'm happy to report that, yes, a procedure exists (and it is even fairly simple).
The specification itself says most of it:
[The alignment patterns] are spaced as evenly as possible between the Timing Pattern and the opposite side of the symbol, any uneven spacing being accommodated between the timing pattern and the first alignment pattern in the symbol interior.
That is, only the interval between the first and second coordinate may differ from the rest of the intervals. The rest must be equal.
Another important bit is of course that, for the APs to agree with the timing patterns, the intervals must be even.
The remaining tricky bit is just getting the rounding right.
Anyway - here's code printing the alignment position table:
def size_for_version(version):
return 17 + 4 * version
def alignment_coord_list(version):
if version == 1:
return []
divs = 2 + version // 7
size = size_for_version(version)
total_dist = size - 7 - 6
divisor = 2 * (divs - 1)
# Step must be even, for alignment patterns to agree with timing patterns
step = (total_dist + divisor // 2 + 1) // divisor * 2 # Get the rounding right
coords = [6]
for i in range(divs - 2, -1, -1): # divs-2 down to 0, inclusive
coords.append(size - 7 - i * step)
return coords
for version in range(1, 40 + 1): # 1 to 40 inclusive
print("V%d: %s" % (version, alignment_coord_list(version)))
Here's a Python solution which is basically equivalent to the C# solution posted by #jgosar, except that it corrects a deviation from the thonky.com table for version 32 (that other solution reports 110 for the second last position, whereas the linked table says 112):
def get_alignment_positions(version):
positions = []
if version > 1:
n_patterns = version // 7 + 2
first_pos = 6
positions.append(first_pos)
matrix_width = 17 + 4 * version
last_pos = matrix_width - 1 - first_pos
second_last_pos = (
(first_pos + last_pos * (n_patterns - 2) # Interpolate end points to get point
+ (n_patterns - 1) // 2) # Round to nearest int by adding half
# of divisor before division
// (n_patterns - 1) # Floor-divide by number of intervals
# to complete interpolation
) & -2 # Round down to even integer
pos_step = last_pos - second_last_pos
second_pos = last_pos - (n_patterns - 2) * pos_step
positions.extend(range(second_pos, last_pos + 1, pos_step))
return positions
The correction consists of first rounding the second last position (up or down) to the nearest integer and then rounding down to the nearest even integer (instead of directly rounding down to the nearest even integer).
Disclaimer: Like #jgosar, I don't know whether the thonky.com table is correct (I'm not going to buy the spec to find out). I've simply verified (by pasting the table into a suitable wrapper around the above function) that my solution matches that table in its current version.
sorry about my English.
I hope this can help you, and not to later reply.
first things, the standard forget a important thing is that the top left is define with (0,0).
the { 6, 26, 50, 74 } means the alignment points row coordinate and col coordinate, and I don't
know why they do like this, maybe for save space. but we combine all the values for example the:
{ 6, 26, 50, 74 }
and we get :
{ 6 , 6 } ---> ( the x coordinate is 6, and the y is 6, from top/left )
{ 6 , 26 }
{ 6 , 50 }
{ 6 , 74 }
{ 26, 26 }
{ 26, 50 }
{ 26, 74 }
{ 50, 50 }
{ 50, 74 }
{ 74, 74 }
those point's are the actual coordinate of alignment patterns center.
Ps: if a position has the position detection patterns, we ignore output alignment, like the position
(6, 6).
I also have this question before, but now, I solve it, so I hope you can solve it too.
good luck~
There are some comments on the top rated answer that suggest it isn't 100% accurate, so i'm contributing my solution as well.
My solution is written in C#. It should be easy to translate it to a language of your choice.
private static int[] getAlignmentCoords(int version)
{
if (version <= 1)
{
return new int[0];
}
int num = (version / 7) + 2;//number of coordinates to return
int[] result = new int[num];
result[0] = 6;
if (num == 1)
{
return result;
}
result[num - 1] = 4 * version + 10;
if (num == 2)
{
return result;
}
result[num - 2] = 2 * ((result[0] + result[num - 1] * (num - 2)) / ((num - 1) * 2)); //leave these brackets alone, because of integer division they ensure you get a number that's divisible by 2
if (num == 3)
{
return result;
}
int step = result[num - 1] - result[num - 2];
for (int i = num - 3; i > 0; i--)
{
result[i] = result[i + 1] - step;
}
return result;
}
The values i get with it are the same as shown here: http://www.thonky.com/qr-code-tutorial/alignment-pattern-locations/
To sum it up, the first coordinate is always 6.
The last coordinate is always 7 less than the image size. The image size is calculated as 4*version+17, therefore the last coordinate is 4*version+10.
If the coordinates were precisely evenly spaced, the position of one coordinate before the last would be (first_coordinate+(num-2) * last_coordinate)/(num-1), where num is the number of all coordinates.
But the coordinates are not evenly spaced, so this position has to be reduced to an even number.
Each of the remaining coordinates is spaced the same distance from the next one as the last two are from each other.
Disclaimer: I didn't read any of the documentation, i just wrote some code that generates a sequence of numbers that's the same as in the table i linked to.
Starting with #ericsoe's answer, and noting it's incorrect for v36 and v39 (thanks to #Ana's remarks), I've developed a function that returns the correct sequences. Pardon the JavaScript (fairly easy to translate to other languages, though):
function getAlignmentCoordinates(version) {
if (version === 1) {
return [];
}
const intervals = Math.floor(version / 7) + 1;
const distance = 4 * version + 4; // between first and last alignment pattern
const step = Math.ceil(distance / intervals / 2) * 2; // To get the next even number
return [6].concat(Array.from(
{ length: intervals },
(_, index) => distance + 6 - (intervals - 1 - index) * step)
);
}
I don't know if this is a useful question to ask. It just is the way it is, and it doesn't really matter much if it were {22,24,22}. Why are you asking?
My guess it that the spacing should be multiples of 4 modules.
It seems like most answers aren't correct for all versions (especially v32, v36 and v39) and/or are quite convoluted.
Based on #MaxArt's great solution (which produces wrong coordinates for v32), here's a C function which calculates the correct coordinates for all versions:
#include <math.h>
int getAlignmentCoordinates(int version, int *coordinates) {
if (version <= 1) return 0;
int intervals = (version / 7) + 1; // Number of gaps between alignment patterns
int distance = 4 * version + 4; // Distance between first and last alignment pattern
int step = lround((double)distance / (double)intervals); // Round equal spacing to nearest integer
step += step & 0b1; // Round step to next even number
coordinates[0] = 6; // First coordinate is always 6 (can't be calculated with step)
for (int i = 1; i <= intervals; i++) {
coordinates[i] = 6 + distance - step * (intervals - i); // Start right/bottom and go left/up by step*k
}
return intervals+1;
}
The key is to first round the division to the nearest integer (instead of up) and then round it to the next largest even number.
The C program below uses this function to generate the same values as in the table of ISO/IEC 18004:2000 Annex E linked by OP and the (updated) list found on thonky.com:
#include <stdio.h>
void main() {
for (int version = 2; version <= 40; version++) {
int coordinates[7];
int n = getAlignmentCoordinates(version, coordinates);
printf("%d:", version);
for (int i = 0; i < n; i++) {
printf(" %d", coordinates[i]);
}
printf("\n");
}
}

Resources