Stepwise function in gnuplot -
i want know how create plot of stepwise function in gnuplot. function want plot includes operations cost several distance range , multiple products. instance, if distance 0-300 km product 1 cost 1.05 $/km , product 2, 0.86 $/km. when distance increases, cost each product decrease.
i have defined 1 function each product , plot them functions together:
gnuplot> f(x)=x<=300 ? 1.05 : x<=650 ? 0.65 : x<=1300 ? 0.46 : x<=1950 ? 0.4 : x<=3250 ? 0.31 : 0.22 gnuplot> x<=300 ? 0.86 : x<=650 ? 0.53 : x<=1300 ? 0.38: x<=1950 ? 0.32 : x<=3250 ? 0.24 : 0.19 gnuplot> plot [0:5000][0:3] f(x), g(x)
there 1 problem: can not remove vertical lines. idea?
thanks help
there 2 approaches can take. best approach use datafile, can use functions, although more difficult.
datafile approach
you going have trouble doing function, because going vertical lines. datafile gives little better control, , allows mark end points of pieces of piecewise function typical open/closed dots. set data file format:
x y # left point of piece 1 x y # right point of piece 1 # 1 single blank line x y # left point of piece 2 x y # right point of piece 2 # 1 single blank line ...
with function f, can like
0 1.05 300 1.05 300 0.65 650 0.65 650 0.46 1300 0.46 1300 0.4 1950 0.4 1950 0.31 3250 0.31 3250 0.22 6000 0.22
then plot datafile lines
gives
we can fancier with†
plot datafile w lines,\ last=0,\ "" u 1:(oldlast=last,last=$1,$1==oldlast?$2:1/0) w points pt 6 lt 1,\ last=0,\ "" u 1:(oldlast=last,last=$1,$1==oldlast?1/0:$2) w points pt 7 lt 1
to produce
here first plot same curve before. initialize variable last 0 (the value of first x coordinate)‡, , plot open dots.
to evaluate (oldlast=last,last=$1,$1==oldlast?$2:1/0)
first stores value of last oldlast , stores value of first column (the x coordinate) last use on next point. check see if x-coordinate same value of oldlast (the value of x-coordinate last point). if is, use 2nd column value, otherwise use unplottable 1/0
. cause points plotted if first point in 2 point blocks. plot these points using pointstyle 6 (an open point) , linetype 1 (the same used in lines).
we same thing again, time plot second points filled dots (pointtype 7).
we can either add points function g same file, separating others 2 blank lines , use indexes refer them, or create separate datafile g. can add similar plot commands current command. example, if use same file function f followed function g, can do:
plot datafile 0 w lines,\ last=0,\ "" 0 u 1:(oldlast=last,last=$1,$1==oldlast?$2:1/0) w points pt 6 lt 1,\ last=0,\ "" 0 u 1:(oldlast=last,last=$1,$1==oldlast?1/0:$2) w points pt 7 lt 1,\ datafile 1 w lines,\ last=0,\ "" 1 u 1:(oldlast=last,last=$1,$1==oldlast?$2:1/0) w points pt 6 lt 1,\ last=0,\ "" 1 u 1:(oldlast=last,last=$1,$1==oldlast?1/0:$2) w points pt 7 lt 1
function approach
as far getting 1 jump, functions have lot of redundant conditions. redefine f (and g) as
f(x)=x<=300 ? 1.05 : x<=650 ? 0.65 : x<=1300 ? 0.46 : x<=1950 ? 0.4 : x<=3250 ? 0.31 : 0.22
and plot it. make sure samples set high enough, otherwise may end collecting multiple jumps or undesirable slanted lines.
set xrange[0:6000] set yrange[0:2] set samples 1000 plot f(x)
we get
however, still vertical connecting lines. going hard avoid function. best way can think of avoid inject small non-plottable value before breaks. f(x), can with
f(x)=x<=290 ? 1.05 : x<=300? (1/0) : x<=640? 0.65 : x<=650 ? (1/0) : x<=1290 ? 0.46 : x<=1300 ? (1/0) : x<=1940? 0.4 : x<=1950 ? (1/0) : x<=3240 ? 0.31: x<=3250? (1/0) : 0.22
here, have inject non-plottable value of 1/0
region of length 10 before breaks. smaller lengths can used well. if set samples high enough sure sampling hits each of these breaks (in case sample of 1000 before enough), avoid connecting points.
with samples set small (for example 100), might still connecting lines
thus if use gap size smaller 10, may need use higher sampling avoid connecting lines. larger gaps may work smaller sampling.
depending on sampling, gaps might larger specified if sampling low. example, setting gaps size of 100 with
f(x)=x<=200 ? 1.05 : x<=300? (1/0) : x<=550? 0.65 : x<=650 ? (1/0) : x<=1200 ? 0.46 : x<=1300 ? (1/0) : x<=1850? 0.4 : x<=1950 ? (1/0) : x<=3150 ? 0.31: x<=3250? (1/0) : 0.22
and sampling of 10, get
where gaps have size of 222.22 (i have added labels make easy compute gap sizeΔ), sampling of 1000, get
where gaps have size 101.1, close value of 100 specified in function.
to use functions this, therefore, use model , set gap size value small enough appear non-existent on final graph (notice on graph 0 6000, can barely see gap size of 10), , set samples reasonably high.
with function approach, don't know of way add filled , open dots if desired.
† gnuplot version 5.1 (the current development version) supports pointtype variable
option can simplify to
plot last=0,\ datafile u 1:2:(oldlast=last,last=$1,$1==oldlast?6:7) w linespoints pt var lt 1
here plot points, use same test before select between pointtype 7 or 6. can both point types @ once, can use linespoints style instead of doing 2 separate plots.
‡ initializing last value less first x-coordinate cause first point filled.
Δ draw these labels, in first case (with set xrange[0:1000]
, set samples 10
), used
plot f(x),\ "+" u 1:(f($1)+0.1):(abs($1-250)<150||abs($1-600)<160?sprintf("%0.2f",$1):"") w labels
and in case of set samples 1000
plot f(x),\ "+" u 1:(f($1)+0.1):(abs($1-250)<51||abs($1-600)<51?sprintf("%0.2f",$1):"") w labels
it takes little playing around bounds on abs
functions here desired labels appear. examining output using set table
can helpful getting them right.
Comments
Post a Comment