6
$\begingroup$

I'm trying to export a list of plots into a single PDF file, but I don't know how to make them each take up a page (one page – one plot):

gf = Table[Plot[Sin[a x], {x, -10, 10}], {a, 1, 10}]
Export["gf.pdf", gf]

I found some answers, but they do not allow to achieve what I want, such as merging multiple plots into one figure, importing pdf for merging, or export them one by one.

$\endgroup$
0

4 Answers 4

6
$\begingroup$

Here's the easy way.

We build a Notebook where each Cell contains one plot and has PageBreakBelow->True. If you want the things to fill up the page, use ImageSize->Full.

gf = Table[Plot[Sin[a x], {x, -10, 10}], {a, 1, 10}];
nb = Notebook[
   Table[
    Cell[BoxData[ToBoxes@Show[g, ImageSize -> Full]], "Output", PageBreakBelow -> True],
    {g, gf}
    ]
   ];

Export["~/Desktop/meh.pdf", nb]

enter image description here

If you want them filling up the page height wise, use Rotate, a different ImageSize spec (I hardcoded it, but it's really just the default value for WindowSize minus all of the CellMargins and padding in the PrintingOptions), and AspectRatio->Full:

prepRotatedImage[g_] :=
 Show[
  ReplacePart[g, 1 -> Rotate[g[[1]], \[Pi]/2] ], 
  PlotRange -> Replace[
    PlotRange /. Options[g, PlotRange],
    {x_, y_} :> {y , x}
    ],
  AspectRatio -> Full,
  ImageSize -> {808, 911} - {160, 50}
  ]

gf = Table[Plot[Sin[a x], {x, -10, 10}], {a, 1, 10}];
nb = Notebook[
   Table[
    Cell[BoxData[ToBoxes@prepRotatedImage[g]
      ],
      "Output", PageBreakBelow -> True],
    {g, gf}
    ]
   ];

enter image description here

$\endgroup$
8
  • $\begingroup$ Is there a way to set page sizes so that there is no white space around the plot? $\endgroup$ Jan 22, 2022 at 2:01
  • $\begingroup$ Yeah set ImageSize->... and if you want it centered use CellMargins options $\endgroup$
    – b3m2a1
    Jan 22, 2022 at 2:07
  • $\begingroup$ ImageSize is applied to Graphics, AFAIK. And it usually has different aspect ratio, than the page... $\endgroup$ Jan 22, 2022 at 2:10
  • $\begingroup$ Well yeah you set those options on the Graphics and the others on the Cell $\endgroup$
    – b3m2a1
    Jan 22, 2022 at 2:12
  • $\begingroup$ Can you provide a working example? I mean, produce a PDF where each plot occupies the whole page (keeping the original aspect ratio of the plot)? $\endgroup$ Jan 22, 2022 at 2:14
2
$\begingroup$

I don't know how to make them each take up a page

There might be a way to do this in Mathematica directly. I do not know now. But this is how I would do it. The idea is to just generate the Latex directly, then go to the folder and compile that to pdf. Free Latex compilers are available for windows, Linux and mac.

enter image description here

Here is a link to the generated PDF I just made shown above.

The idea is to first generate each plot to separate pdf file. Give them names 1.pdf, 2.pdf etc... Then write a small Latex code in a loop to read them and put them in separate pdf page centered in middle of the page.

Now you can add a title, and caption and figure number and anything else if you want. Much more flexible this way. To make the image take the full width of the text, change width=0.75\textwidth to width=\textwidth. You can also try width=0.9\pagewidth. One can not eliminate the white space above and below while keeping the same aspect ratio of the image, else it will become distored.

SetDirectory[NotebookDirectory[]]
gf = Table[Plot[Sin[a x], {x, -10, 10}], {a, 1, 10}]
MapIndexed[Export[ToString[First@#2] <> ".pdf", #1] &, gf];
s = "\\documentclass[12pt]{article} 
\\usepackage{graphicx}
\\begin{document}
";
Do[s = s <> "\\null
\\vfill
\\begin{center}
\\includegraphics[width=0.75\\textwidth]{" <> ToString[n] <> ".pdf}
\\end{center}
\\vfill
\\clearpage
"
  , {n, 1, Length[gf]}
  ];
s = s <> "\\end{document}
";
 file = OpenWrite["index.tex", PageWidth -> Infinity];
 WriteString[file, s];
 Close[file]

After you run the above code, there will be file index.tex. Then just do lualatex index.tex or pdflatex index.tex on it from the terminal and you'll get index.pdf generated.

Update to make images fit whole page

It is very easy to do this in Latex. Just change the command which includes graphics to

\includegraphics[width=\textwidth,height=0.98\textheight,keepaspectratio=false]

And you can adjust the page margin also using \usepackage[margin=1pt]{geometry}

Here is the resulting new pdf file

enter image description here

Here is the update Mathematica code (which is the same as before but with the above small change)

SetDirectory[NotebookDirectory[]]
gf=Table[Plot[Sin[a x],{x,-10,10}],{a,1,10}]
MapIndexed[Export[ToString[First@#2]<>".pdf",#1]&,gf];
s="\\documentclass[12pt]{article} 
\\usepackage[margin=1pt]{geometry}
\\usepackage{graphicx}
\\begin{document}
";
Do[s=s<>"\\begin{center}
\\includegraphics[width=\\textwidth,height=0.98\\textheight,keepaspectratio=false]{"<>ToString[n]<>".pdf}
\\end{center}
%
"
,{n,1,Length[gf]}
];
s=s<>"\\end{document}
";
 file=OpenWrite["index.tex",PageWidth->Infinity];
 WriteString[file,s];
 Close[file]

Here is also a link to the above pdf file after compiling the generated latex.

$\endgroup$
9
  • $\begingroup$ Is there a way to set page sizes so that there is no white space around the plot? $\endgroup$ Jan 22, 2022 at 2:02
  • $\begingroup$ @AlexeyPopkov sure. Will update. Without rescaling the image, just need to replace width=0.75\textwidth with width=\textwidth or even width=\pagewidth Then Latex will automatically scale the image to fit the width of the page. width=\textwidth would be a better choice. $\endgroup$
    – Nasser
    Jan 22, 2022 at 2:02
  • $\begingroup$ Thanks. But suppose we have plots of different sizes. Is it possible to set the page sizes according to the plot sizes? $\endgroup$ Jan 22, 2022 at 2:08
  • $\begingroup$ @AlexeyPopkov when adding width=\textwidth the latex will scale the all images to fit page width regardless of the original image size. That will be a better way to do it. You really do not want to change page size itself. Latex scales the image keeping the same aspect ratio with the option width=\textwidth. There are ways to override this by telling it to ignore aspect ratio. And yes, you can change page size if you really want using geometry package. You can do anything you want really in Latex. But the above is the most simple approach. $\endgroup$
    – Nasser
    Jan 22, 2022 at 2:12
  • 1
    $\begingroup$ @AlexeyPopkov OK. I am sure this all can be done in Latex with the use of geometry package and graphicx package. But this will require more advance Latex coding and I think it is going beyond the scope of this answer and is more of a Latex coding. The idea is, if you use Latex to generate the required pdf, then you can do anything you want which Latex allows since we are not using Mathematica other than for generating the images only. $\endgroup$
    – Nasser
    Jan 22, 2022 at 2:33
2
$\begingroup$

Some time ago I had a need to export PDFs with multiple pages each containing only one plot occupying the whole page. I wasn't able to find a way to do this using Mathematica, and was forced to export them one-by-one as PDF, and then to merge produced PDFs into one file using pdfunite from Poppler utils:

gf = Table[Plot[Sin[a x], {x, -10, 10}], {a, 1, 10}]
tempFiles = Table[Export[ToString@StringForm["``.pdf", i], gf[[i]]], {i, 1, Length[gf]}]
command = StringJoin["pdfunite ", 
   Table["\"" <> tempFiles[[i]] <> "\" ", {i, 1, Length[tempFiles]}], "\"Result.pdf\""];
If[Run[command] == 0, DeleteFile @ tempFiles; SystemOpen["Result.pdf"]];

Related:

Also, it is possible to use Poppler installed on Linux running under Windows Subsystem for Linux as I show here.


As an alternative, for merging PDF files one can use the PyMuPdf library for Python as shown here.

First, install PyMuPdf (it requires Python 3.6 or later):

python -m pip install --upgrade pip
python -m pip install --upgrade pymupdf

Define mergePDFs via ExternalFunction:

mergePDFs = ExternalFunction["Python", "import fitz
def merge_pdfs(sources, output):
    result = fitz.open()
    for pdf in sources:
        with fitz.open(pdf) as mfile:
            result.insert_pdf(mfile)
    result.save(output)
    return output"]

It can be used as follows:

SetDirectory[$UserDocumentsDirectory];

mergePDFs[DeleteCases[FileNames["*.pdf"], "result.pdf"], "result.pdf"]
"result.pdf"

It works extremely fast. For example, merging 505 PDF files takes only about 0.7 seconds on my laptop producing a PDF of size 11 MB.

P.S. There is a limitation due to a bug in the current (1.19.4) version of PyMuPdf: it can merge no more than 508 files at one call and cannot merge into one of the source files (fixed in version 1.19.5).


Here is what we get with the above methods:

plots = {Plot[{Sin[x], Sin[2 x], Sin[3 x]}, {x, 0, 2 Pi}, PlotLegends -> "Expressions"],
   Plot[{Sin[x], Sin[2 x], Sin[3 x]}, {x, 0, 10}, PlotLayout -> "Column"],
   Plot[{BesselJ[0, x], BesselJ[1, x], BesselJ[2, x], BesselJ[3, x], BesselJ[4, x], 
     BesselJ[5, x]}, {x, -20, 20}, PlotLayout -> {"Column", UpTo[4]}]};
tempFiles = 
  Table[Export[StringTemplate["~temp~``.pdf"][i], plots[[i]]], {i, 1, Length[plots]}];
If[mergePDFs[tempFiles, "plots.pdf"] === "plots.pdf", DeleteFile@tempFiles; 
  "plots.pdf", $Failed] // SystemOpen

screenshot

$\endgroup$
0
$\begingroup$

You can wrap the images in graphics objects sized to a page each.

For control of margin size set the print options.

The graphics settings below place each plot at the centre of each page.

(*Temporary session page settings*)
SetOptions[$FrontEndSession,
  PrintingOptions -> {
    "PrintingMargins" -> {
      {11(*Left position*), 44(*Right clip*)},
      {32(*Bottom clip*), 25(*Top position*)}},
    "FirstPageHeader" -> False,
    "FirstPageFooter" -> False,
    "RestPagesHeader" -> False,
    "RestPagesFooter" -> False}];

gf = Table[Plot[Sin[a x], {x, -10, 10}], {a, 1, 10}];

x = 700; y = 1080;
pages = ExpressionCell[Graphics[{White, Rectangle[{0, 0}, {x, y}],
       Inset[#, {x/2, y/2}, {Center, Center}, {x, x}]},
      PlotRange -> {{0, x}, {0, y}}, ImageSize -> {x, y}], "Print"] & /@ gf;

nb = CreateDocument[pages, WindowSize -> 860, Visible -> True];

Export["nb.pdf", nb];
NotebookClose[nb]
Print["Exported to " <> FileNameJoin[{Directory[], "nb.pdf"}]]

Also with formatting : exporting nb to pdf without images being cropped?

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.