I have a problem with setting the x and ytics in gnuplot.
I want to create heat maps, and to do it I need specific tics for each "block" in them. I want to create them with loops, so it is much easier to work with them, because for instance I need to make like 60 xtics so I have to write down this:
set xtics ("-0.3" 0, "-0.29" 1, ... "0.3" 60)
It is exhausting and frustrating, so I wanted to make a script like this:
xnumtics = 60
ynumtics = 90
set macros
xticstring = '('
do for [i=0:xnumtics] {
xticstring = xticstring.'"'.(-0.3 + i*0.01).'" '.i.', '
}
xticstring = xticstring.'"'.0.3.'" '.xnumtics.')'
set xtics #xticstring
yticstring = '('
do for [j=0:ynumtics] {
yticstring = yticstring.'"'.(0 - i*0.01).'" '.j.', '
}
yticstring = yticstring.'"'.0.9.'"'.ynumtics.' '
set ytics #yticstring
Unfortunately I get an error: line 21: internal error : STRING operator applied to non-STRING type
line 21 refers for: xticstring = xticstring.'"'.(-0.3 + i*0.01).'" '.i.','
I got this idea from: Can GNUPLOT dynamically prepare index labels?
I am using gnuplot 4.6 ptchlvl 4 on ubuntu 14.04 LTS
Sorry if it is too trivial, I cannot figure it out what is the problem...
Thank you!
The string concatenation operator . can automatically convert only integer numbers, not doubles. You would need to use sprintf or gprintf to convert the (-0.3 + i*0.01) to a string.
However, a shorter way to set the tics would be to use set for ... iterations:
xnumtics = 60
ynumtics = 90
set xtics () # clear all tics
set for [i=0:xnumtics] xtics add (gprintf("%g", -0.3 + i * 0.01) i)
set ytics ()
set for [i=0:ynumtics] ytics add (gprintf("%g", -i * 0.01) i)
Do you really need to manually add the tics? Usually one maps the values from a data file to use gnuplot's usual numerical axes:
plot 'file.dat' using (-0.3 + $1 * 0.01):($2 * -0.01)
Related
To my understanding there should be one empty space between numbers and units.
However, in gnuplot the prefix %c (see help format specifiers) for numbers from 1-999 apparently seems to be ' ' instead of ''.
So, in the example plot below neither the xtic labels nor the ytic labels are all correct.
Either you have some tic labels with zero space or with two spaces, but not all with one. It's a detail and maybe some people won't even notice, but if possible I would prefer to do it the correct way.
Quite some time ago I placed a bug report, but no response so far.
Is there maybe an immediate workaround?
Code:
### wrong prefix for %c 1-999
reset session
set size ratio -1
set logscale xy
set format x "%.0s%cΩ" # no space
set format y "%.0s %cΩ" # one space
set xrange [1e-3:1e12]
set grid x, y
plot x
### end of code
Result:
Addition:
Based on the answer of #maij pointing to the source code, here is a gnuplot attempt to "fix" this, which should be easily transferred to C.
Code:
### gnuplot "fix" for prefix for %c 1-999
prefix(power) = "yzafpnum kMGTPEZY"[(power+24)/3+1 : (power+24)/3 + sgn(abs(power))]
do for [power=-24:24:3] {
print sprintf("% 3g '%s'", power, prefix(power))
}
### end of code
Result:
-24 'y'
-21 'z'
-18 'a'
-15 'f'
-12 'p'
-9 'n'
-6 'u'
-3 'm'
0 '' # zero length
3 'k'
6 'M'
9 'G'
12 'T'
15 'P'
18 'E'
21 'Z'
24 'Y'
It looks like a bug.
This is the workaround I came up it. With this, there is always one space between the number and the units.
You can tell gnuplot where to set each tick mark individually and what each label should be, with set xtics add. The function gprintf can format a number using gnuplot specifiers.
Since we already know what value each tick should have, it's easy to set them with a loop.
# Function to choose the right label format.
f(x) = (x < 1000 && x >= 1) ? gprintf("%.0f Ω", x) : gprintf("%.0s %cΩ", x)
# Loop to set each tick mark and label.
do for [i=-2:12:2] {
set xtics add (f(10**i) 10**i)
set ytics add (f(10**i) 10**i)
}
set size ratio -1
set logscale xy
set xrange [1e-3:1e12]
set grid x, y
plot x
Fix the source code:
Currently I have only source code of the Debian Stretch gnuplot version 5.0.5, linenumbers etc. might be outdated.
The problem is in the function gprintf in util.c around line 868:
power = (power + 24) / 3;
snprintf(dest, remaining_space, temp, "yzafpnum kMGTPEZY"[power]);
Here we see the following:
the letters in yzafpnum kMGTPEZY are the scientific prefixes.
From 1 - 999, power = (0 + 24) / 3 = 8
and yzafpnum kMGTPEZY"[8] is the additional space
I am not a C expert, but as a first attempt, I changed this to
power = (power + 24) / 3;
if (power != 8) {
snprintf(dest, remaining_space, temp, "yzafpnum kMGTPEZY"[power]);
} else {
snprintf(dest, remaining_space, "%s", "");
}
(The gprintf function expects at least a terminating null character to be printed, most probably there are simpler solutions.)
A workaround without recompiling:
What about setting the tic labels manually? But I think you came up with this idea before and don't like it.
I like to store everything I can in a variable since each gnuplot script I make generates tens of plots at once and it makes things easier to track. Here is a sample of one plot (variable of interest: ytics):
# Setup style
set terminal pngcairo dashed
unset key
set style line 1 pointtype 7 pointsize 0.3 linecolor rgb "black"
# Setup the plots' ytics
ytics_H2 = (0,0.002,0.004,0.006,0.008,0.010,0.012);
# Store the range for each variable
min_T = 200; max_T = 1800;
min_H2 = 0; max_H2 = 0.012;
# Plot
set output 'my_output_H2.png'
set ytics ytics_H2
set xrange [min_T :max_T ]
set yrange [min_H2:max_H2]
plot 'scatter.dat' using 1:2 with points linestyle 1
Here is the result:
As you can see, only the last tick gets printed. If I replace the variable ytics by the vector to which it is set to, everything works as expected.
For such use cases gnuplot has macros:
set macros # necessary only for v < 5.0
ytics = "(1, 5, 8)"
set ytics #ytics
plot x
In order to use macros, you must define a string variable which contains the command parts you want to use at a later point, here ytics = "(1, 5, 8)". Later you can use its content with #ytics.
The important fact here is, that gnuplot first replaces #ytics with the content of the string variable ytics, i.e. expands set ytics #ytics to set ytics (1, 5, 5) and only then executes the whole command.
Because your intervals are fixed and the same, you could also use start, incr, end form:
set ytic 0, 0.002, 0.012
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?
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.
You can do like that
mp_setup(bottom_margin, top_margin)=(tmargin=0,bmargin=0,mp_available_height=1.0 -top_margin-bottom_margin,mp_current_height=bottom_margin)
test:
print mp_setup(0.05,0.05)
==> 0.05
As you mentioned, the grouping statement in the function is not supporting yet.
I would like to plot the frequency-domain response of a filter in a similar manner to how the pole-zero plots are on the Wikipedia's "Chebyshev filter" page: http://en.wikipedia.org/wiki/File:Chebyshev_Type_I_Filter_s-Plane_Response_(8th_Order).svg . In particular, what I would like is to cut the plot in half along the Y axis and to make the cut stand out as representing the frequency response.
So far I have managed to get this:
The maked seam can be seen but it doesn't stand out, as if freshly welded. I hope the meaning gets to you because I can't find a better explanation now.
Now, what I have, so far, with wxMaxima's draw3d() function, is this:
draw3d(logx=false,logy=false,logz=true,
enhanced3d=false,line_width=2,color=red,explicit(cabs(Hs(x+%i*y)),x,-0.01,0,y,-3,3),
enhanced3d=[z**.5,x,y,z],palette=gray,proportional_axes=xy,
/* cbrange=[0.05,100.95], */ view=[0,0],yv_grid=101,xu_grid=101,
explicit(cabs(Hs(x+%i*y)),x,-1,0,y,-3,3))$
where Hs(s) is defined earlier, say:
Hs(s):=0.0248655/((s+0.210329)*(s^2+0.12999*s+0.521695)*(s^2+0.340319*s+0.22661))$
I don't know how to make the frequency response stand out, the order of printing doesn't seem to matter. Does anyone know if it can be done and, if so, how?
I don't know how to achieve that with maxima, but here is a solution with gnuplot only. This uses the + pseudo filename to create the 1D-plot for x=0 with splot. Complex numbers are specified with brackets, {x,y}, i.e. i = {0,1}:
set terminal pngcairo size 1000,800
set output 'chebyshev.png'
N = 501
set isosamples N
set samples N
set pm3d interpolate 3,3
set palette gray
set cbrange [*:10]
set xrange [-1:0]
set yrange [-3:3]
set logscale z
set autoscale zfix
set view 120,278
unset key
set grid
Hs(s) = 0.0248655/((s+0.210329)*(s**2+0.12999*s+0.521695)*(s**2+0.340319*s+0.22661))
splot abs(Hs(x+{0,1}*y)) w pm3d, \
'+' using (y = ($0/(N-1.0) * 6 - 3), 0):(y):(abs(Hs({0,1}*y))) w l lw 3
The result with 4.6.3 is:
I'm quite new to gnuplot and I'm using this code;
set xlabel 'x';
set ylabel 'y';
set palette rgbformulae 7,5,15;
set surface;
set cntrparam levels 10;
set isosamples 50;
unset key;
set title 'Magnetic Field Component, By';
splot 'ByF.txt' w l palette title 'By';
My issue is it comes out looking like this;
It looks strange because it's adding contours or lines from y = 0 to y = 2 at z = 0 for all values of x. How do I stop it doing this? I have another plot using a different .txt file, inside these text files is basically this graph but rotated 90 degrees in the x-y plane which DOESN'T give me this weird z = 0 plane of lines. So it must be some setting of the contours which is going wrong.
This is probably due to the fact that the data-file should leave one blank line between each x (or y) scan (called block in gnuplot)