10

I have a full-page figure that needs to be rotated to fit on the page. I started out with this figure in an appendix at the end of my document, and just wrapped the figure in \begin{landscape}...\end{landscape} (from the pdflscape package; I'm using pdflatex) and I was pretty happy with the results. However, I've decided the figure needs to be in the middle of the document, and I'm having trouble reproducing the results there.

The best I've come up with so far is to use the sidewaysfigure environment from the rotating package:

\documentclass{article}
\usepackage{blindtext}

\usepackage{pdflscape}
\usepackage{rotating}

\begin{document}
\blindtext[3]

\begin{sidewaysfigure}
\caption{This figure and its caption are sideways.  Ideally I would also like the pdf page containing it to be rotated so that the figure is upright for on-screen viewing.}
\end{sidewaysfigure}

\blindtext[3]

\begin{figure}
\caption{this figure should be numbered after the other one, come after it in the document, and be oriented normally.}
\end{figure}

\blindtext[2]
\end{document}

This works pretty well, except that I really liked the feature of pdflscape where the PDF page is rotated so that the figure contents and caption are oriented optimally for on-screen viewing, which seems to be missing when using the rotating package.

Things I've tried:

  • using the landscape environment anyway. This gives an immediate page break at the point in the source where the figure occurs.
  • using the landscape environment in an \afterpage{}. This sorta works, except that it's actually moving the figure around, the numbering gets switched with the subsequent figure, which is undesirable.
  • I didn't actually try it, but this solution involving fancyhdr won't work because there are going to be other figure pages (in fact, it's currently looking like this landscape figure is going to be immediately followed by a figure page)
  • I was even desperate and tried using the internal commands (\PLS@AddRotate{90}) that pdflscape uses, but they apply immediately, so the wrong page gets wrotated.

The output from sidewaysfigure is good enough to be getting on with (I think I'm falling into this trap!), but if there are any ways to fix this, I'd very much appreciate it!

This question ends up being very similar to this other one by another user which never received an answer due to not having enough details.

arcticmac
  • 283

2 Answers2

12

This combines sidwaysfigure and pdflscape into one environment. It uses the aux file to locate where the figure actually winds up.

\documentclass{article}
\usepackage{blindtext}% MWE only
\usepackage{graphicx}% for \rotatebox
\usepackage{everypage}
\usepackage{environ}
\usepackage{pdflscape}% not required

\newcounter{abspage}% \thepage not reliab

\makeatletter
\newcommand{\newSFPage}[1]% #1 = \theabspage
  {\global\expandafter\let\csname SFPage@#1\endcsname\null}

\NewEnviron{SidewaysFigure}{\begin{figure}[p]
\protected@write\@auxout{\let\theabspage=\relax}% delays expansion until shipout
  {\string\newSFPage{\theabspage}}%
\ifdim\textwidth=\textheight
  \rotatebox{90}{\parbox[c][\textwidth][c]{\linewidth}{\BODY}}%
\else
  \rotatebox{90}{\parbox[c][\textwidth][c]{\textheight}{\BODY}}%
\fi
\end{figure}}

\AddEverypageHook{% check if sideways figure on this page
  \ifdim\textwidth=\textheight
    \stepcounter{abspage}% already in landscape
  \else
    \@ifundefined{SFPage@\theabspage}{}{\global\pdfpageattr{/Rotate 0}}%
    \stepcounter{abspage}%
    \@ifundefined{SFPage@\theabspage}{}{\global\pdfpageattr{/Rotate 90}}%
  \fi}
\makeatother

\begin{document}
\blindtext[3]

\begin{SidewaysFigure}
\caption{This figure and its caption are sideways.  
Ideally I would also like the pdf page containing it to be rotated so that the figure is upright for on-screen viewing.}
\end{SidewaysFigure}

%\begin{landscape}

\blindtext[3]

\begin{figure}
\caption{this figure should be numbered after the other one, come after it in the document, and be oriented normally.}
\end{figure}

\blindtext[4]
%\end{landscape}
\end{document}
John Kormylo
  • 79,712
  • 3
  • 50
  • 120
  • So basically the difference is that you're implementing something like the sidewaysfigure environment yourself? Or is there some other difference between that and what you're doing? – arcticmac May 03 '16 at 19:14
  • 1
    I never use packages if I can do it myself. I even developed a solution which did not use zref, but decided no one else would be interested. – John Kormylo May 03 '16 at 20:52
  • Fair enough! Though it might be worth editing your answer to make that more clear. My first read through, it sounded like you thought it performed better ("This doesn't force a page break") for some reason and I had to look closely to see that that shouldn't be the case. And actually, I'd potentially be interested in seeing your solution without zref, at least from an academic point of view. – arcticmac May 04 '16 at 16:39
  • 1
    Since I appear to have reinvented sidewaysfigure, I redid my solution as an environment. – John Kormylo May 05 '16 at 16:57
  • This looks interesting, however, when I compile it, it does not turn the caption... – Mil Sep 07 '16 at 16:22
  • @JohnKormylo Yes, I ran it multiple times. The problem is that I also use \usepackage{float} \floatstyle{plain} \restylefloat{figure} for placement of the captions above and below different floats. It doesn't seem to be working together with this. – Mil Sep 08 '16 at 07:29
  • Also, if you have two or more sidewaysfigures it doesn't work (subsequent pages will also be rotated). For example, change the second figure in the MWE to a sidewaysfigure and change the last blindtext to [4]. – Mil Sep 08 '16 at 07:39
  • Wow! When I used \restylefloat{figure} it somehow stopped \rotatebox from running and put both figures on the same page. Anyway, isn't plain the default for figure? – John Kormylo Sep 08 '16 at 14:53
  • Yes. After your last edit, your solution works like a charm – also for tables. Well done! – Mil Sep 08 '16 at 15:23
  • 1
    Thanks! This still works perfectly in 2022. I put your header in landscapefigure.sty and now use \usepackage{landscapefigure} across documents. – Luke Davis Mar 22 '22 at 22:03
1

Based on this answer to another question (suggested by @UlrikeFischer), I hit upon the atbegshi package, which lets you run things when a page is being typeset (in this case, adding the /Rotate 90 command to the PDF page).

I originally tried to make do like this (simplified some things that seemed unnecessary from the original answer, as well as changing it to rotate the page instead of double page width):

\AtBeginShipout{\ifnum\thepage=0\pageref{landscapefigure}
  \pdfpageattr{/Rotate 90}
\fi}

However, that seems to break when including the hyperref package, which I definitely want to use in my real document. So then I went back, and incorporated the \zref stuff from the original answer and wrapped it all up in a nice macro:

\makeatletter
\newcommand{\rotateFigurePageForLabel}[1]{%
  \zlabel{#1}%
  \AtBeginShipout{%
  \ifnum\c@page=\zref@extractdefault{#1}{abspage}{0}
    \pdfpageattr{/Rotate 90}
  \fi}
}
\makeatother

Usage is now something like:

\begin{sidewaysfigure}
  \caption{This figure and its caption are sideways.  So is the page in the PDF.}
  \label{fig:landscapefigure}
  \rotateFigurePageForLabel{fig:landscapefigure}
\end{sidewaysfigure}

(of course, this may be a bit sneaky because it's creating a new \zlabel with the label text you give it, but I was originally hoping to have it just use the regular label. I couldn't figure out a good way to get that to play nice with hyperref though.)

arcticmac
  • 283
  • Well I know why I didn't use pageref: It can't be used reliable as a number in tests. Eg it could be a roman number. – Ulrike Fischer Apr 30 '16 at 07:20
  • 1
    @UlrikeFischer yeah, I have no doubt you know much better than I do what you're doing. And you're absolutely right that \pageref wouldn't really be a good idea. I was just sad to need to use yet another package and a command as long and hard to remember as \zref@extractdefault{#1}{abspage}{0} vs \pageref which is nice and short and easy to remember. (I was also trying to avoid just copying and pasting everything until I understood why it was needed; I'm still not very good at advanced TeX stuff.) – arcticmac May 03 '16 at 19:10
  • @arcticmac I'm trying to accomplish in what you have succeded, but your answer isn't clear enough. Could you please elaborate your answer to full working example? – daniatic Jan 16 '18 at 20:27