5

I've been trying to use the exam environment to produce nice solutions for an exam. My hope is to have the solution include a figure using tikzpicture and pgfplots and then have text wrapped around the image. I can get it to work using without the solutions environment by using wrapfigure: enter image description here

but once I use the solutions environment, the image is missplaced: enter image description here

Here is the code I've been using:

\documentclass[12pt]{exam}
\usepackage{pgfplots}
\usepackage{wrap fig}
\usepackage{lipsum}
\printanswers

\begin{document}
    \begin{questions}
    \question[10]
    Choose A or B.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{choices}
    \choice some problem
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{solution}

    \begin{wrapfigure}{L}{.5\textwidth}
        \begin{tikzpicture}
            \begin{axis}[
            smooth,
            trig format plots=rad,
            axis lines=middle,
            axis equal]
            \addplot [domain=0:pi, samples=150, red] ({2*sin(5*x)*cos(x)}, {2*sin(5*x)*sin(x)});
            \draw [-stealth, ultra thick, dashed, draw=blue] 
                    (axis cs: 0,0)
                    -- ++(canvas polar cs: radius=3cm,angle=0);
            \draw [-stealth, ultra thick, dashed, draw=blue] 
                (axis cs: 0,0)
                    -- ++(canvas polar cs: radius=4cm,angle=deg{pi/5});
            \end{axis}
        \end{tikzpicture}%
    \end{wrapfigure}
    \lipsum[1-1]
    \end{solution}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \choice some other problem
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{solution}
    another solution
    \end{solution}
    \end{choices}
    \end{questions}
\end{document}

Any tips/suggestions would be greatly appreciated!

EDIT

I should mention that I get the following warning:

Package wrapfig Warning: wrapfigure used inside a conflicting environment on in
put line 17.

  • I get a warning: wrapfigure used inside a conflicting environment on in put line 17 – nidhin Oct 27 '19 at 15:47
  • @nidhin yes thank you! I forgot to include it. I edited the post. – Donnie Nathan Chad Oct 27 '19 at 15:49
3

A conceptually easier approach is to put the text into a minipage and manually break it. \nopar ends a paragraph without making it look like the end of a paragraph.

The advantage is that you can include equations and other non-\baselineskip type fields without messing things up. Just put everything into the minipage until you are ready to place the \nopar.

\documentclass[12pt]{exam}
\usepackage{pgfplots}
\usepackage{wrap fig}
\usepackage{lipsum}
\printanswers

\newsavebox{\mybox}% exam uses box0, possibly others
\newcommand{\nopar}{\strut{\parfillskip=0pt \parskip=0pt \par}}

\begin{document}
    \begin{questions}
    \question[10]
    Choose A or B.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{choices}
    \choice some problem
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{solution}

    \savebox{\mybox}{% measure image
        \begin{tikzpicture}
            \begin{axis}[
            smooth,
            trig format plots=rad,
            axis lines=middle,
            axis equal]
            \addplot [domain=0:pi, samples=150, red] ({2*sin(5*x)*cos(x)}, {2*sin(5*x)*sin(x)});
            \draw [-stealth, ultra thick, dashed, draw=blue] 
                    (axis cs: 0,0)
                    -- ++(canvas polar cs: radius=3cm,angle=0);
            \draw [-stealth, ultra thick, dashed, draw=blue] 
                (axis cs: 0,0)
                    -- ++(canvas polar cs: radius=4cm,angle=deg{pi/5});
            \end{axis}
        \end{tikzpicture}}
    \par\noindent\raisebox{\dimexpr \ht\strutbox-\ht\mybox}{\usebox\mybox}\hfill
    \begin{minipage}[t]{\dimexpr \linewidth-\wd\mybox-\columnsep}
Lorem ipsum dolor sit amet, consectetuer adipiscinvestibulum ut, placerat ac, adipiscing vitae, felis. gravida mauris. Nam arcu libero, nonummy eget, cotate a, magna. Donec vehicula augue eu neque. Pmorbi tristique senectus et netus et malesuada famMauris ut leo. Cras viverra metus rhoncus sem. Nulum urna fringilla ultrices. Phasellus eu tellus sit placerat. Integer sapien est, iaculis in,\nopar
    \end{minipage}
\noindent pretium quPraesent eget sem vel leo ultrices bibendum. Aenedolor nulla, malesuada eu, pulvinar at, mollis ac, ntor semper nulla. Donec varius orci eget risus. Deu, accumsan eleifend, sagittis quis, diam. Duis egdignissim rutrum.

    \end{solution}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \choice some other problem
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{solution}
    another solution
    \end{solution}
    \end{choices}
    \end{questions}
\end{document}
| improve this answer | |
  • Well, you lose TeX's paragraph optimization and have more manual work to get the breaking point just right. Adjusting the insbox solution (or my quick write-up) to wrap for a line more or less is easy (just an optional argument) and so is using a displayed equation. – Skillmon Oct 28 '19 at 23:12
7

You can use the generic code in insbox.tex for this. Note that somehow insbox does fail badly in the solution environment if you add an additional paragraph after the first (because its calculation of how much space is still required fails). For that you can use \restoreinsbox (but only if your paragraph starts after the insertion). I didn't create anything that works when your new paragraph starts amidst the insertion, though.

EDIT: I've added the two macros \restoreinsboxL and \restoreinsboxR, they both take an optional argument. If not given they behave like \restoreinsbox, but if you give them an optional argument it is interpreted as an additional count of lines which should be short. This way you can also restore the effects of \InsertBoxL and \InsertBoxR if the first paragraph is shorter than the inserted box.

\documentclass[12pt]{exam}
\usepackage{pgfplots}
\usepackage{duckuments}
\printanswers
\input{insbox} % this is no LaTeX package, but a generic one

\newcommand*\restoreinsboxL[1][0]
  {%
    \everypar{}%
    \ifnum#1=0
      \parshape=0
    \else
      \ParShape=2
                {#1} {\the\@framewidth} 0pt
                1    0pt                0pt
    \fi
  }
\newcommand*\restoreinsboxR[1][0]
  {%
    \everypar{}%
    \ifnum#1=0
      \parshape=0
    \else
      \ParShape=2
                {#1} 0pt {\the\@framewidth}
                1    0pt 0pt
    \fi
  }
\newcommand*\restoreinsbox
  {%
    \everypar{}%
    \parshape=0
  }

\begin{document}
    \begin{questions}
    \question[10]
    Choose A or B.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{choices}
    \choice some problem
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{solution}

    \InsertBoxL{0}
      {%
        \begin{tikzpicture}
            \begin{axis}[
            smooth,
            trig format plots=rad,
            axis lines=middle,
            axis equal]
            \addplot [domain=0:pi, samples=150, red] ({2*sin(5*x)*cos(x)}, {2*sin(5*x)*sin(x)});
            \draw [-stealth, ultra thick, dashed, draw=blue] 
                    (axis cs: 0,0)
                    -- ++(canvas polar cs: radius=3cm,angle=0);
            \draw [-stealth, ultra thick, dashed, draw=blue] 
                (axis cs: 0,0)
                    -- ++(canvas polar cs: radius=4cm,angle=deg{pi/5});
            \end{axis}
        \end{tikzpicture}%
      }%
    \blindduck[1]
    \par
    \restoreinsbox
    \blindduck[2]
    \end{solution}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \choice some other problem
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{solution}
    another solution
    \end{solution}
    \end{choices}
    \end{questions}
\end{document}

enter image description here

EDIT2: The following defines a pretty primitive draft of another wrap macro implementation. It isn't able to do much and might need a lot of manual adjustments. However it works quite well in the following example.

It defines two macros, both working only on a local scope. The first one is

\wrapcontents[<width>]{<l/r>}[<correction>]{<contents>}[<lines to skip>]

If you specify a <width> argument that width will be used for the box width (and the material will be typeset in vertical mode, similar to a \parbox). With l/r you can chose where to place the contents, on the left or right. <correction> can either be a positive number without a sign, in which case it's the lines which have to be shorter, or a signed integer (+/-), in which case it is added to the automatically calculated number of lines. <contents> is the contents around which should be wrapped, either read as a \vbox or as a \hbox. <lines to skip> is the number of lines the paragraph should be typeset normally before the insertion.

The second macro is

\restorewrap[<lines>]

If you don't specify <lines> the effect of the indentation ends, if you specify a number the effect will be used for the next <lines> number of lines, too.

I don't know why, but you have to use \restorewrap inside the choices environment, this isn't the case in normal text (and I'm too lazy to investigate). But since this implementation does nothing on following paragraphs automatically and only works on a local scope, it doesn't affect the next \choice.

Disclaimer: Some of the code (the output of the insertion) is highly inspired by insbox.tex.

Complete MWE:

\documentclass[12pt]{exam}
\usepackage{pgfplots}
\usepackage{duckuments}
\printanswers

\usepackage{grabbox}

\makeatletter
\newlength\wrapcont@width
\newlength\wrapcont@sep
\newlength\wrapcont@indent
\newlength\wrapcont@hsize
\newcount\wrapcont@lines
\newcount\wrapcont@tempcount
\setlength\wrapcont@sep{5pt}
\newsavebox\wrapcont@box
\newcommand*\wrapcontents[2][]
  {%
    % #1 : width
    % #2 : l/r
    \@ifnextchar[{\wrapcont@a{#1}{#2}}{\wrapcont@a{#1}{#2}[+0]}%
  }
\def\wrapcont@a#1#2[#3]%
  {%
    % #1 : width
    % #2 : l/r
    % #3 : correction
    \if\relax\detokenize{#1}\relax
      \wrapcont@hbox
    \fi
    \wrapcont@vbox{#1}{#2}{#3}%
  }
\def\wrapcont@hbox\fi\wrapcont@vbox#1#2#3%
  {%
    % #1 : width
    % #2 : l/r
    % #3 : correction
    \fi
    \@grabbox{}\wrapcont@box{}\hbox{}{\wrapcont@b{#2}{#3}}%
  }
\newcommand*\wrapcont@vbox[3]
  {%
    % #1 : width
    % #2 : l/r
    % #3 : correction
    \@grabbox{\hsize=#1\relax\linewidth\hsize}\wrapcont@box{}\vbox{}%
      {\wrapcont@b{#2}{#3}}%
  }
\newcommand*\wrapcont@b[2]
  {%
    % #1 : l/r
    % #2 : correction
    \@ifnextchar[{\wrapcont@c{#1}{#2}}{\wrapcont@c{#1}{#2}[0]}%
  }
\newcommand*\wrapcont@parshape{}
\def\wrapcont@c#1#2[#3]%
  {%
    % #1 : l/r
    % #2 : correction
    % #3 : lines skipped
    \wrapcont@width\wd\wrapcont@box\relax
    \advance\wrapcont@width\wrapcont@sep
    \wrapcont@hsize\linewidth
    \advance\wrapcont@hsize-\wrapcont@width
    \ifnum0<0#2\relax
      \wrapcont@lines#2\relax
    \else
      \wrapcont@lines
        \numexpr
          (\ht\wrapcont@box+\dp\wrapcont@box\ifnum#3>0 +\wrapcont@sep\fi+\wrapcont@sep)%
          /\baselineskip#2%
        \relax
    \fi
    \vbox to 0pt
      {%
        \vskip#3\baselineskip
        \ifnum#3>0
          \vskip\wrapcont@sep
        \fi
        \def\@tempa{#1}%
        \def\@tempb{r}%
        \ifx\@tempa\@tempb
          \vtop{\noindent\hbox to\hsize{\hss\usebox\wrapcont@box}}%
        \else
          \def\@tempb{l}%
          \ifx\@tempa\@tempb
          \else
            \GenericError
              {}
              {wrapcontent Error: Unknown alignment '#1', using 'l' as backup.}
              {}{}%
          \fi
          \vtop{\noindent\usebox\wrapcont@box}%
        \fi
        \vss
      }%
    \begingroup
      \def\@tempa{#1}%
      \def\@tempb{r}%
      \ifx\@tempa\@tempb
        \aftergroup\wrapcont@indent\aftergroup\z@
      \else
        \aftergroup\wrapcont@indent\aftergroup\wrapcont@width
      \fi
    \endgroup
    \vglue-\parskip
    \vskip-\baselineskip
    \wrapcont@tempcount0
    \edef\wrapcont@parshape{=\the\numexpr#3+\wrapcont@lines+1\relax\space}%
    \loop\ifnum#3>\wrapcont@tempcount
      \advance\wrapcont@tempcount\@ne
      \edef\wrapcont@parshape
        {\unexpanded\expandafter{\wrapcont@parshape}0pt \the\hsize\space}%
    \repeat
    \wrapcont@tempcount0
    \loop\ifnum\wrapcont@lines>\wrapcont@tempcount
      \advance\wrapcont@tempcount\@ne
      \edef\wrapcont@parshape
        {%
          \unexpanded\expandafter{\wrapcont@parshape}%
          \the\wrapcont@indent\space\the\wrapcont@hsize\space
        }%
    \repeat
    \edef\wrapcont@parshape
      {\unexpanded\expandafter{\wrapcont@parshape}0pt \the\hsize\space}
    \expandafter\parshape\wrapcont@parshape\relax
  }
\newcommand*\restorewrap[1][0]
  {%
    \ifnum0=#1\relax
      \parshape=0
    \else
      \wrapcont@tempcount0
      \edef\wrapcont@parshape{=\the\numexpr#1+1\relax\space}%
      \loop\ifnum#1>\wrapcont@tempcount
        \advance\wrapcont@tempcount\@ne
        \edef\wrapcont@parshape
          {%
            \unexpanded\expandafter{\wrapcont@parshape}%
            \the\wrapcont@indent\space\the\wrapcont@hsize\space
          }%
      \repeat
      \edef\wrapcont@parshape
        {\unexpanded\expandafter{\wrapcont@parshape}0pt \the\hsize\space}%
      \expandafter\parshape\wrapcont@parshape
    \fi
    \relax
  }
\makeatother

\begin{document}
    \begin{questions}
    \question[10]
    Choose A or B.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{choices}
    \choice some problem
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{solution}

    \wrapcontents{l}
      {%
        \begin{tikzpicture}
            \begin{axis}[
            smooth,
            trig format plots=rad,
            axis lines=middle,
            axis equal]
            \addplot [domain=0:pi, samples=150, red] ({2*sin(5*x)*cos(x)}, {2*sin(5*x)*sin(x)});
            \draw [-stealth, ultra thick, dashed, draw=blue] 
                    (axis cs: 0,0)
                    -- ++(canvas polar cs: radius=3cm,angle=0);
            \draw [-stealth, ultra thick, dashed, draw=blue] 
                (axis cs: 0,0)
                    -- ++(canvas polar cs: radius=4cm,angle=deg{pi/5});
            \end{axis}
        \end{tikzpicture}%
      }%
    \blindduck[3]
    \par
    \restorewrap[2]
    \blindduck[2]
    \par
    \restorewrap
    \blindduck[3]
    \end{solution}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \choice some other problem
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \begin{solution}
    another solution
    \end{solution}
    \end{choices}
    \end{questions}
\end{document}

Result:

enter image description here

| improve this answer | |
  • 2
    I was working on this solution too, but there's this problem of the alignment of the following \choices… – Bernard Oct 27 '19 at 17:09
  • @Bernard you're right, I didn't noticed. I'll take a look, but I'm not sure whether it can be solved trivially. – Skillmon Oct 27 '19 at 18:17
  • @Bernard I guess that fixing this will be non-trivial and include some patching. I'll try something else. – Skillmon Oct 27 '19 at 18:31
  • I've already tried . A solution might be to close the choices environment, then re-open it, but it would require some resume function/key for the counter. – Bernard Oct 27 '19 at 18:36
  • @Bernard I'm currently writing a small insbox replacement that require more manual work and shouldn't screw up the alignment of the next paragraphs (only working on a local scope and not resetting the parshape on a new paragraph), but I don't know whether that one will work. And I don't have time left today, will take another look tomorrow. – Skillmon Oct 27 '19 at 18:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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