I have a set of points "data" defining a curve that I want to plot with bezier smooth.
So I want to fill the area below that curve between some pairs of x values.
If I only had one pair of x values it's not that difficult because I define a new set of data and plot it with filledcu. Example:
The problem is that I want to do that several times in the same plot.
Edit: Minimal working example:
#!/usr/bin/gnuplot
set terminal wxt enhanced font 'Verdana,12'
set style fill transparent solid 0.35 noborder
plot 'data' using 1:2 smooth sbezier with lines ls 1
pause -1
Where the structure of 'data' is:
x_point y_point
And I realized that my problem is that in fact I can't fill not even one curve, it seems to be filled because the slope is almost constant there.
To fill parts below a curve, you must use the filledcurves style. With the option x1 you fill the part between the curve and the x-axis.
In order to fill only parts of the curve, you must filter your data, i.e. give the x-values a value of 1/0 (invalid data point) if they are outside of the desired range, and the correct value from the data file otherwise. At the end you plot the curve itself:
set style fill transparent solid 0.35 noborder
filter(x,min,max) = (x > min && x < max) ? x : 1/0
plot 'data' using (filter($1, -1, -0.5)):2 with filledcurves x1 lt 1 notitle,\
'' using (filter($1, 0.2, 0.8)):2 with filledcurves x1 lt 1 notitle,\
'' using 1:2 with lines lw 3 lt 1 title 'curve'
This fills the range [-1:0.5] and [0.2:0.8].
To give a working example, I use the special filename +:
set samples 100
set xrange [-2:2]
f(x) = -x**2 + 4
set linetype 1 lc rgb '#A3001E'
set style fill transparent solid 0.35 noborder
filter(x,min,max) = (x > min && x < max) ? x : 1/0
plot '+' using (filter($1, -1, -0.5)):(f($1)) with filledcurves x1 lt 1 notitle,\
'' using (filter($1, 0.2, 0.8)):(f($1)) with filledcurves x1 lt 1 notitle,\
'' using 1:(f($1)) with lines lw 3 lt 1 title 'curve'
With the result (with 4.6.4):
If you must use some kind of smoothing, the filter may affect the data curve differently, depending on the filtered part. You can first write the smoothed data to a temporary file and then use this for 'normal' plotting:
set table 'data-smoothed'
plot 'data' using 1:2 smooth bezier
unset table
set style fill transparent solid 0.35 noborder
filter(x,min,max) = (x > min && x < max) ? x : 1/0
plot 'data-smoothed' using (filter($1, -1, -0.5)):2 with filledcurves x1 lt 1 notitle,\
'' using (filter($1, 0.2, 0.8)):2 with filledcurves x1 lt 1 notitle,\
'' using 1:2 with lines lw 3 lt 1 title 'curve'
Related
I am currently working on a project where I need to plot a set of functions and fill the area between them.
I have tried different things, but I cannot really get it to work.
Here is a simplified version of the gnuplot script:
f(x) = 80
g(x) = 0.35*x - 7.5
h(x) = -1.96629*x + 710
i(x) = -80
j(x) = -0.35*x + 7.5
k(x) = 1.96629*x -710
set xzeroaxis
set xtics axis
set xrange [0:500]
set yzeroaxis
set ytics axis
set yrange [-200:200]
set border 0
plot f(x) with lines ls 1 lt rgb "red", \
g(x) with lines ls 1 lt rgb "red", \
h(x) with lines ls 1 lt rgb "red", \
i(x) with lines ls 1 lt rgb "blue", \
j(x) with lines ls 1 lt rgb "blue", \
k(x) with lines ls 1 lt rgb "blue"
This produces the following plot:
I have tried different things and this link got me some of the way, but I am running out of ideas.
So my question goes: is it possible to fill the area between the red and blue lines (I.e the convex space that the functions form)?
You can do it easily if you already know which curves are lower bounds and which are upper bounds:
max(a,b)=(a>b)?a:b
min(a,b)=(a<b)?a:b
lowerb(x)=max(max(i(x),j(x)),k(x))
upperb(x)=min(min(f(x),g(x)),h(x))
plot "+" using 1:((lowerb($1)<upperb($1))?lowerb($1):1/0):(upperb($1)) with filledcurves
The ternary operator in the plot command allows to plot only { lowerb(x)< y <upperb(x)} and not { lowerb(x) > y > upperb(x)}
If you have a very long list of functions, it should be possible to automate the construction of lowerb and upperb using a macro.
Use the ternary operator to define piece wise the red function. Call it f1. Plot f1 and -f1 with filledcurves. I think that approach should do it.
Suppose I have the following data file, so-qn.dat:
Type on on-err off off-err
good 75 5 55 4
bad 15 2 30 3
#other 10 1 15 2
which contains values on columns 2 and 4 and corresponding error deltas on columns 3 and 5.
I can produce a columnstacked histogram:
#!/usr/bin/gnuplot
set terminal png
set output 'so-qn.png'
set linetype 1 lc rgb "blue" lw 2 pt 0
set linetype 2 lc rgb "dark-red" lw 2 pt 0
set style data histograms
set style histogram columnstacked
set style fill solid
set ylabel "% of all items"
set yrange [0:100]
set boxwidth 0.75
set xtics scale 0
set xlabel "Option"
plot 'so-qn.dat' using 2 ti col, \
'' using 4:key(1) ti col
But I can’t figure out how to add errorbars to this. The closest I got so far is with
plot 'so-qn.dat' using 2 ti col, '' using 2:3 with yerrorbars lc rgb 'black' ti col, \
'' using 4:key(1) ti col, '' using 4:5:key(1) with yerrorbars lc rgb 'black' ti col
which produces
but only one of the error bars is in the right spot (I actually have no idea where the bottom left one gets its y from), one is completely invisible (hidden behind the right stack?), and I’d like the error bars to not show up in the key.
Is it possible to combine column-stacked histograms and error bars?
You can add errorbars to column-stacked histograms by manually adding plot-commands for the errorbars. To do so, you need, however, to keep track of the y-positions.
Therefore, let's introduce two variables which store the y-position for each of the two columns' errorbars.
y1 = -2
y2 = -4
You need to initialize these variables with -(number of column)
Next, let us define two functions that update the variables y1, y2.
f1(x) = (y1 = y1+x)
f2(x) = (y2 = y2+x)
Now, generate the desired plot via
plot 'so-qn.dat' using 2 ti col, \
'' using 4:key(1) ti col, \
'' using (0):(f1($2)):3 w yerr t "", \
'' using (1):(f2($4)):5 w yerr t ""
As you can see, you can supress the errorbars in the key by assigning an empty title (t ""). This approach even gives you more flexibility in customizing the appearance of the errorbars (e.g., assign different linestyles etc.).
This being said, I personally think this visualization is rather confusing. You might want to consider another visualization:
set bars fullwidth 0
set style data histograms
set style fill solid 1 border lt -1
set style histogram errorbars gap 2 lw 2
plot 'so-qn.dat' using 2:3:xtic(1) ti columnhead(2), \
'' using 4:5:xtic(1) ti columnhead(4)
I am trying to use gnuplot to fill between a curve and the x axis for a certain xrange. For example I would like to fill between the line f(x)=x when x<5.
Example code:
set xrange [-10:10]
set yrange [-10:10]
set samples 100
plot x with filledcurves above x1=5
When this is plotted in Gnuplot 5.0 it does not show any fill.
I can try the reverse of:
plot x with filledcurves below x1=5
This gets closer because it fills below the line f(x)=x when x<5, however, it also shades the area above when x>5. There is also no way to limit it to above the x axis as well.
Any assistance would be appreciated. Thanks.
It seems there is no "direct" way to do it. Christoph gives a solution here.
Based on his code I came up with the following:
set xrange [-10:10]
set yrange [-10:10]
filter_lt(x,xmax) = ((x < xmax) ? x : 1/0)
f(x) = x
xmax = 5
plot '+' using (filter_lt($1,xmax)):(f($1)) with filledcurves x1 lt 1 notitle,\
'' using 1:(f($1)) with lines lw 2 lt 1 title 'f(x)=x'
I am plotting two graphs using gnuplot. First plot is actual data and the second one is the fitting of the data.
The script I used for plotting this is shown here below:
#!/usr/bin/gnuplot
reset
set terminal png enhanced
set terminal pngcairo enhanced color dashed
set output 'msd-maltoLyo12per-225ns.png'
##########################################
set macros
labelSIZE="font 'Arial,24'"
ticFONT="font 'Arial,16"
set key font 'Arial,14'
set key spacing 1.5 samplen 5
##########################################
set xrange [0:225]
set yrange [0:11000]
set xtic #ticFONT
set ytic #ticFONT
set xtics out nomirror
set ytics out nomirror
##############################
set style line 1 lt 1 lc rgb "red" lw 2.0
set style line 2 lt 2 lc rgb "blue" lw 2.0
set style line 3 lt 3 lc rgb "coral" lw 2.0
set style line 4 lt 4 lc rgb "green" lw 2.0
set style line 5 lt 5 lc rgb "black" lw 2.0
##############################
f(x)=a+b*x
fit [120:225] f(x) 'diff-xy-maltoLyo12per.dat' via a,b
plot 'diff-xy-maltoLyo12per.dat' using 1:2 with lines linestyle 1 title "{/Symbol b}Mal-C_{12}", f(x) lw 3.0 lc rgb 'black'
Here I plot the fitting graph from 1 to 120 as shown . Also I want to plot the same graph from range 120 to 225 as in the picture .
Now I want a single plot which contain the two black lines and the red line.
How can I achieve this?
Thanks in advance.
Working with the script you already have, you can use two functions to fit in the different ranges separately, and then use a conditional plot that selects one if x < 120 and the other one if x > 120:
f1(x)=a1+b1*x
fit [0:120] f1(x) 'diff-xy-maltoLyo12per.dat' via a1,b1
f2(x)=a2+b2*x
fit [120:225] f2(x) 'diff-xy-maltoLyo12per.dat' via a2,b2
f(x) = x < 120 ? f1(x) : f2(x)
plot 'diff-xy-maltoLyo12per.dat' using 1:2 with lines linestyle 1 title "{/Symbol b}Mal-C_{12}", f(x) lw 3.0 lc rgb 'black'
Now, the way I would go about this, would be to generate a special fitting function, whose parameters would give me the point at which the slope changes as a result of the fitting itself. Say you call that point x0 (for which the value of the function is y0), the slope at the left of it is m1 and the slope at the right m2. Then the function at the left has the form m1*(x-x0)+y0 and the function at the right has the form m2*(x-x0)+y0. The overall function can be defined in gnuplot as:
f(x) = x < x0 ? m1*(x-x0)+y0 : m2*(x-x0)+y0
and you can fit f(x) "data" via x0, m1, m2, y0. You can also generate this function without the condition using a step function:
f(x) = m1*(x-x0)*(sgn(x0-x)+1)/2 + m2*(x-x0)*(sgn(x-x0)+1)/2 + y0
After you fit, for which you might need to provide some initial values, you can print x0 and you'll get the best value (that should be close to 120 in your case, as you know) for the position of the change in slope.
I want to plot a histogram with broken axis on Y. A good tutorial has been explained here and here but they don't fit my need. The data points are
"Method" "Year1" "Year2"
M1 12 -40
M2 5 40
The code snippet for this data points are
set ylabel "The Profit (%)"
set style data histogram
set style histogram cluster gap 1
# Draw a horizontal line at Y=0
set arrow 1 from -1,0 to 2,0 nohead
plot 'test_data.txt' using 2:xtic(1) ti col lc rgb "black", '' u 3 ti col lc rgb "grey"
And the output looks like
As you can see the grey bars are on the extreme values. What I want is to limit the yrange from - to +20 and put a ~~ symbol (rotate it by 90 degree) on the second bars and put a label -40 and +40. Something like this figure
How that is possible?
You can do it, but it is very tedious:
Crop the y-values in the using statement of your histograms
Plot a label with the labels plotting style when the value is above or below a given limit.
Plot the vectors, which show, that the boxes are truncated.
The following script works:
set ylabel "The Profit (%)"
set style histogram cluster gap 1
set boxwidth 0.9 relative
# Draw a horizontal line at Y=0
set xzeroaxis lt -1
ulim = 15
llim = -15
set yrange[-20:20]
sc = 0.333
set style fill solid noborder
plot 'test_data.txt' using ($2 > ulim ? ulim : ($2 < llim ? llim : $2)):xtic(1) ti col lc rgb "black" with histogram, \
'' u ($3 > ulim ? ulim : ($3 < llim ? llim : $3)) ti col lc rgb "grey" with histogram,\
for [c=2:3] '' u ($0-1+(c-2.5)*sc):(column(c) > ulim ? ulim : 1/0):(sprintf('+%d', ulim)) with labels offset 0, char 1.5 notitle,\
for [c=2:3] '' u ($0-1+(c-2.5)*sc):(column(c) < llim ? llim : 1/0):(sprintf('%d', llim)) with labels offset 0, char -1.5 notitle,\
for [c=2:3] for [ofs=0:1] '' u ($0-1+(c-2.5)*sc - 0.03 + ofs*0.02):\
(column(c) > ulim ? ulim - 1 : (column(c) < llim ? llim - 1 : 1/0)):(0.04):(2) with vectors lc rgb 'black' nohead notitle
and gives the following result with 4.6.3:
There is too much involved to explain everything, so here are some important remarks:
The histogram boxes are placed starting from 0 and are given a custom label. This is important for the placement of the labels and the vectors ($0-1 in the using statement).
The factor sc = 0.333 results from the three columns for on xtick (year1, year2, and the gap 1).
The method works for both columns 2 and 3
The script gives some warning, because some plots are empty (no value of column 2 exceeds the limits, so the respective label and vectors plots contain no points).
I think its not practicable to use curves to indicate the broken boxes.
If your boxes have borders, they would appear also on top of the broken boxes, which might be counterintuitive.
Use either set xzeroaxis to draw a line at y=0, or an arrow with graph coordinates (set arrow from graph 0,first 0 to graph 1, first 0 nohead).