How do I draw a set of vertical lines in gnuplot? - gnuplot

E.g. if I have a graph and want to add vertical lines at every 10 units along the X-axis.

From the Gnuplot documentation. To draw a vertical line from the bottom to the top of the graph at x=3, use:
set arrow from 3, graph 0 to 3, graph 1 nohead

Here is a snippet from my perl script to do this:
print OUTPUT "set arrow from $x1,$y1 to $x1,$y2 nohead lc rgb \'red\'\n";
As you might guess from above, it's actually drawn as a "headless" arrow.

alternatively you can also do this:
p '< echo "x y"' w impulse
x and y are the coordinates of the point to which you draw a vertical bar

You can use the grid feature for the second unused axis x2, which is the most natural way of drawing a set of regular spaced lines.
set grid x2tics
set x2tics 10 format "" scale 0
In general, the grid is drawn at the same position as the tics on the axis. In case the position of the lines does not correspond to the tics position, gnuplot provides an additional set of tics, called x2tics. format "" and scale 0 hides the x2tics so you only see the grid lines.
You can style the lines as usual with linewith, linecolor.

To elaborate on previous answers about the "every x units" part, here is what I came up with:
# Draw 5 vertical lines
n = 5
# ... evenly spaced between x0 and x1
x0 = 1.0
x1 = 2.0
dx = (x1-x0)/(n-1.0)
# ... each line going from y0 to y1
y0 = 0
y1 = 10
do for [i = 0:n-1] {
x = x0 + i*dx
set arrow from x,y0 to x,y1 nohead linecolor "blue" # add other styling options if needed
}

Related

How can I make a filled region in the x direction in gnuplot?

I know that gnuplot has the great type of plot that is filledcurve, which you can make a filled region between two curves that are presented like 1:2:3, it will make a curve between columns $2 and $3 for the same x value $1. But how can I fill this region in the graph below in gnuplot? The range is in x direction like x1:x2:y, same value of y.
My data it's in form like:
# rho1 rho2 C
0.8022651311239721 0.8299444680667378 0.00005011872336272725
0.8022624676512962 0.8299464715046031 0.00004466835921509635
0.8022618998639025 0.8299490455369624 0.000039810717055349695
0.8022533810411624 0.8299390462160209 0.000035481338923357534
...
But I can separate that in two archives too.
Here is a useful trick that uses the 3D plotting style with zerror and then sets the view angle so that it looks like a 2D x/y plot. I don't have enough of your data to replicate the plot you show so I use a junk data file just for the purpose of showing how the plot works:
# 3D plot style "with zerror" takes 5 columns of input
# x y z zlow zhigh
# We will choose a view angle such that "z/zlow/zhigh" is the horizontal axis
# "x" is the vertical axis
# "y" is unused because it is along the line of sight
# For your data as described
rho1 = 1 # column 1
rho2 = 2 # column 2
c = 3 # nominal y value, we use it for X
junk = 0 # unused constant coordinate
rhomean(c) = (column(rho1) + column(rho2)) / 2.
set view 270, 0
set view azimuth -90
unset ytics
set zlabel "ρ" # horizontal axis in this projection
set xlabel "C" # vertical axis in this projection
set zrange [0:50] # Note how this affects the horizontal axis!
splot "data" using c:(junk):(rhomean(c)):rho1:rho2 with zerror lt black fc "gold"
The with zerror plot style and the set view azimuth command both require a reasonbly current version of gnuplot.

How to use nonlinear axes in Gnuplot?

I saw some examples like this one:
f(x) = log10(x)
g(x) = 10**x
set nonlinear x via f(x) inverse g(x)
So this one is equivalent to just log-scaling the x.
But I don’t get why we need to write the inverse function?
And also I have this situation:
For data in x>=0 range I need to scale x in a way that it shows in an almost-half plot;
For data in -100<=x<0 I need to scale x in a way that it shows in a small part of plot;
For data in x<-100 I need to scale x in a way as for data in x>=0.
So let’s imagine we have an a4paper and gnuplot creates his plots on it. I want to have a plot result that will be drawn in an x scales like:
If x>=0 1cm = 5
If -100<=x<0 1cm = 100
If x<-100 1cm = 5
(I don’t mean it’s important to me to have only this centimeters, it just says that I need a correlation between delta of two x values and real length between them.)
I’m so sorry I can’t understand this mechanics of scaling.
The forward function tells gnuplot where to draw user coordinate [x,y] on the page. Call that location [x',y']. Only the forward function is needed for this. But the interactive terminals echo back mouse position and allow you to click on the plot for various purposes. In order to know what a mouse click on [x',y'] means, the program has to convert it back to the original [x,y]. For that it needs the inverse function.
For an example of using different scaling functions over different portions of the full plot, see the online demo nonlinear1.dem reproduced below
# This example shows how a nonlinear axis definition can be used to
# create a "broken axis". X coordinates 0-100 are at the left,
# X coordinates 500-1000 are at the right, there is a small gap between them.
# So long as no data points with (100 < x < 500) are plotted, this works as expected.
#
# f(x) maps x axis (discontinuous) to shadow axis coords (continuous linear range [0:1000])
# g(x) maps shadow axis coords to x axis readout
#
set title "A 'broken' x axis can be defined using 'set nonlinear x'"
# Define the broken-axis mapping
axis_gap = 25.
f(x) = (x <= 100) ? x : (x < 500) ? NaN : (x - 400 + axis_gap)
g(x) = (x <= 100) ? x : (x < 100 + axis_gap) ? NaN : (x + 400 - axis_gap)
set xrange [15:600] noextend
set nonlinear x via f(x) inverse g(x)
set xtics 50.
set xtics rotate by -90 nomirror
set ytics nomirror
set border 3
unset key
# Creation of the broken axis marks (this should be automated)
set arrow 500 from 100, graph 0 to 500, graph 0 nohead lt 500 lw 2 lc bgnd front
set arrow 501 from 100, graph 0 length graph .01 angle 75 nohead lw 2 front
set arrow 502 from 100, graph 0 length graph -.01 angle 75 nohead lw 2 front
set arrow 503 from 500, graph 0 length graph .01 angle 75 nohead lw 2 front
set arrow 504 from 500, graph 0 length graph -.01 angle 75 nohead lw 2 front
plot 'silver.dat' with yerrorbars lw 2, '' with lines

Setting a unique legend in a multiplot

I would like to have a unique legend preferably at the bottom of a multiplot. I have tried with set key at screen 0,5, screen 0.1 however it is not ideal as you can see. It is very close to the X labels and values. How can I push it a bit further down the graph?
What are my options?
My multiplot is created with
set multiplot layout 2,2 rowsfirst offset 0, 0.001
set key at screen 0.58, screen 0.06
Any other ideas?
An alternative approach would be perhaps to specify the outer margins of the entire multiplot as well as the spacing between individual plots. Like this, one could reserve enough space in the (global) bottom margin for the legend:
set multiplot layout 2,2 rowsfirst \
margins char 8,char 2,char 8,char 2 \
spacing char 8,char 4
set key at screen 0.5, char 6
plot x w l t 'x', x*x w l t 'x*x'
plot x w l t ''
plot x w l t ''
plot x w l t ''
This example would produce:

Gradient colored polar curve

I'm trying to do the following in gnuplot: color with gradient an ellipse. Each point of the
ellipse has its z-value given by the function
charge_density(t,beta) = -sin(t)*beta*(sqrt(1-(beta**2)))/(1-((sin(t)*beta)**2))
The radius function of the ellipse is given by a similar function:
radius(t,beta) = sqrt(1-(beta**2))/sqrt(1-((sin(t)*beta)**2))
Where beta is just a parameter satisfying 0<beta<1, and t is the angle.
Well, I tried to use the "+" special file with the lc rgb variable option, but it doesn't work with polar coordinates.
I also tried the set mapping cylindrical, but nothing happened.
Is this possible only with cartesian coordinates? In this case, I'll have to do 2 graphics and modify the above functions...
Or will I have to create a data file with angle, radius, z data?
I'd like to do this with pm3d and the following palette:
set palette model RGB defined (-1 "blue", 0 "black", 1 "red")
here is the code:
beta =0.5
charge_density(t,beta) = -sin(t)*beta*(sqrt(1-(sin(t)*beta)**2))/(1-((sin(t)*beta)**2))
radius(t,beta) = sin(t*beta) # your function equals 1!
# convert polar to carthesian
r_x(t)=radius(t,beta)*cos(t)
r_y(t)=radius(t,beta)*sin(t)
set palette model RGB defined (-1 "blue", 0 "black", 1 "red")
set size ratio -1 # same unit length in x and y
# number of sample points.
# increase if curve has edges
set samples 100
#decouple range of "+" and xrange
set parametric
plot [0:3*pi] "+" u (r_x($1)):(r_y($1)):(charge_density($1,beta))\
with lines linewidth 3 linecolor palette
and there the result:
NOTE: Your radius equals to 1, so I took another function. Also, your charge_density has one extra closing parenthesis.
Some comments:
if you plot with lc rgb variable, a 24bit RGB color value is expected:
(red*256^2 + green*256 + blue) with red, green, blue = 0...255
If you want gnuplot to use the color according to the palette, write lc palette
gnuplot 4.6 does not support "+" for polar. Also, the mapping sets the behavior for 3D plots. However, as your formula calculates a radius for an angle, you can easily transform this to carthesian coordinates and plot these. There is still one drawback: The range given in the plot sets the xrange, too. This also means that the "length" of your curve changes when you change the xrange. You can solve this by set parametric which causes gnuplot to use a dedicated variable u instead of x when plotting functions. It is nice (and helps you) that this affects the special file "+", too. I do not know if this is a (positive) bug or a feature.

GNUPlot: Animating Labels

My problem, following from my previous question, goes like this now: I have a particle moving in a plane, and now I want a sort of box at the side which says the particle's position in XY and its velocity. I tried using labels, but they end up overlapping each other.
Here's a really crude "sketch" of what I want to see:
+------------------------------------------+
| +-----------+ |
| | | t = 2 |
| | PLOT HERE | x = 0 y = 1 |
| | | vx = 2 vy = 3 |
| +-----------+ |
+------------------------------------------+
where those numbers would be changing at each frame. I've been able to animate a title, but a label seems different.
My current code looks very much like the answer in here GNUPlot - Plot 2D datapoints as MPEG but with some minor stylistic modifications, and that I removed the title. I can produce data that are just the XY coordinates, which is what I use right now.
I can also produce something like (these are random points, just for the sake of illustration)
#X Y t vx vy
0.00 1.00 0.0 0.0 6.28
0.01 0.01 0.01 1.0 6.00
for the animating labels.
A nice way for placing labels from a data file is with the labels plotting style. However, there are some difficulties for placing labels outside of the actual plotting area, since these points and labels usually are clipped.
Since you are using stats anyway to fix the x- and yrange, here is how I would do this:
Set a fixed right margin with e.g. set rmargin 20. This uses a right margin of 20 character widths. You could also use absolute coordinates like set rmargin at screen 0.8, but since you need the margin to place labels, character units seem appropriate.
Use the upper right corner of your plot area as reference point (STATS_max_x, STATS_max_y) and shift the labels using the offset parameter and shifting again by some character widths.
So, a complete script might look as follows:
# calculate the number of points
stats 'file.txt' using 1:2 nooutput
# if you want to have a fixed range for all plots
set xrange [STATS_min_x:STATS_max_x]
set yrange [STATS_min_y:STATS_max_y]
set terminal pngcairo size 800,400
outtmpl = 'output%07d.png'
v_label(x, y) = sprintf('vx = %.2f vy = %.2f', x, y)
c_label(x, y) = sprintf('x = %d y = %d', x, y)
t_label(t) = sprintf('t = %.2f', t)
set rmargin 20
do for [i=0:STATS_records-1] {
set output sprintf(outtmpl, i)
plot 'file.txt' every ::::i with lines title sprintf('n = %d', i),\
'' every ::i::i using (STATS_max_x):(STATS_max_y):(t_label($3)) with labels offset char 11,-5 notitle,\
'' every ::i::i using (STATS_max_x):(STATS_max_y):(c_label($1, $2)) with labels offset char 11,-6.5 notitle,\
'' every ::i::i using (STATS_max_x):(STATS_max_y):(v_label($4, $5)) with labels offset char 11,-8 notitle
}
set output
Note, that the rmargin and offset settings depend on the terminal, terminal size, font and font size. For nicer labels placement you might consider placing the vx and vy labels separately and maybe changing their alignment.
Alternatively, in each iteration you can extract the current line from your data file and set the labels manually. This however requires you to use an external tool to extract the line:
do for [i=0:STATS_records-1] {
line = system(sprintf("sed -n %dp file.txt", i+2))
set label 1 at screen 0.9, screen 0.9 sprintf("t = %.2f", real(word(line, 3)))
set label 2 at screen 0.9, screen 0.88 sprintf("x = %.2f y = %.2f", real(word(line, 1)), real(word(line, 2)))
plot 'file.txt' every ::::i with lines title sprintf('n = %d', i)
}
I don't know which variant fits you better. I used i+2 as line number to skip the commented header line, which isn't detected automatically. By using tag for the label (set label 1) you make sure, that old labels are overwritten.

Resources