0

I would like to produce many different figures for my thesis, which should visually look consistent to each other. I.e. I want the graph size (the visible border) of each plot to have the same size. My challenge is that (x/x2/y/y2)tics and labels are sometimes present, sometimes not. A rather crude approach would be to use a fixed canvas size and fixed margins, but this would give undesirably large empty space above and below the plot if x or x2 tics and labels are absent.

I will be using the cairolatex terminal. Is there a possibility to fix the graph size, but to allow autoscaling of the canvas? Some pseudo-code would be:

# desired graph size in cm
graph_width = 10
graph_height = 7
# calculate extra space that is needed for tics and labels
extra_space_bottom = 0
if [xtics = on]
 extra_space_bottom = extra_space_bottom + <space for xtics>
if [xlabel = on]
 extra_space_bottom = extra_space_bottom + <space for xlabel>
# ...
# the same for y, x2, y2, title, colorbox etc.
# now the canvas size will be:
set terminal cairolatex size graph_width+extra_space_left+extra_space_right, graph_height+extra_space_bottom+extra_space_top

Maybe this could be a starting point?

Eldrad
  • 733
  • 3
  • 15
  • ...after the comments/discussion to my answer... in order to avoid misunderstandings.... Do you want to have a **fixed** graph size (visible border) for all graphs, and at the same time a **fixed** canvas size (invisible border), but with **minimal** margins, or would the _canvas_ size be **different** for all plots? – theozh Jul 08 '21 at 12:46
  • @theozh The latter, the canvas size should be different for all plots (it should be automatically adjusted). Usually, the background of a plot is white, and the paper in the LaTeX document is also white, therefore the differing canvas size would be invisible. At the same time, the canvas shouldn't be larger than necessary. – Eldrad Jul 08 '21 at 13:47
  • ok, good, then we have the same understanding. The code in my answer is doing this for `wxt`, or `pdfcairo` terminal. However, I also quickly tried `cairolatex` and as you said, the graph sizes in the LaTeX document were different. I don't know LaTeX very well, but maybe some LaTeX settings might fix this? – theozh Jul 08 '21 at 14:38
  • As far as I see it the "error" is already happening within gnuplot, and not later during the LaTeX compilation. Already the raw pdf (without the tics) has a wrong sized border. – Eldrad Jul 08 '21 at 15:20
  • forgot to mention @theozh – Eldrad Jul 09 '21 at 08:59

3 Answers3

2

Amended answer using \input{figure} rather than generating a standalone figure for inclusion

After looking at the source code and playing with set term tikz plotsize x,y I have concluded that this option was not well thought out and cannot easily be fixed. However there is a different tikz option tightboundingbox that seems to do exactly what you want and requires no source code modification.

My suggestion:

(1) Define a fixed size output in gnuplot's set term command, and define fixed plot borders within that leaving sufficient space in the margins for the most space-consuming labels you expect to handle. This amended answer requires the tikz terminal because we will use the tightboundingbox terminal option

 set term tikz tightboundingbox size 5in, 3in
 set output 'figure_N.tex'
 set lmargin at screen 0.15
 set rmargin at screen 0.85
 set tmargin at screen 0.85
 set bmargin at screen 0.15

(2) Plot your figures and close the output TeX file

 set output 'figure_1.tex'
 plot <whatever>
 set output 'figure_2.tex'
 plot <something else>
 unset output

(3) In your TeX document, do not give it the original size specified in set term. Let it pick up the bounding box as calculated by tikz/pgf. E.g.

\usepackage{gnuplot-lua-tikz}
\usepackage{wrapfig}
\begin{document}

Some text\\

\begin{wrapfigure}{r}{}
\input{figure_1}
\end{wrapfigure}

Some more text\\

\begin{wrapfigure}{r}{}
\input{figure_2}
\end{wrapfigure}

Yet more text\\
\end{document}

enter image description here

Ethan
  • 13,715
  • 2
  • 12
  • 21
  • I see, you create fixed sizes and margins like I wrote in my question, but then cut away the unneeded parts. Unfortunately the `standalone` option is a bad choice for me, as I might be cross-referencing from within the figure to other parts of the document or the bibliography. An `input` solution would therefore be better. Sorry for not stating this explicitly in the question. However, `tikz` is already offering exactly what I want: the option `plotsize` instead of `size`. Alas, it suffers from asymmetric tic lengths as described in the manual. – Eldrad Jul 10 '21 at 18:47
  • I have never used that option so I don't know the details. Maybe you can use the command `set ytics scale ` to fix the asymmetry? – Ethan Jul 11 '21 at 03:43
  • I already considered this option, but this correction factor unfortunately is not a constant, but seems to depend on the overall layout of the figure :-/ So either one would need to look into the actual code that is generating the tics to find out what is happening, or again resort to double plotting… – Eldrad Jul 11 '21 at 09:23
  • I can confirm that the amended version gives correct results! The choice between `tikz` and `cairolatex` is probably an unimportant one, until TeX runs out of memory due to too many tikz figures… But until then it's good to have both alternatives. – Eldrad Jul 13 '21 at 13:20
1

This is a straightforward question, however, I'm not sure if there is a simple way to do it in gnuplot. I thought I've seen a similar question earlier, but I can't find it. At least, gnuplot has the option to set the aspect ratio of a graph, check help size. With this the graph will have the desired aspect ratio and eventually extra wide margins either on the left and right or on top and bottom, depending on the canvas aspect ratio.

The idea of this workaround is the following;

  1. set the aspect ratio of your graph to the desired ratio GraphSizeFixedY/GraphSizeFixedX.
  2. set your canvas to the size GraphSizeFixedX, GraphSizeFixedY, plot the graph and remember the margins (left, right, bottom, top)
  3. set your canvas to the "inverse" aspect ratio GraphSizeFixedY, GraphSizeFixedX, replot and remember the margins
  4. set the canvas to the desired width and height and add the minimum of the remembered corresponding margins and replot again.

Drawback is that you have to plot 3 times. I tried this for wxt and pdfcairo terminal. I hope it will also work for pdflatex terminal. Maybe there is an easier solution which I haven`t thought of.

Code:

### fixed graph size and variable canvas size
reset session

myTerminal = 'wxt'
GraphSizeFixedX = 500
GraphSizeFixedY = 350
Unit = ''

# uncomment these lines if you want to use pdfcairo terminal
# myTerminal = 'pdfcairo'
# GraphSizeFixedX = 10
# GraphSizeFixedY = 7
# Unit = 'cm'

FILE = 'tbSizeGraphFixed.pdf'
set output FILE

set size ratio real(GraphSizeFixedY)/GraphSizeFixedX   # real() to avoid integer division

LMargin(n) = GPVAL_TERM_XMIN
RMargin(n) = GPVAL_TERM_XSIZE/GPVAL_TERM_SCALE+1-GPVAL_TERM_XMAX
BMargin(n) = GPVAL_TERM_YMIN
TMargin(n) = GPVAL_TERM_YSIZE/GPVAL_TERM_SCALE+1-GPVAL_TERM_YMAX

# set canvas ratio
set term @myTerminal size GraphSizeFixedX @Unit, GraphSizeFixedY @Unit

# actual plotting command
set xlabel "x-label"
set ylabel "y-label"
# set x2label "x2-label"    # uncomment for comparison
# set y2label "y2-label"    # uncomment for comparison
plot sin(x)

Lmargin1 = LMargin(0)
Rmargin1 = RMargin(0)
Bmargin1 = BMargin(0)
Tmargin1 = TMargin(0)

# set "inverse" canvas ratio
set term @myTerminal size GraphSizeFixedY @Unit, GraphSizeFixedX @Unit
replot
Lmargin2 = LMargin(0)
Rmargin2 = RMargin(0)
Bmargin2 = BMargin(0)
Tmargin2 = TMargin(0)

min(a,b) = a<b ? a : b
Factor = myTerminal eq "wxt" ? 1: GPVAL_TERM_SCALE    # not completely clear why this is needed

TermSizeVarX = GraphSizeFixedX + \
               real(min(Lmargin1,Lmargin2) + min(Rmargin1,Rmargin2)) / Factor
TermSizeVarY = GraphSizeFixedY + \
               real(min(Bmargin1,Bmargin2) + min(Tmargin1,Tmargin2)) / Factor

set term @myTerminal size TermSizeVarX @Unit, TermSizeVarY @Unit
set output FILE
replot

set output
### end of code

Result: (wxt terminal, graph size 500,350 pixels, background colored just for illustration)

x and y-label only. Canvas size 586 x 418 pixels

enter image description here

x,y,x2, and y2-label. Canvas size 610 x 434 pixels

enter image description here

theozh
  • 22,244
  • 5
  • 28
  • 72
  • I tried your solution for `cairolatex`, but unfortunately I am getting different results. Without any tics/labels the graph size is (10.3×7.1)cm, with x and y (10.7×7.4)cm, with tics on all 4 axis it's (11.0×7.6)cm. Unfortunately I am unsure what the actual numbers of the GPVAL_TERM_ variables mean… is there any explanation to them? The manual is a little bit scarce to this regard. Did you mean this question here: https://stackoverflow.com/questions/19128829/gnuplot-store-plot-area-dimensions-for-later-use – Eldrad Jul 07 '21 at 16:38
  • @Eldrad `cairolatex` is producing a graph without tics, labels and text. Check `help cairolatex`: "The cairolatex terminal prints a plot like terminal epscairo or terminal pdfcairo but transfers the texts to LaTeX instead of including them in the graph." So, How do the graphs look like if you are using them in your LaTeX document? – theozh Jul 07 '21 at 20:07
  • Uh oh, now I discovered even more problems with your proposal. The numbers I wrote in the last comment came from compiling the `standalone` .tex. But if I now look more closely into the tex there are two lines with `\includegraphic`, each with a different size, with a \end{document} between them. A second `\end{document}` is after the second `\includegraphic`. Without the `standalone` option the .tex becomes uncompilable (or better to say un-`\input`-able), unfortunately it's broken. – Eldrad Jul 08 '21 at 09:19
  • Maybe this is due to the fact that the same output file gets overwritten with more than 1 plot command? – Eldrad Jul 08 '21 at 09:25
  • @Eldrad hmm, yes, it probably will put several "graphs" into the outputfile, but that's why I have put another `set output FILE` before the last `replot` command. I assume it will overwrite the file, not append to it, if you `set output FILE` again. So, the final file should only contain one graph. As soon as I find some time I will check it with `cairolatex`. – theozh Jul 08 '21 at 09:35
  • The overwrite issue can be resolved by putting a `unset output` just before the last `set output FILE`. As far as I remember `cairolatex` keeps the output file open until everything is finished. But still, the different sizes of the graph remain... – Eldrad Jul 08 '21 at 09:52
  • Your answer helped me to get the right solution, thanks for that. I think your approach might work as well, if you include the conversion factor from bp to cm. – Eldrad Jul 10 '21 at 19:48
0

Based on the approach of @theozh I found a way to correctly calculate the canvas size. The idea is to let gnuplot automatically handle the margins, measure their size, add them to the total canvas size and replot. Fortunately the size of margins is "constant", i.e. the tic labels and axis labels always take the same amount of space no matter how large the terminal size is.

  1. plot everything with cairolatex with some initial guess for the size
  2. from the internal variables GPVAL_TERM_* read the size of the margins
  3. add the calculated margins to the size and replot.

The same procedure will also work if some of the margins are set by the user.

Note: Not tested for multicolumn key placed outside the graph

### fixed graph size and variable canvas size
reset session

myTerminal = 'cairolatex'
XSize = 10 #cm
YSize = 7 #cm

set term @myTerminal size XSize cm, YSize cm
FILE = 'tbSizeGraphFixed.tex'
set out FILE

# actual plotting command
set xlabel "x-label"
set ylabel "y-label"
plot sin(x)

# cairolatex is calculating the size in bp, convert it to cm.
# _*MIN and _*MAX are the borders of the graph
# _*SIZE is canvas size, scaled by _SCALE
# for whatever reason, _*SIZE is 1bp smaller than the actual canvas, and is scaled by a factor of 20
bp2cm = 0.03528
LSpace = bp2cm * (GPVAL_TERM_XMIN)
RSpace = bp2cm * (GPVAL_TERM_XSIZE/GPVAL_TERM_SCALE -GPVAL_TERM_XMAX +1)
BSpace = bp2cm * (GPVAL_TERM_YMIN)
TSpace = bp2cm * (GPVAL_TERM_YSIZE/GPVAL_TERM_SCALE -GPVAL_TERM_YMAX +1)

unset out
set term myTerminal size (XSize+LSpace+RSpace) cm, (YSize+BSpace+TSpace) cm
set out FILE
replot
unset out

Eldrad
  • 733
  • 3
  • 15
  • Right, that's a simpler approach (one 1 replot). In most cases the margin will be "constant", exceptions might be legends with many entries which might change from single column to multiple column legends depending on the canvas size. By the way, what is the idea to multiply with `1.0`? I don't see the necessity. – theozh Jul 13 '21 at 07:19
  • @theozh Yes, you are right, multicolumn keys might change after rescaling, but I'm not sure whether this will affect the margin. One should keep that in mind. Multiplication with 1.0 changes everything to floats. The GPVAL_TERM_* are all integers, and gnuplot only changes to float division after the first floating point number. On my system, `print 1/2 + 0.1` gives 0.1. Of course, putting bp2cm in front would do the trick as well. – Eldrad Jul 13 '21 at 13:04
  • 1
    Yes, change in (or to) a multicolumn legend will probably only affect the margin if the legend is outside the graph, e.g. `set key out`. And yeah, that's the gnuplot "pitfall" of integer division, but here you don't really need floating point division. It will not make a difference because `GPVAL_TERM_XSIZE/GPVAL_TERM_SCALE` will give an integer anyway. – theozh Jul 13 '21 at 13:27
  • @theozh Usually I don't want integer operations at all, that's why I got the habit of putting a `1.0` no matter what I do, but here on stackexchange it's of course superfluous, I removed it and added a warning concerning your remark. – Eldrad Jul 13 '21 at 16:24