I am using gnuplot for the following. I have n equations which I want to plot based on the xaxis value. Here is a sample
set xrange[0:25]
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
plot (x>0)&&(x<10)?f1(x):(x<20)?f2(x):f3(x)
I know that we can set the color of the line easily by using the below. But it changes the whole color
set style line 1 lt 1 lw 3 pt 3 lc rgb "blue"
But what I want is to make the connecting lines a different color. ie if you plot the above graph you will 5 lines. 3 original lines (from the function) and 2 lines (the almost vertical lines) connecting them. I want to change the color of the connecting lines.
Note 1: These functions are automatically generated by a program, and the number of functions could be large. Even the exact plot command is automatically generated
Note 2: I want a way to differentiate my original lines with the interpolated lines which joins my original lines.
Any help is appreciated
What you actually have is one line defined piecewise, and there isn't an easy way to define colors for line segments within a piecewise line in gnuplot.
Easy way (plot a data file)
I would recommend making a data file looking like this:
# x y color
0 0 0
10 10 0
10 10 1
10 30 1
10 30 0
20 60 0
20 60 1
20 200 1
20 200 0
25 250 0
Notice the double points at x=10 and x=20. This is so the line segments meet at the transitions.
Now plot it with linecolor variable:
#!/usr/bin/env gnuplot
reset
set terminal pdfcairo enhanced color dashed rounded lw 5 size 3,2 font 'Arial,14'
set output 'output2.pdf'
set style data lines
set key top left
set tics scale 0.5 out nomirror
plot 'data.dat' u 1:2:3 lc variable
It looks like this:
You can change the palette (set palette) to determine the colors, and you can have more than 2 color values in the data file if you want.
Harder way (only OK for few segments)
You could define 2n-1 separate lines and connect them:
#!/usr/bin/env gnuplot
reset
set terminal pdfcairo enhanced color dashed rounded lw 5 size 3,2 font 'Arial,14'
set output 'output.pdf'
set style data lines
set key top left
set tics scale 0.5 out nomirror
# points every 0.001 units in the range 0:25
set samples 25001
# main lines
f1(x) = (x <= 9.999) ? x : 1/0
f3(x) = (x >= 10.001) && (x <= 19.999) ? 3*x : 1/0
f5(x) = (x >= 20.001) ? 10*x : 1/0
# define slopes and y-offsets of connecting lines
m2 = (f3(10.001)-f1(9.999))/0.002
b2 = (30.0-10.0)/2.0 + 10.0
m4 = (f5(20.001)-f3(19.999))/0.002
b4 = (200.0-60.0)/2.0 + 60.0
# connecting functions
f2(x) = (x >= 9.999) && (x <= 10.001) ? m2*(x-10) + b2 : 1/0
f4(x) = (x >= 19.999) && (x <= 20.001) ? m4*(x-20) + b4 : 1/0
plot [0:25] f1(x), f2(x), f3(x), f4(x), f5(x)
Which looks like this:
You can define a secondary function to define the breakpoints of your function, which is automatically coloring the right linepiece. The below code is easy to extend to different functions and breakpoints (i.e., you can just change x1 or x2). Adding multiple points is also straightforward.
xmin=0.
xmax=25.
x0=0.
x1=10.
x2=20.
nsample=200.
dx=(xmax-xmin)/nsample
print dx
set xrange[xmin:xmax]
set sample nsample
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
f4(x) = (x>x0)&&(x<x1)?f1(x):(x<x2)?f2(x):f3(x)
f5(x) = x
f5(x) = ( (x>x1&&x<=x1+dx) || (x>x2&&x<=x2+dx) )?1:0
set cbrange [0:1]
unset key
plot '+' using 1:(f4($1)):(f5($1)) lc variable with lines
Not that I have use the special filename '+', which just constructs a data file with equally space datapoints (following nsample).
If it is ok to skip the connecting lines, then you can use a simplified version of #andyras second variant. Just define all functions to be 1/0 when outside a specified range:
set style data lines
unset key
f1(x) = (x > 0) && (x < 10) ? x : 1/0
f2(x) = (x > 10) && (x < 20) ? 3*x : 1/0
f3(x) = (x > 20) ? 10*x : 1/0
plot [0:25] f1(x), f2(x), f3(x)
Following yet another possibility. This assumes, that you can select a sampling high enough, so that the "jumps" which connect the functions are always greater than inside a function:
set style data lines
unset key
set xrange[0:25]
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
f(x) = ( (x>0)&&(x<10)?f1(x):(x<20)?f2(x):f3(x) )
set samples 1000
curr = 0
prev = 0
lim = 1
plot '+' using (prev = curr, curr=f($1), $1):(f($1)):(abs(curr-prev) < lim ? 0 : 1) lc var
Related
I've been trying to compute numerically the derivative using gnuplot, using the scripts in this other discussion, even with the same data file. However I keep getting this error:
gnuplot> d(y) = ($0 == 0) ? (y1 = y, 1/0) : (y2 = y1, y1 = y, y1-y2)
^
"prova.g", line 7: ')' expected
I don't know what to do here. Any help?
Here is an example for numerical derivatives from my collection. Requires gnuplot >=5.0 and with the use of files instead of datablocks (and probably with some tweaking with gnuplot>=4.4.0).
Script: (works with gnuplot>=5.0.0, Jan. 2015)
### numerical derivatives
reset session
# create some data
MyFunction = "sin(x)/x"
set table $Data
set samples 150
plot [-10:10] '+' u 1:(#MyFunction) w table
unset table
DerivX(colX) = (x0=x1,x1=column(colX),(x0+x1)/2.)
DerivY(colY) = (y0=y1,y1=column(colY),(y1-y0)/(x1-x0))
set table $Deriv1
plot x1=y1=NaN $Data u (DerivX(1)):(DerivY(2)) w table
unset table
set table $Deriv2
plot x1=y1=NaN $Deriv1 u (DerivX(1)):(DerivY(2)) w table
unset table
set table $Deriv3
plot x1=y1=NaN $Deriv2 u (DerivX(1)):(DerivY(2)) w table
unset table
plot $Data u 1:2 w l lc rgb "red" ti MyFunction, \
$Deriv1 u 1:2 w l lc rgb "web-green" ti "1st Derivative", \
$Deriv2 u 1:2 w l lc rgb "blue" ti "2nd Derivative", \
$Deriv3 u 1:2 w l lc rgb "magenta" ti "3rd Derivative"
### end of script
Result:
Addition: (version for gnuplot 4.2.6, Sept. 2009)
gnuplot 4.2.6 doesn't have datablocks and serial evaluation, but here is a cumbersome workaround without these features.
for illustration, the script creates a data file SO68198576.dat (you already have your input file)
plot the data file into another file TEMP1 skipping the first data line
merge the files line by line into another file TEMP2 using the system command paste (either on Linux already on the system or on Windows you have to install, e.g. CoreUtils from GnuWin).
now you can calculate dx and dy between two successive datapoints from column 1 and 4 and column 2 and 5, respectively.
since the files have different length, the last line(s) should be skipped. This can be done by the system command head -n -2.
That's how TEMP2 looks like:
#Curve 0 of 1, 150 points #Curve 0 of 1, 150 points
#x y type #x y type
-10 -0.0544021 i -9.86577 -0.0432646 i
-9.86577 -0.0432646 i -9.73154 -0.0310307 i
-9.73154 -0.0310307 i -9.59732 -0.0178886 i
...
Script: (works with gnuplot 4.2.6, requires system commands paste and head)
### numerical derivative for gnuplot 4.2.6
reset
FILE = "SO68198576.dat"
set table FILE
set samples 150
plot sin(x)/x
unset table
TEMP1 = FILE.'1'
TEMP2 = FILE.'2'
set table TEMP1
plot FILE u 1:2 every ::1
unset table
system(sprintf('paste %s %s > %s', FILE, TEMP1, TEMP2))
system(sprintf('head -n -2 %s > %s',TEMP2, TEMP1))
x0(col) = (column(col)+column(col+3))/2.
dx(col) = (column(col+3)-column(col))/2.
dy(col) = (column(col+3)-column(col))/2.
plot FILE u 1:2 w lp pt 7 title "Data", \
TEMP1 u (x0(1)):(dy(2)/dx(1)) w lp pt 7 title "1st Derivative"
### end of script
Result: (screenshot gnuplot 4.2.6)
Does anyone have example code in gnuplot for a pie chart? I can't find any great example with a simple graph and the text around it and in it with the % signs that shows easily how much each part has of the circle.
Some example data:
Management frames 4596
Control frames 70173
Data frames 40347
TCP packets 36864
HTTP packets 525
ICMP packets 47
Total frames 115116
Updated:
After some years, I came again across this post, and I thought the code looked pretty messy. Therefore an attempt to improve and clean it up.
The following code is a bit different from the link I referenced above.
instead of a predefined color sequence or number codes in a separate list, the colors of the sections are given in the datablock (or datafile) next to the item/number by the names of predefined colors in gnuplot (see also https://stackoverflow.com/a/55736522/7295599). Because palette is used you can enter either colorname or hex-code, e.g. magenta or 0xff00ff.
the labels are aligned left or right depending on their position relative to 0.
you can choose the starting angle by PieStart and "rotation"-direction by PieDirection of the pie-chart
you can add individual radial and angular offsets for segments and labels
as you can see, there is no need for the total sum in the raw data. The total sum will be calculated automatically.
the reason why I define various functions f(n) which actually do not depend on n is to get the current values of other variables (at the time of calling the function) instead of passing a lot of parameters to the functions.
I hope you can adapt this code to your needs.
Code: (works with gnuplot>=5.0.0)
### pie-chart with labels with gnuplot
reset session
set size square
set angle degrees
set border 0
unset colorbox
unset tics
unset key
$Data <<EOD
# label value color SRoff SAoff LRoff LAoff
"Alpha" 85843 red 0 0 0 0
"Beta" 44000 green 0.2 45 0.2 0
"Gamma" 25399 blue 0 0 0 0
"Delta" 18451 magenta 0 0 0 0
"Epsilon" 12344 yellow 0 0 0 0
"Zeta" 11999 cyan 0 0 0 0
"Eta" 9000 orange 0 0 0 0
"Theta" 8500 0xb0f060 0 0 0.03 0
"Iota" 4711 dark-violet 0 0 0.12 0
EOD
colLabel = 1 # label
colValue = 2 # segment value
colColor = 3 # segment color, either color name or 0xRRGGBB value
colSegRoff = 4 # radial segment offset
colSegAoff = 5 # angular segment offset
colLabRoff = 6 # radial label offset
colLabAoff = 7 # angular label offset
# define a palette from colornames of the datafile/datablock in column colColor
set table $Dummy
myPalette = ''
plot $Data u (myPalette = myPalette.(myPalette eq '' ? '' : ', ').sprintf('%d "%s"',$0,strcol(colColor)),$0) with table
myPalette = '('.myPalette.')'
unset table
set palette defined #myPalette
stats $Data u colValue nooutput # get total sum from column colValue
TotalSum = STATS_sum
set xrange[-1.5:1.5]
set yrange[-1.5:1.5]
PieStart = 90 # 0 = 3 o'clock, 90 = 12 o'clock
PieDirection = -1 # -1 clockwise, 1 counterclockwise
Radius = 1.0
RadiusLabelOff = 0.05 # default radial label offset
SegPosX(n) = column(colSegRoff)*cos((a2+a1+column(colSegAoff))*0.5)
SegPosY(n) = column(colSegRoff)*sin((a2+a1+column(colSegAoff))*0.5)
LabPosX(n) = (Radius+RadiusLabelOff+column(colLabRoff))*cos((a2+a1+column(colLabAoff))*0.5)
LabPosY(n) = (Radius+RadiusLabelOff+column(colLabRoff))*sin((a2+a1+column(colLabAoff))*0.5)
a1=a2=PieStart
getAngles(n) = (a1=a2, a2=a2+sgn(PieDirection)*column(colValue)/TotalSum*360)
getLabel(n) = sprintf("%s %.1f%%", strcol(colLabel), column(colValue)/TotalSum*100)
set multiplot layout 2,1
plot $Data u (getAngles(0), SegPosX(0)):(SegPosY(0)):(Radius):(PieDirection<0?a2:a1):(PieDirection<0?a1:a2):($0) \
with circles fs solid 1.0 lc palette notitle,\
'' u ( getAngles(0), Align=LabPosX(0)):(LabPosY(0)): (Align>0? getLabel(0) : '') with labels font ",10" left, \
'' u ( getAngles(0), Align=LabPosX(0)):(LabPosY(0)): (Align<0? getLabel(0) : '') with labels font ",10" right
PieDirection = +1
a1=a2=PieStart
replot
unset multiplot
### end of code
Result:
Say, I have two points (x1,y1) and (x2,y2) on the same line . The midpoint of joining this two points is (x,y). Is it possible to draw a perpendicular bisector through (x,y) in gnuplot? How will I draw it?
It's simple math:
your line slope: slope = (y2 - y1) / (x2 - x1)
your line equation: line(x) = slope * (x - x1) + y1
the middle point (calling it xm,ym because x,y are reserved):
xm=(x1+x2)/2.0
ym=(y1+y2)/2.0
the perpendicular line equation: line_perp(x) = -(x-xm)/slope + ym
plot both: plot line(x), line_perp(x)
In case y2==y1 or x2==x1 i.e the two points are in horizontal/vertical line you can fix the script using an arrow:
if (y2==y1 || x2==x1) {
set arrow from xm, graph 0 to xm, graph 1 nohead
plot ym
} else {
plot line(x), line_perp(x)
}
Instead of going via y = a*x + b as in #bibi's and #user4489658's answers, where a could be infinite, I would go via the angle (check help atan2).
This covers vertical lines without extra treatment.
Make sure to use set size ratio -1 (check help size) that the perpendicular bisector really looks perpendicular in the graph.
Script:
### drawing perpendicular bisectors
reset session
$Data <<EOD
# x1 y1 x2 y2
10 20 15 20
10 10 20 20
20 10 20 15
12 10 18 12
10 12 12 18
EOD
set key out
set offset 1,1,1,1
set angle degrees
set size ratio -1
colX1 = 1
colY1 = 2
colX2 = 3
colY2 = 4
dx(n) = column(colX2)-column(colX1)
dy(n) = column(colY2)-column(colY1)
a0(n) = atan2(dy(n),dx(n)) + 90
xm(n) = (column(colX1)+column(colX2))*0.5
ym(n) = (column(colY1)+column(colY2))*0.5
Scaling = 0.2
L0(n) = Scaling*sqrt(dx(n)**2 + dy(n)**2)
getParams(n) = (dx0=L0(0)*cos(a0(0)), dy0=L0(0)*sin(a0(0)), x0=xm(0)-dx0, y0=ym(0)-dy0)
plot $Data u colX1:colY1 w p pt 7 lc "blue" ti "Start", \
'' u colX2:colY2 w p pt 7 lc "red" ti "End", \
'' u colX1:colY1:(dx(0)):(dy(0)) w vec lc "web-green" filled ti "Vector", \
'' u (getParams(0),x0):(y0):(2*dx0):(2*dy0) w vec lc "black" dt 3 nohead ti "\nperpendicular\nbisector"
### end of script
Result:
Equation of your line is
y=ax+b
a=(y2-y1)/(x2-x1)
b=(x2*y1-y2*x1)/(x2-x1)
Midpoint:
x3=(x1+x2)/2.;y3=(y1+y2)/2.
Equation of perpendicular line:
y-y3=-1./a*(x-x3)
y=-1./a*x+x3/a+y3
a2=-1./a
b2=x3/a+y3
gnuplot script:
x1=1.;y1=3.;x2=10.;y2=15.
a=(y2-y1)/(x2-x1)
b=(x2*y1-y2*x1)/(x2-x1)
x3=(x2+x1)/2.;y3=(y2+y1)/2.
a2=-1./a
b2=x3/a+y3
set arrow 1 from x1,y1 to x2,y2 nohead
plot [0:15][0:22] a2*x+b2
From a function in C++ I get in a file the coordinates of the centers of a chain of spheres (of constant radius r). I would like to plot this chain with gnuplot. How can I represent the spheres with the true radius? This solution actually does not work, since the unit of pointsize is not the same as that of the axis (and is also changing with the axis limits).
This a slightly dirty solution which uses parametric (and some commands from Unix). For each line of the following data, we will plot a sphere with radius r, and centered at (x,y,z):
# points.dat :
# x y z radius
0 0 0 0.5
1 2 2 1.0
3 4 5 0.7
2 5 7 1.0
1 3 4 0.75
2 0 1 1.5
In other words, we will run commands with the form:
splot x1+r1*cos(v)*cos(u), y1+r1*cos(v)*sin(u), z1+r1*sin(v) title "line 1",\
x2+r2*cos(v)*cos(u), y2+r2*cos(v)*sin(u), z2+r2*sin(v) title "line 2", ...
The following code will do the trick (comments through the script):
set view equal xyz # to scale the axes of the plot
set hidden3d front # draw opaque spheres
set parametric # enable parametric mode with angles (u,v)
set urange [0:2*pi]
set vrange [-pi/2.0:pi/2.0]
filename = 'spheres.dat'
# get number of data-lines in filename
nlines = system(sprintf('grep -v ^# %s | wc -l', filename))
# this will save the plot commands
commands = 'splot '
do for [i=1:nlines] {
# get the i-th line
line = system( sprintf('grep -v ^# %s | awk "NR == %i {print; exit}" ', filename, i) )
# extract the data
x = word(line,1)
y = word(line,2)
z = word(line,3)
r = word(line,4)
# and save the instructions to plot the corresponding sphere
commands = commands . sprintf('%s + %s*cos(v)*cos(u), %s + %s*cos(v)*sin(u), %s + %s*sin(v) t "line %i"', x, r, y, r, z, r, i)
# if not EOF, add a comma to commands
if(i<nlines) { commands = commands . ', ' }
}
# commands is a string. We can run it into the command line through macros
set macros
#commands
This is the output I obtain:
I would like to plot how the amplitude and orientation of a 2D vector evolves over time. To do this I would like to create a graph reminiscent of the canonical E & B field graphs you may recall from an introductory electricity and magnetism class.
Specifically, I would like to connect my 2D vector points with a ribbon, so that they are easy to see. Is there a simple way to do this in MATLAB? quiver3 is pretty close, but it lacks the ribbon. Perhaps some sort of parametric surface?
You can use the plotting functions FILL3 and QUIVER3 to do something like this:
x = linspace(0,4*pi,30); %# Create some x data
y1 = sin(x); %# Create wave 1
y2 = sin(x-pi); %# Create wave 2
u = zeros(size(x)); %# Create a vector of zeroes
hRibbon1 = fill3(x,y1,u,'r'); %# Plot wave 1 and fill underneath with color
set(hRibbon1,'EdgeColor','r',... %# Change the edge color and
'FaceAlpha',0.5); %# make the colored patch transparent
hold on; %# Add to the existing plot
quiver3(x,u,u,u,y1,u,0,'r'); %# Plot the arrows
hRibbon2 = fill3(x,u,y2,'b'); %# Plot wave 2 and fill underneath with color
set(hRibbon2,'EdgeColor','b',... %# Change the edge color and
'FaceAlpha',0.5); %# make the colored patch transparent
quiver3(x,u,u,u,u,y2,0,'b'); %# Plot the arrows
axis equal; %# Use equal axis scaling
And here's the resulting plot:
here's a solution that draws a ribbon between any two lines in 3D space. you can plot your quiver over it & adjust the opacity using 'FaceAlpha' as in gnovice's solution
To make the function clearer, I am first posting it without error-checking and resizing functions (which make up most of the body of the function & aren't particularly interesting)
function h = filledRibbon (x,y,z,u,v,w,c, varargin)
%function filledRibbon (x,y,z,u,v,w,c, varargin)
%
%plots a ribbon spanning the area between the lines x,y,z and x+u,y+v,z+w
%in the color c
%varargin is passed directly to patch
%returns a handle to the patch graphic created
%make up a set of regions that span the space between the lines
xr = [x(1:end-1); x(1:end-1) + u(1:end-1); x(2:end) + u(2:end); x(2:end)];
yr = [y(1:end-1); y(1:end-1) + v(1:end-1); y(2:end) + v(2:end); y(2:end)];
zr = [z(1:end-1); z(1:end-1) + w(1:end-1); z(2:end) + w(2:end); z(2:end)];
%plot the regions with no edges
h = patch(xr,yr,zr,c, 'LineStyle','none', varargin{:});
use this error-checking version in your actual code:
function h = filledRibbon (x,y,z,u,v,w,c, varargin)
%function filledRibbon (x,y,z,u,v,w,c, varargin)
%
%plots a ribbon spanning the area between the lines x,y,z and x+u,y+v,z+w
%in the color c
%varargin is passed directly to patch
%returns a handle to the patch graphic created
if ~exist('w', 'var') || isempty(w)
w = 0;
end
if ~exist('u', 'var') || isempty(u)
u = 0;
end
if ~exist('v', 'var') || isempty(v)
v = 0;
end
if ~exist('c', 'var') || isempty(c)
c = 'b';
end
%make all vectors 1xN
x = reshape(x,1,[]);
y = reshape(y,1,[]);
z = reshape(z,1,[]);
%if any offsets are scalar, expand to a vector
if all(size(u) == 1)
u = repmat(u, size(x));
end
if all(size(v) == 1)
v = repmat(v, size(x));
end
if all(size(w) == 1)
w = repmat(w, size(x));
end
%make up a set of regions that span the space between the lines
xr = [x(1:end-1); x(1:end-1) + u(1:end-1); x(2:end) + u(2:end); x(2:end)];
yr = [y(1:end-1); y(1:end-1) + v(1:end-1); y(2:end) + v(2:end); y(2:end)];
zr = [z(1:end-1); z(1:end-1) + w(1:end-1); z(2:end) + w(2:end); z(2:end)];
%plot the regions with no edges
h = patch(xr,yr,zr,c, 'LineStyle','none', varargin{:});