The "record" treatment of binary image data yields incorrect plotting. Since "record" is used (in parallel with other plotting methods) to set the scale, aspect ratio, rotation, and skew of an image, this is a serious problem. "array" input works OK, but for certain size values "record" causes duplicate copies of the output image. This occurs for many output terminals -- I have tested with pngcairo, png, x11, wxt, and pdfcairo. I attach sample output and a datafile that reproduce the problem, along with the script below.
[dhcp-10-227:~/Documents/Projects/jets] zowie% gnuplot
G N U P L O T
Version 5.0 patchlevel 3 last modified 2016-02-21
Copyright (C) 1986-1993, 1998, 2004, 2007-2016
Thomas Williams, Colin Kelley and many others
gnuplot home: http://www.gnuplot.info
faq, bugs, etc: type "help FAQ"
immediate help: type "help" (plot window: hit 'h')
Terminal type set to 'qt'
gnuplot> set terminal pngcairo size 800,800
Terminal type set to 'pngcairo'
Options are ' background "#ffffff" enhanced fontscale 1.0 size 800, 800 '
gnuplot> set output "ok.png"
gnuplot> set title "Array processing (implicit index) is OK"
gnuplot> plot "imdump2.dat" binary array=(200,400) format="%double%double%double" using 3 with image
gnuplot> set output "bad.png"
gnuplot> set title "Record processing (explicit index) is bad"
gnuplot> plot "imdump2.dat" binary record=(200,400) format="%double%double%double" using 1:2:3 with image
gnuplot> set output "x.png"
gnuplot> set title "X index is as expected"
gnuplot> plot "imdump2.dat" binary array=(200,400) format="%double%double%double" using 1 with image
gnuplot>
(note that the X and Y fields in the attached binary file simply echo the index value of each pixel, so the "ok.png" and "bad.png" should produce exactly the same output).
I have fixed the problem. The following patch fixes it. The problem was that the "record" specifier was causing (e.g.) a 200x400 array to be read as if it were a 400x200 array. This would not be a problem if each pixel were being individually read and parsed by the "with image" code, since each pixel would then be individually placed. But "with image" uses a shortcut of calculating a single Jacobian matrix for the transform (assuming the image-coord -> pixel-coord transformation is linear). That yielded strange duplicates and skewed copies of the image.
*** datafile.c.old Wed Nov 2 14:20:41 2016
--- datafile.c Wed Nov 2 14:21:02 2016
*** 3535,3542 ****
df_matrix_file = FALSE;
plot_option_array();
set_record = TRUE;
! df_xpixels = df_bin_record[df_num_bin_records - 1].cart_dim[1];
! df_ypixels = df_bin_record[df_num_bin_records - 1].cart_dim[0];
FPRINTF((stderr,"datafile.c:%d record dimensions %d x %d\n", LINE,
df_xpixels, df_ypixels));
continue;
--- 3535,3542 ----
df_matrix_file = FALSE;
plot_option_array();
set_record = TRUE;
! df_xpixels = df_bin_record[df_num_bin_records - 1].cart_dim[0];
! df_ypixels = df_bin_record[df_num_bin_records - 1].cart_dim[1];
FPRINTF((stderr,"datafile.c:%d record dimensions %d x %d\n", LINE,
df_xpixels, df_ypixels));
continue;
The following patch fixes this problem. It is due to an incorrect assignment of xpixels and ypixels sizes in the binary matrix read code: an NxM matrix is read as if it were an MxN matrix, but ONLY with the “record” specifier. The “array” specifier had the correct order.
3538,3539c3538,3539
< df_xpixels = df_bin_record[df_num_bin_records - 1].cart_dim[1];
< df_ypixels = df_bin_record[df_num_bin_records - 1].cart_dim[0];
Related
Bugs:
#1873I hate the binary file handling code.
I'll apply your patch because it's obvious that the two adjacent code sections handling "record=(a,b)" and "array=(a,b)" disagree with each other about the interpretation of a and b.
On the other hand I'm at a loss to explain why the "record=(a,b)" variant even cares what a and b are. The whole point of this mode (at least according to the docs) is that the file itself contains x and y coordinates, and that should be definitive. And indeed if you simply leave out the record keyword altogether it seems to work fine other than issuing a warning. WIth plot styles other than "image" it doesn't even issue the warning. So I'm wondering why/when the "record" keyword is needed in the first place? Do you know?
Thanks!
The issue is that the relative locations of the points in the record array matter for some plot styles. In “with points” plots, it really doesn’t matter — the points get plotted in a different order if you get the matrix shape wrong, but they look the same in the end. But “with lines” in 3-D plots a grid connecting the data points, so getting the order wrong would give you a few stray lines here and there.
The image plotting methods are, I think, the only 2-D ones where the shape matters. What’s going on is that the image plotting code doesn’t just place pixels in random locations — for speed it assumes they’re supposed to be a uniform grid in data space. The code looks at the coordinates of the origin, the lower-right point, and the upper-left point, and uses that to create a linear transformation converting between pixel location in the matrix and dataspace location to be rendered. Then the rest of the rendering code treats the record matrix as some kind of implicit array matrix: it ignores the ordinate values and calculates them using that linear transformation.
That’s a useful hack, even though it means you can’t input an arbitrarily-distorted image: most of the time linear transformations are enough; and truly arbitrary distortions are something like 1,000 times slower. (I spent a long time implementing arbitrary resampling for PDL — it’s a bear to get right). (For fully arbitrary image distortions with Gnuplot one currently has to go to a 3-D plot with the viewpoint looking down from above.)
All the best,
Craig
Related
Bugs:
#1873More thoughts:
plot foo binary format="%double%double%double" using 1:2:3 with points pt 5 lc palette z
In the current case however, the coordinates do describe a regular grid. So here the image code could look at the actual coordinate values to decide what the grid dimensions are.
Non-linear image distortions are now handled fairly easily, so long as you can describe the distortion by an invertable equation. See the demos for the recently added nonlinear scaling code. The nonlinear mappings work in either 2D or 3D.
http://skuld.bmsc.washington.edu/people/merritt/gnuplot/nonlinear3.html
Last edit: Ethan Merritt 2016-11-03
Very cool!
How do you implement the distortion onto the output pixel grid? Are you using the inverse transform to sample the input image? Or are you doing some sort of spatial filtering? If the former, I can offer some code I wrote for PDL, to carry out the resample. It’s a bit expensive — it calculates the discrete Jacobian at every point and uses that to generat a spatially variable input filter - but it yields photometric/scientific quality output.
Best,
Craig
Related
Bugs:
#1873There is no sampling involved. The coordinate system itself is mapped through an arbitrary pair of functions f(x) and g(y). So each pixel (x,y) is printed at output coordinate (f(x),g(y)) The inverse functions are needed so that you can recover the orginal coordinates from the position in the output image. This works for all plot types, not just image plots. Depending on the purpose of the whole exercise, you might want to label the axes in the orginal coordinate system or the transformed one.
I’ll have a look at it, thanks! Sounds very, very useful.
Related
Bugs:
#1873This was incorporated by Ethan some time ago but the fix has not survived into the current v5.0.6. The problem is the final brackets of (now) lines 3547 and 3548 of datafile.c: the cart_dim[1] and cart_dim[0] are transposed, causing trouble with non-square reads of record files in which the independent values are passed in as arrays (rather than implicit).
Weird. All I can do at this point is to apply it again. Sorry.
No worries! Just reporting it as I see it.
Thanks for keeping on top of this stuff — I use gnuplot every single day, and it is a real boon.
All the best,
Craig
Related
Bugs:
#1873