openwebwork / pg

Problem rendering engine for WeBWorK
http://webwork.maa.org/wiki/Category:Authors
Other
46 stars 76 forks source link

Cropping from pgfplots is not always working for final SVG output #1023

Open Alex-Jordan opened 7 months ago

Alex-Jordan commented 7 months ago

There may be an issue with the dvisvgm flow for creating an svg from PGlateximage.pl. My server is using dvisvgm version 3.0.3, which is what came with TeXLive 2023. If I run the following problem, the SVG of the image has lots of excess space under the actual image. (The SVG source has width='217.624508pt' height='1907.534988pt', so clearly that height is way off.)

I have built the PDF and PNG from the same source, and there is no issue like this. So it's either the DVI itself or the conversion from DVI to SVG where this excess space is introduced.

The excess space doesn't come out of nowhere either. It's because the domain for the plot starts at 0.01, where the function's output is -100. The excess space down there seems to be about right if you wanted to include (0.01,-100) in the plot. Even though that should be cropped out. You can play with where the plot domain starts, making it further from 0, and eventually the excess space goes away once the start of the plot actually begins at y=-8.

Weird thing: you do not get this behavior if you turn it all upside down. That is, change the ymax to positive 8, and change the function to 1/x, and you will not see this behavior with excess space above the graph. @drgrice1 showed something similar today but there was excess space to the left of the graph. It suggests that maybe part of what's going on has to do with some plotted node with negative coordinates not being properly accounted for when it's time to crop stuff out of the DVI.

DOCUMENT();
loadMacros(qw(PGstandard.pl PGML.pl PGlateximage.pl));

$image_1 = createLaTeXImage();
$image_1->texPackages(["pgfplots"]);
$image_1->BEGIN_LATEX_IMAGE
\begin{tikzpicture}
  \begin{axis}[ymin=-8]
    \addplot[domain=0.01:3] {-1/x};
  \end{axis}
\end{tikzpicture}

END_LATEX_IMAGE

BEGIN_PGML
[!image!]{$image_1}{600}
END_PGML

ENDDOCUMENT();

Note: independent of PG/WeBWorK, I tried to build a DVI and SVG using

\documentclass[12pt]{standalone}
\usepackage[]{xcolor}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
  \begin{axis}[ymin=-8]
    \addplot[domain=0.01:3] {-1/x};
  \end{axis}
\end{tikzpicture}
\end{document}

and the same latex and dvisvgm that WW uses. But I can't reproduce the issue this way (the SVG source does not have absurd height.) I'm not entirely sure the above .tex is what PG builds from though.

somiaj commented 7 months ago

I have ran across this issue with this when testing out my PGplot macro (which uses pgfplots). If I have points outside the range of the axes, those points affect the final size of the image, but are not included in the image causing the blank space as you described.

Though when testing out your problem, I notice the issue only on my 2.18 server, but not on my development server (which the image is generated correctly). Do you notice this same behavior, that this only occurs on 2.18? The two servers have identical versions of texlive and dvisvgm, so unsure why one server has extra space and one server doesn't. I also think I only ever saw the issue when testing my PGplot macro when using it for problems on my 2.18 server and not when testing it with develop.

Alex-Jordan commented 7 months ago

That is interesting because it may help us track down where this is coming from. But for me on my develop server, I still have this issue.

Out of curiosity, when you see this happen, has it always been excess space either below or to the left (not above or to the right?)

somiaj commented 7 months ago

I don't recall exactly where the excess area was, I was more focused on getting a working problem so I had my code limit the domain/codomain to match the axes view to avoid the issue. But I did some more testing, and it does appear the image will always appear in the top right (so bottom left is where the blank area is).

Here is an example that might be easier to play with, you can just move points inside and outside the axes range.

DOCUMENT();
loadMacros(qw(PGstandard.pl PGML.pl PGlateximage.pl));
$refreshCachedImages = 1;

$image = createLaTeXImage();
$image->texPackages(["pgfplots"]);
$image->svgMethod('dvisvgm');
$image->BEGIN_LATEX_IMAGE
\begin{tikzpicture}
  \begin{axis}[ymin=-5,ymax=5,xmin=-5,xmax=5]
    \addplot[] coordinates {(50,-50) (-100,100)};
  \end{axis}
\end{tikzpicture}

END_LATEX_IMAGE

BEGIN_PGML
[!image!]{$image}{600}
END_PGML

ENDDOCUMENT();

For instance if I make points appear off grid in the upper/right, the image is generated correctly. \addplot[] coordinates {(-5,-5) (100,100)};, but if I move the bottom/left out of the axes range, the extra space is created, \addplot[] coordinates {(-50,-50) (100,100)};

I figured out why it was working on my develop server, I was still using the default pdf2svg. Changing this to dvisvgm did create the same issue, so I added $image->svgMethod('dvisvgm') to the problem to ensure the correct method to cause the issue was being used.

somiaj commented 7 months ago

I dug into the code a bit, and forced the .tex file to stick around. Here is the actual tex file that is being used to generate the output:

\documentclass{standalone}
\def\pgfsysdriver{pgfsys-dvisvgm.def}
\usepackage[svgnames]{xcolor}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
  \begin{axis}[ymin=-5,ymax=5,xmin=-5,xmax=5]
    \addplot[] coordinates {(-50,-50) (100,100)};
  \end{axis}
\end{tikzpicture}

\end{document}

The main difference I noticed was the line \def\pgfsysdriver{pgfsys-dvisvgm.def}. With that line I get this issue when manually using latex + dvisvgm to create the image. Removing that line, I no longer see the issue. I don't know exactly what this pgfsys-dvisvgm.def is doing, but something about that driver is causing the issue.

Alex-Jordan commented 7 months ago

When I try locally to latex a tex file with the \def\pgfsysdriver{pgfsys-dvisvgm.def} line, the result is blank. That is, if I open the DVI (and I don't think I have a dvi reader, so it gets auto-converted to PDF) it's just blank. Commenting out that line, it goes back to what it should be.

I found this: https://tex.stackexchange.com/questions/695802/incorrect-tikzpicture-size-when-using-dvisvgm-output-driver-pgf-tikz

But given that I am just getting blank DVIs from local latex execution, I'm not able to try out the solution there.

somiaj commented 7 months ago

@Alex-Jordan I didn't actually look at the .dvi, only the resulting .svg. I too see that with the \def\pgfsysdriver{pgfsys-dvisvgm.def} and viewing the image.dvi with xdvi that I don't see anything (blank image), but I do see the image after conversion to .svg, with incorrect clipping.

drgrice1 commented 7 months ago

The line \def\pgfsysdriver{pgfsys-dvisvgm.def} is what makes it work correctly with dvisvgm. Without that there will be lots of other problems with the generated svg images.

There does seem to be a bug though as @Alex-Jordan's link shows. That was filed as an issue at https://github.com/pgf-tikz/pgf/issues/1275, and a pull request that fixes it was merged. So in future releases of dvisvgm this will be fixed.

drgrice1 commented 7 months ago

If you want to fix this on your system, then change line 130 of /usr/share/texlive/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-dvisvgm.def to \raise-\pgf@ya\hbox{\ifpgf@sys@svg@inpicture\else\special{dvisvgm:bbox \pgf@sys@tonumber\pgf@picmaxx\space\pgf@sys@tonumber\pgf@picmaxy}\special{dvisvgm:bbox lock}\fi\box#1\ifpgf@sys@svg@inpicture\else\special{dvisvgm:bbox unlock}\fi}%. At least that is the file and line number on Ubuntu 22.04.

drgrice1 commented 7 months ago

By the way, you will always see a blank dvi when using the pgfsys-dvisvgm.def pgf system driver. That is because everything is converted to postscript specials that can be correctly dealt with by dvisvgm. Postscript specials don't give output in dvi, but are perfectly valid in a dvi file. The dvi files created with that pgf system driver are not intended to be used directly. They are meant to be processed by dvisvgm.

Alex-Jordan commented 7 months ago

That edit worked on my local system, and now I get an SVG that has proper bounding where I previously did not.

Are you saying the the latest dvisvgm version does not have the correction, but somewhere a develop branch has it? I am wondering if TeXLive 2024 will have it. And wondering if the 2.19 installation/upgrade instructions should suggest installing a particular version of dvisvgm or latex distribution.

somiaj commented 7 months ago

I don't think the fix is in dvisvgm, but in the pgf backend being used by pgfplots. On Debian, the package that controls the file pgfsys-dvisvgm.def that is edited is texlive-pictures, which is part of TeXLive, so the fix should come with newer versions of TeXLive.

Would it be worth adding a comment about this around the configuration to use dvisvgm vs pdf2svg configuration option?

drgrice1 commented 7 months ago

Yes, the fix is actually not in dvisvgm itself, but in the pgfsys-dvisvgm.dev file (which is in the texlive-pictures package on Ubuntu) as @somiaj said.

The fix has been committed to the master branch of https://github.com/pgf-tikz/pgf (which is probably their develop branch).

drgrice1 commented 7 months ago

We could do something similar to what we do for the imagemagick policy file, and that we used to do for the issue with UTF-8 encoding with XMLRPC::Lite. Make a patch that is applied in the docker build, and also add instructions to the webwork 2.19 installation manual as to how to apply that patch.