Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 16721: Analysing why rectangle is not drawn in Cairo graphics #47

Open
hturner opened this issue Aug 14, 2024 · 3 comments
Open

Bug 16721: Analysing why rectangle is not drawn in Cairo graphics #47

hturner opened this issue Aug 14, 2024 · 3 comments
Labels
Graphics Issues related to graphics needs analysis Track down the cause of the bug, or identify as not a bug needs reprex Write a minimal reproducible example that demonstrates the bug SIP 2024 Items reserved for R Dev Day @ SIP 2024

Comments

@hturner
Copy link
Member

hturner commented Aug 14, 2024

As described in Bug 16721, when drawing multiple thin rectangles to create an image, one (or more?) of the rectangles is not drawn, creating a white stripe:

png("ImageWithWhiteStripe.png", width = 330, height = 200, type = "cairo")
image(matrix(1, nrow = 300, ncol = 1))
dev.off()

This only affects cairo raster devices. A hypothesis from @pmur002 is that the width of the rectangles is smaller than a pixel, so if a rectangle lies exactly on the border of two pixels with less than half a pixel on each side, nothing is drawn in those pixels.

This is currently difficult to debug as the white stripe occurs a long way through a loop where the 300 rectangles are drawn. Also it is difficult to relate the rectangles to pixels as the image does not fill the device due to axes etc.

So there are two main things that would be useful here:

  • Simplifying the reprex, e.g. using R functions from {grid}. Trying to pin down when and why the bug occurs by considering different examples.
  • Debugging to find the relevant lines of code and the input arguments at that stage. This will be down in the C code. Is the bug in the R codebase, or is it in cairo_rectangle from the external Cairo graphics library?

Some starter code for the first challenge

library(grid)

# Explore thin rectangles aligned exactly with pixels (or not)
png(width=100, height=100)
grid.rect(x=.01, width=.01, just="left", gp=gpar(col=NA, fill="black"))
dev.off()

# View a small pixel much bigger (with a pixel boundary grid)
img <- readPNG("Rplot001.png")
grid.raster(img, interpolate=FALSE)
grid.segments(0:10/10, 0, 0:10/10, 1)

For the second challenge, print debugging may be helpful

# Print out the sequence of x-values where the rectangles are drawn
static void cairoRectPath(double x0, double y0, double x1, double y1, 
                          pX11Desc xd) 
{
    printf("%f, %f\n", x0, x1);
    cairo_rectangle(xd->cc, x0, y0, x1 - x0, y1 - y0);
}
@hturner hturner added needs reprex Write a minimal reproducible example that demonstrates the bug needs analysis Track down the cause of the bug, or identify as not a bug Graphics Issues related to graphics Hutch 2024 Issues reserved for R Dev Day @ Hutch 2024 labels Aug 14, 2024
@hturner hturner added RSECon24 and removed Hutch 2024 Issues reserved for R Dev Day @ Hutch 2024 labels Aug 22, 2024
@hturner hturner added SIP 2024 Items reserved for R Dev Day @ SIP 2024 and removed RSECon24 labels Sep 27, 2024
@EllaKaye
Copy link

EllaKaye commented Oct 9, 2024

@georgestagg and I have had fun with this!

We believe we understand what is going on, and have suggested a fix. We've written up a long comment on the original bug report. @pmur002, would you mind reviewing/commenting there?

@georgestagg
Copy link

georgestagg commented Nov 5, 2024

When working on graphics, Paul's gdiff package is great for checking to see what (if anything) has visually changed when working on the code. The system is snapshot based: shapshots are taken using a known version of R and a patched version of R, then the snapshots are compared for visual differences.

In the interests of documenting what I did for this bug, something like the following is the procedure that I performed to test the change to the graphics system:

  • Build an unpatched version of R-devel in a separate directory to the one I am working with.
  • Run the unpatched version (I just executed [built]/bin/R) and install the gdiff package: e.g. install.packages('gdiff').
  • setwd() somewhere reasonable to store snapshots, e.g. setwd("[...]/testing/unpatched").
  • Load the gdiff package.
  • Run the examples in a certain package using gdiff, and store snapshots for the graphics generated. EDIT: be sure to set your device! For example, for the "graphics" package run:
gdiffPackage("graphics", device = gdiff::pngDevice(type = "cairo"))
  • Now, rebuild R with your proposed patches in a separate directory.
  • Run the patched version of R. Reinstall the gdiff package if required.
  • setwd() somewhere reasonable (different!) to store the new snapshots, e.g. setwd("[...]/testing/patched").
  • Load the gdiff package.
  • Run the examples in the package again, gdiffPackage("graphics", device = [...]).

Now the fun part. Use gdiff to compare the old output to the new output:

gdiffCompare(controlDir = [...]/testing/unpatched)

Some text output will be shown, giving you a summary of where there are visual changes to the graphics output:

Files that differ [4/385]
--------------------------------------------------------------------------------
../current/Control/pairs-006.png         differs from Test/pairs-006.png (Compare/pairs-006.png.png [2])
../current/Control/pairs.default-006.png differs from Test/pairs.default-006.png (Compare/pairs.default-006.png.png [2])
../current/Control/persp-003.png         differs from Test/persp-003.png (Compare/persp-003.png.png [174])
../current/Control/persp-004.png         differs from Test/persp-004.png (Compare/persp-004.png.png [43])

These files can then be compared by eye, or if they're too close to see the difference you can run a command (if you have the imagemagick package installed) to produce an image consisting of only the differences between the two snapshots:

compare [...]/bezierGrob-001.png [...]/bezierGrob-001.png -compose src diff-bezierGrob-001.png

Which should produce an image like the following, where the red pixes highlight differences:
diff-grid xspline-001

I did the gdiffPackage()/gdiffCompare () procedure several times, collating the text results into a log file via manual copy and paste.

@georgestagg
Copy link

A couple more tips when using gdiff:

  • Run patched an unpatched R in the same context, (e.g. both in a terminal).
  • Ensure that you set the device= argument for the graphics device you're interested in.
  • Ensure the versions of all your packages in both the patched R and unpatched R's libraries match, including dependencies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Graphics Issues related to graphics needs analysis Track down the cause of the bug, or identify as not a bug needs reprex Write a minimal reproducible example that demonstrates the bug SIP 2024 Items reserved for R Dev Day @ SIP 2024
Projects
None yet
Development

No branches or pull requests

3 participants