I am having some difficulty generating a plot of a data set that is oscillating between negative and positive values (line a sin or cos). My goal is to fill the area under the curve with alternating colour: negative region with blue and positive with red. To be more precise I want to fill the area between the curve and the x axis. So far i managed to plot the curve with alternating colours (blue for negative, red for positive) using:
set palette model RGB defined ( 0 'red', 1 'blue' )
unset colorbox
plot 'data.set' u 1:2:( $2 < 0.0 ? 1 : 0 ) w lines lt 1 lw 4 palette
Unfortunately if I replace w lines with filledcurves I don't get an alternate fill. How can one accomplish this?
Cheers
If I understood the question correctly, you can try this:
plot '+' using 1:(0):(sin($1)) w filledc below, \
'+' using 1:(0):(sin($1)) w filledc above
which is telling gnuplot to fill the area between two curves (sin(x) and 0), using the above and below positions. There is another solution as well:
plot '+' using 1:(sin($1) > 0 ? sin($1):0) w filledcurves y1, \
'+' using 1:(sin($1) < 0 ? sin($1):0) w filledcurves y2
and the result would be:
The important part refers to the options part of filledcurves. See more details here and here.
Related
I haven't been able to find any example of what I'm trying to do in GNUplot from raking docs and demos.
Essentially I want to plot the Blue, Green, and Red lines I manually drew on this output (for demonstration) at the 10/50/90% marks.
EDIT: For clarity, I'm looking to determine where the distribution lines hit the cumulative distribution at 0.1/0.5/0.9 to know which co-ordinates to draw the lines at. Thanks!
set terminal png size 1600,800 font "Consolas" 16
set output "test.png"
set title "PDF and CDF - 1000 Simulations"
set grid y2
set ylabel "Date Probability"
set y2range [0:1.00]
set y2tics 0.1
set y2label "Cumulative Distribution"
set xtics rotate by 90 offset 0,-5
set bmargin 6
plot "data.txt" using 1:3:xtic(2) notitle with boxes axes x1y1,'' using 1:4 notitle with linespoints axes x1y2
Depending on the number of points in your cumulative data curve you might need interpolation. The following example is chosen such that no original data point will be at your levels 10%, 50%, 90%. If your data is not steadily increasing, it will take the last value which matches your level(s).
The procedure is as follows:
plot your data to a dummy table.
check when Level is between to successive y-values (y0,y1).
remember the interpolated x-value in xp.
draw arrows from the borders of the graph to the point (xp,Level) (or instead use the partly outside rectangle "trick" from #Ethan).
Code:
### linear interpolation of data
reset session
set colorsequence classic
set key left
# create some dummy data
set sample 10
set table $Data
plot [-2:2] '+' u 1:(norm(x)) with table
unset table
Interpolate(yi) = x0 + (x1-x0)*(yi-y0)/(y1-y0)
Levels = "0.1 0.5 0.9"
do for [i=1:words(Levels)] {
Level = word(Levels,i)
x0 = x1 = y0 = y1 = NaN
set table $Dummy
plot $Data u (x0=x1,x1=$1,y0=y1,y1=$2, (y0<=Level && Level<=y1)? (xp=Interpolate(Level)):NaN ): (Level) w table
unset table
set arrow i*2 from xp, graph 0 to xp,Level nohead lc i
set arrow i*2+1 from xp,Level to graph 1,Level nohead lc i
}
plot $Data u 1:2 w lp pt 7 lc 0 t "Original data"
### end code
Result:
It is not clear if you are asking how to find the x-coordinates at which your cumulative distribution line hits 0.1, 0.5, 0.9 (hard to do so I will leave that for now) or asking how to draw the lines once you know those x values. The latter part is easy. Think of the lines you want to draw as the unclipped portion of a rectangle that extends off the plot to the lower right:
set object 1 rectangle from x1, 0.1 to graph 2, -2 fillstyle empty border lc "blue"
set object 2 rectangle from x2, 0.1 to graph 2, -2 fillstyle empty border lc "green"
set object 3 rectangle from x3, 0.1 to graph 2, -2 fillstyle empty border lc "red"
plot ...
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'
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).
I have a file with 3 columns, the first 2 are the position x y and the 3rd one I use it for define the color so I have something like this:
set palette model RGB defined ( 1 'black', 2 'blue', 3 'green', 4 'red')
unset colorbox
plot "file" u 2:1:3 w points pt 14 ps 2 palette, "file2" u 2:1:3 w points pt 14 ps 2 palette
Now the question: Is it possible to have a proper legend with this kind of point and COLOR?.
Since the points will have different colors (according to the pallete) I want to specify what means each color in the legend.
The only solution I was thinking was to write somewhere in the plot some text with the character of the point (in this case pt 14) and specify the color... but is not really a solution right?
So please help!
There is no option for this, you need to fiddle a bit. Here is YAGH (Yet another gnuplot hack) ;)
Assuming that your values are equidistantly spaced, you can use the '+' special filename with the labels plotting style.
To show only the custom key, consider the following example:
labels="first second third fourth"
set xrange[0:1] # must be set for '+'
set yrange[0:1]
set samples words(labels) # number of colors to use
key_x = 0.8 # x-value of the points, must be given in units of the x-axis
key_y = 0.8
key_dy = 0.05
set palette model RGB defined ( 1 'black', 2 'blue', 3 'green', 4 'red')
unset colorbox
plot '+' using (key_x):(key_y + $0*key_dy):(word(labels, int($0+1))):0 \
with labels left offset 1,-0.1 point pt 7 palette t ''
This gives (with 4.6.4):
As the set samples doesn't affect the data plots, you can integrate this directly in your plot command:
...
unset key
plot "file" u 2:1:3 w points pt 14 ps 2 palette, \
"file2" u 2:1:3 w points pt 14 ps 2 palette, \
'+' using (key_x):(key_y - $0*key_dy):(word(labels, int($0+1))):0 \
with labels left offset 1,-0.1 point pt 14 ps 2 palette
But you need to set a proper xrange, yrange and the values of key_x, key_y and key_dy.
This is not the most intuitive way, but it works :)
I have an alternative solution posted here:
Using Gnuplot to plot point colors conditionally
Essentially you plot once without a legend entry, then make dummy plots (with no data) for each point color/label.
Here is an example data set.
#x y r c
1 2 10 2
3 1 2 4
3 2 1 5
I can plot with circle's radius representing the 3rd column OR with color representing the 3rd column. However, I don't know how to keep them both in the plot.
Here is my code to plot with radius representing the 3rd column.
plot 'rslt.log' u 1:2:3 w points pt 7 ps variable
Try:
plot 'rslt.log' u 1:2:3:4 w points pt 7 ps variable lc palette
An alternative is:
plot 'test.dat' u 1:2:3:4 w p pt 7 ps variable lc variable
or using the circles linestyle:
plot 'test.dat' u 1:2:3:4 w circles linecolor variable
If you want solid filled circles:
plot 'test.dat' u 1:2:3:4 w circles linecolor variable fillstyle solid
For any of the above, you can substitute linecolor variable with linecolor palette as suggested by #andyras. The difference is that palette maps a floating point number onto the palette whereas variable maps the integer to a linestyle which has a color associated with it.
With ps variable the number in the associated column becomes a multiplicative factor which increases the default size of the point. With circles you have the freedom to specify the exact size of the circle (as the radius) -- Although I'm not 100% sure which axis is used in the common case where the aspect ratio of your plot isn't 1.