Skip to content

Commit 5849eab

Browse files
authored
Merge pull request #1856 from plotly/log-contour
Log contour
2 parents 9c35a14 + cd5a6f2 commit 5849eab

11 files changed

+109
-7
lines changed

src/traces/contour/find_all_paths.js

+33-7
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ function equalPts(pt1, pt2, xtol, ytol) {
4545
Math.abs(pt1[1] - pt2[1]) < ytol;
4646
}
4747

48+
// distance in index units - uses the 3rd and 4th items in points
4849
function ptDist(pt1, pt2) {
49-
var dx = pt1[0] - pt2[0],
50-
dy = pt1[1] - pt2[1];
50+
var dx = pt1[2] - pt2[2],
51+
dy = pt1[3] - pt2[3];
5152
return Math.sqrt(dx * dx + dy * dy);
5253
}
5354

@@ -114,9 +115,13 @@ function makePath(pi, loc, edgeflag, xtol, ytol) {
114115
ptavg,
115116
thisdist;
116117

117-
// check for points that are too close together (<1/5 the average dist,
118-
// less if less smoothed) and just take the center (or avg of center 2)
119-
// this cuts down on funny behavior when a point is very close to a contour level
118+
/*
119+
* Check for points that are too close together (<1/5 the average dist
120+
* *in grid index units* (important for log axes and nonuniform grids),
121+
* less if less smoothed) and just take the center (or avg of center 2).
122+
* This cuts down on funny behavior when a point is very close to a
123+
* contour level.
124+
*/
120125
for(cnt = 1; cnt < pts.length; cnt++) {
121126
thisdist = ptDist(pts[cnt], pts[cnt - 1]);
122127
totaldist += thisdist;
@@ -174,6 +179,10 @@ function makePath(pi, loc, edgeflag, xtol, ytol) {
174179
}
175180
pts.splice(0, cropstart);
176181

182+
// done with the index parts - remove them so path generation works right
183+
// because it depends on only having [xpx, ypx]
184+
for(cnt = 0; cnt < pts.length; cnt++) pts[cnt].length = 2;
185+
177186
// don't return single-point paths (ie all points were the same
178187
// so they got deleted?)
179188
if(pts.length < 2) return;
@@ -252,6 +261,21 @@ function startStep(mi, edgeflag, loc) {
252261
return [dx, dy];
253262
}
254263

264+
/*
265+
* Find the pixel coordinates of a particular crossing
266+
*
267+
* @param {object} pi: the pathinfo object at this level
268+
* @param {array} loc: the grid index [x, y] of the crossing
269+
* @param {array} step: the direction [dx, dy] we're moving on the grid
270+
*
271+
* @return {array} [xpx, ypx, xi, yi]: the first two are the pixel location,
272+
* the next two are the interpolated grid indices, which we use for
273+
* distance calculations to delete points that are too close together.
274+
* This is important when the grid is nonuniform (and most dramatically when
275+
* we're on log axes and include invalid (0 or negative) values.
276+
* It's crucial to delete these extra two before turning an array of these
277+
* points into a path, because those routines require length-2 points.
278+
*/
255279
function getInterpPx(pi, loc, step) {
256280
var locx = loc[0] + Math.max(step[0], 0),
257281
locy = loc[1] + Math.max(step[1], 0),
@@ -263,11 +287,13 @@ function getInterpPx(pi, loc, step) {
263287
var dx = (pi.level - zxy) / (pi.z[locy][locx + 1] - zxy);
264288

265289
return [xa.c2p((1 - dx) * pi.x[locx] + dx * pi.x[locx + 1], true),
266-
ya.c2p(pi.y[locy], true)];
290+
ya.c2p(pi.y[locy], true),
291+
locx + dx, locy];
267292
}
268293
else {
269294
var dy = (pi.level - zxy) / (pi.z[locy + 1][locx] - zxy);
270295
return [xa.c2p(pi.x[locx], true),
271-
ya.c2p((1 - dy) * pi.y[locy] + dy * pi.y[locy + 1], true)];
296+
ya.c2p((1 - dy) * pi.y[locy] + dy * pi.y[locy + 1], true),
297+
locx, locy + dy];
272298
}
273299
}
Loading
96 Bytes
Loading
-112 Bytes
Loading
20 Bytes
Loading
-352 Bytes
Loading

test/image/baselines/contour_log.png

54.4 KB
Loading
Loading
15 Bytes
Loading
63 Bytes
Loading

test/image/mocks/contour_log.json

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"data": [
3+
{
4+
"x": [0, 1, 2, 3, 10, 30],
5+
"y": [0, 1, 2, 3, 10, 30],
6+
"z": [
7+
[10, 9, 8, 7, 6, 5],
8+
[9, 8, 7, 6, 5, 4],
9+
[8, 7, 6, 5, 4, 3],
10+
[7, 6, 5, 9, 3, 2],
11+
[6, 5, 4, 8, 2, 1],
12+
[5, 4, 3, 2, 1, 0]
13+
],
14+
"contours": {"start": 4, "end": 6.5, "size": 1},
15+
"type": "contour"
16+
},
17+
{
18+
"x": [0, 1, 2, 3, 10, 30],
19+
"y": [0, 1, 2, 3, 10, 30],
20+
"z": [
21+
[10, 9, 8, 7, 6, 5],
22+
[9, 8, 7, 6, 5, 4],
23+
[8, 7, 6, 5, 4, 3],
24+
[7, 6, 5, 9, 3, 2],
25+
[6, 5, 4, 8, 2, 1],
26+
[5, 4, 3, 2, 1, 0]
27+
],
28+
"contours": {"start": 4, "end": 6.5, "size": 1},
29+
"type": "contour",
30+
"showscale": false,
31+
"xaxis": "x2"
32+
},
33+
{
34+
"x": [0, 1, 2, 3, 10, 30],
35+
"y": [0, 1, 2, 3, 10, 30],
36+
"z": [
37+
[10, 9, 8, 7, 6, 5],
38+
[9, 8, 7, 6, 5, 4],
39+
[8, 7, 6, 5, 4, 3],
40+
[7, 6, 5, 9, 3, 2],
41+
[6, 5, 4, 8, 2, 1],
42+
[5, 4, 3, 2, 1, 0]
43+
],
44+
"contours": {"start": 4, "end": 6.5, "size": 1},
45+
"type": "contour",
46+
"showscale": false,
47+
"yaxis": "y2"
48+
},
49+
{
50+
"x": [0, 1, 2, 3, 10, 30],
51+
"y": [0, 1, 2, 3, 10, 30],
52+
"z": [
53+
[10, 9, 8, 7, 6, 5],
54+
[9, 8, 7, 6, 5, 4],
55+
[8, 7, 6, 5, 4, 3],
56+
[7, 6, 5, 9, 3, 2],
57+
[6, 5, 4, 8, 2, 1],
58+
[5, 4, 3, 2, 1, 0]
59+
],
60+
"contours": {"start": 4, "end": 6.5, "size": 1},
61+
"type": "contour",
62+
"showscale": false,
63+
"xaxis": "x2",
64+
"yaxis": "y2"
65+
}
66+
],
67+
"layout": {
68+
"xaxis": {"domain": [0, 0.45]},
69+
"xaxis2": {"domain": [0.55, 1], "type": "log"},
70+
"yaxis": {"domain": [0, 0.45]},
71+
"yaxis2": {"domain": [0.55, 1], "type": "log"},
72+
"margin": {"l": 50, "b": 50, "r": 110, "t": 10},
73+
"width": 500,
74+
"height": 400
75+
}
76+
}

0 commit comments

Comments
 (0)