Search code examples
gnuplot

Gnuplot Function with Multiple Statements


Question

Is it possible to define functions which have multiple statements defined within?

Context

I want to automate some of the calculations involved in creating stacked plots by defining functions. In particular, I was hoping to have something like

mp_setup(bottom_margin, top_margin) = \
    set tmargin 0; \
    set bmargin 0; \
    mp_available_height = 1.0 - top_margin - bottom_margin; \
    mp_current_height = bottom_margin;
mp_plot(plot_height) = \
    mp_plot_size = plot_height * mp_available_height; \
    set origin 0,mp_current_height; \
    set size 1,mp_plot_size; \
    mp_current_height = mp_current_height + mp_plot_size;

with the intended usage being:

...
set multiplot
mp_setup(0.05, 0.05)

mp_plot(1.0/3.0)
plot ...

mp_plot(2.0/3.0)
plot ...

and this should automatically result in the plots being nicely stacked without me having to calculate the origin and size for each graph.

Problem

The way of defining the functions above doesn't work because it seems like the parsing of the function definition ends at the first occurrence of ;; but these semicolons are necessary in order to separate each statement (otherwise, we have set tmargin 0 set bmargin 0... which is invalid).

It also seems like Gnuplot doesn't support any way of grouping statement (like {...} in C/C++); or at least, I have never come across it.

Possible Solution

The only method I know to store multiple functions and evaluate them is using macros:

mp_setup = "<as above>"
mp_plot = "<as above>"

But the issue here is that macros do not allow for arguments to be passed in and instead each variable would have to be declared beforehand as follows:

...
set multiplot
top_margin = 0.05
bottom_margin = 0.05
@mp_setup

plot_height = 1.0/3.0
@mp_plot
plot ...

 plot_height = 2.0/3.0
@mp_plot
plot ...

This solution, although it should work, is not quite as elegant.

Is there no other way of doing this?


Solution

  • No, it isn't possible to define such functions. In gnuplot user-defined functions cannot contain set, unset or other commands. Only those kind of expressions are allowed, which return numerical or string variables. Here, you can have several expressions, separated by comma:

    a = 0
    f(x) = (a = a + 1, a + x)
    print f(1)
    print f(1)
    

    Besides your solution to use macros (@var), I prefer constructing strings inside the function and calling eval:

    set_margin(s, v) = sprintf('set %smargin at screen %f;', s, v)
    set_margins(l, r, b, t) = set_margin('l', l).set_margin('r', r).set_margin('b', b).set_margin('t', t)
    
    eval(set_margins(0.1, 0.95, 0.15, 0.98))
    

    For your specific case of a multiplot layout you can also see Removing blank gap in gnuplot multiplot.