gnuplot: mark/highlight area (part of linegraph) - graph

my data is quite simple, just a timestamp and a number like this:
2013-01-23 08:27:55 2801
2013-01-23 08:33:13 2801
2013-01-23 08:38:31 2660
2013-01-23 08:43:49 2785
2013-01-23 08:49:07 2785
I get the data from a another system. Space between date and time, and tabulator between "date time" and the number.
The whole time window is a few hours .. a couple of days. This overall time window contains one or more interesting parts (typically few..several hours), and I would like to mark or highlight these interesting parts somehow to make it easier and faster to analyse the graphs.
Th einteresting time window would need to be specified manually, e.g. from 2014-01-23 10:00:00 to 2013-01-24 12:00:00 for 2 hour window.
Drawing a rectancle to the background of the linegraph is one possibility, and changing the line color (or something similar) is another.
How can I do that from manually/separately defined time stamps? The best I was able to find was splitting the data with empty lines, and use something like this (from http://www.gnuplotting.org/introduction/plotting-data/):
set style line 1 lc rgb '#0060ad' lt 1 lw 2 pt 7 ps 1.5 # --- blue
set style line 2 lc rgb '#dd181f' lt 1 lw 2 pt 5 ps 1.5 # --- red
plot 'plotting-data3.dat' index 0 with linespoints ls 1, '' index 1 with linespoints ls 2
But splitting the data is a bit arduous (?); I'm looking for elegant gnuplot means to achive the goal. Robust splitting could be possible as well, if thats really the best alternative.
Below is the plotting function, works well but I'd like to mark/highlight selected parts of the graph.
-Paavo
function my_gnuplot {
if [ $# -ne 3 -o -z "$1" -o -z "$2" -o -z "$3" ]
then
echo $0 $FUNCNAME Invalid parameters, exiting
exit 3
fi
sid="$1" ; shift
stime="$1" ; shift
etime="$1" ; shift
if [ $sid -gt 0 -a $sid -lt 10 ]
then
title=0$sid
else
title=$sid
fi
gnuplot <<- EOF
reset
set terminal png size 1800,900 enhanced font myfont.ttf 10
set xdata time
set timefmt "%Y-%m-%d %H:%M:%S"
set format x "%Y-%m-%d %H:%M"
set title "SID=$title from $stime to $etime"
set grid
set xrange [ "$stime" : "$etime" ]
set yrange [ -2000 : 6000 ]
set style data linespoints
plot "sid_data_$sid.txt" using 1:9 notitle
EOF
}

You can use rectangles to fill the space pretty easily:
set xdata time
set timefmt '%Y-%m-%d %H:%M:%S'
set object 1 rectangle from "2013-01-23 08:33:13",graph 0 to "2013-01-23 08:43:49",graph 1 fs solid fc rgb "red" behind
plot 'test.dat' u 1:3 w lines ls -1

Related

How to plot a tree/graph/web with weighted edges in Gnuplot?

i am plotting a tree in gnuplot as discussed here (How to plot tree/graph/web data on gnuplot?). However, i would like to include the edges weight of the tree, i.e. for each edge i have a number (e.g. 10, 20, 30, 40) that represents the edge weight. The figure below shows in red the edges weight that i want to plot in gnuplot (i added this using power point).
Can anyone tell me how to plot edges with weight in gnuplot?
I would propose a slight variation on the answer which you mention in your question. Let's assume that the coordinates of the vertices are stored in a file pnts.dat as follows:
0 5 10
1 20 20
2 15 15
3 30 30
4 40 10
Here, the first column records the corresponding label, while second and third columns contain the x- and y-coordinate, respectively.
The edges could be defined in a separate file edges.dat as:
0 1 30 0 1
1 2 40 0 -2
1 4 20 0 1
1 3 10 0 1
Here, the first two column contain the point indices (they refer to the first column of pnts.dat). The third column records the weight of a particular edge. Finally, the last two columns contain the x,y displacement of the generated associated label.
With this, the Gnuplot script could look like:
set xr [0:50]
set yr [0:50]
set size square
flePnts = 'pnts.dat'
fleEdges = 'edges.dat'
loadEdges = sprintf('< gawk '' \
FNR==NR{x[$1]=$2;y[$1]=$3;next;} \
{printf "%%f\t%%f\n%%f\t%%f\n\n", x[$1], y[$1], x[$2], y[$2];} \
'' %s %s', flePnts, fleEdges);
loadWeights = sprintf('< gawk '' \
FNR==NR{x[$1]=$2;y[$1]=$3;next;} \
{printf "%%f\t%%f\t%%s\n", (x[$1]+x[$2])/2 + $4, (y[$1]+y[$2])/2 + $5, $3} \
'' %s %s', flePnts, fleEdges);
plot \
loadEdges using 1:2 with lines lc rgb "black" lw 2 notitle, \
flePnts using 2:3:(0.6) with circles fill solid lc rgb "black" notitle, \
flePnts using 2:3:1 with labels tc rgb "white" font "Arial Bold" notitle, \
loadWeights using 1:2:3 with labels tc rgb "red" center font "Arial Bold" notitle
the loadEdges command invokes gawk in order to generate for all edges the corresponding pairs of x/y coordinates (delimited by a blank line)
loadWeights calculates for each edge the middle point and places a label at these coordinates (taking into account the required offset)
Finally, one obtains:
Addicionally, if you want to add arrows to the edges, you have to do these steps:
Add the arrow style:
set style arrow 1 head filled size screen 0.025,10,40 lc rgb "black" lw 2
Change the command with lines for with vectors
loadEdges using 1:2:3:4 with vectors arrowstyle 1 notitle, \
The following image show you the final result:
And this is the final code:
set xr [0:50]
set yr [0:50]
set size square
set style arrow 1 head filled size screen 0.025,10,40 lc rgb "black" lw 2
flePnts = 'pnts.dat'
fleEdges = 'edges.dat'
loadEdges = sprintf('< gawk '' \
FNR==NR{x[$1]=$2;y[$1]=$3;next;} \
{printf "%%f\t%%f\t%%f\t%%f\n\n", x[$1], y[$1], (x[$2]-x[$1]), (y[$2]-y[$1]);} \
'' %s %s', flePnts, fleEdges);
loadWeights = sprintf('< gawk '' \
FNR==NR{x[$1]=$2;y[$1]=$3;next;} \
{printf "%%f\t%%f\t%%s\n", (x[$1]+x[$2])/2 + $4, (y[$1]+y[$2])/2 + $5, $3} \
'' %s %s', flePnts, fleEdges);
plot \
loadEdges using 1:2:3:4 with vectors arrowstyle 1 notitle, \
flePnts using 2:3:(0.6) with circles fill solid lc rgb "black" notitle, \
flePnts using 2:3:1 with labels tc rgb "white" font "Arial Bold" notitle, \
loadWeights using 1:2:3 with labels tc rgb "red" center font "Arial Bold" notitle
Here is a suggestion which resembles #ewcz's solution, i.e. using a list of IDs with x,y coordinates and a list of connections using two IDs.
However, with the following differences:
all data in one file (in two different blocks addressed with index)
a gnuplot-only solution without awk or gawk and hence platform-independent. A lookup list is created with gnuplot, similar to this answer.
individual label offsets with rotation angle dA and relative length dR between the points (dR=0: at center of connector, dR=-1: at starting point,dR=1: at end point). Because of this, is recommended to use set size ratio -1 such that e.g. a rotation by 45 degrees is visually 45 degrees in the graph.
Data: SO42447683.dat
# ID x y
0 5 10
1 20 20
2 15 15
3 30 30
4 40 10
# ID1 ID2 weight dA dR
0 1 30 7 0
1 2 40 20 0
1 4 20 0 0
1 3 10 0 0
Script: (works for gnuplot>=5.0.0, without option textbox it works with >=4.6.0)
### plot tree with different labels
reset
FILE = "SO42447683.dat"
set size ratio -1
set key noautotitle
set offsets 0.5,0.5,0.5,0.5
set angle degrees
set style textbox opaque noborder
IdIdxs = XYs = ' '
stats FILE u (IdIdxs=IdIdxs.sprintf("%s:%d ",strcol(1),$0), \
XYs=XYs.sprintf("%g %g ",$2,$3)) index 0 nooutput
Px(i) = real(word(XYs,2*i+1))
Py(i) = real(word(XYs,2*i+2))
getIdx(col) = (c0=strstrt(IdIdxs,sprintf(" %s:",strcol(col))), \
c1=strstrt(IdIdxs[c0+1:],' ')+c0, \
s0=IdIdxs[c0:c1], c2=strstrt(s0,':'), int(s0[c2+1:]))
getLxy(colA,colR) = (idx0=getIdx(1), x0=Px(idx0),y0=Py(idx0), \
idx1=getIdx(2), x1=Px(idx1),y1=Py(idx1), \
rm = sqrt((x1-x0)**2+(y1-y0)**2)*(column(colR)+1)*0.5, \
a = atan2(y1-y0,x1-x0)+column(colA), \
Ly = y0+rm*sin(a), Lx=x0+rm*cos(a))
plot FILE index 1 u (idx0=getIdx(1),x0=Px(idx0)):(y0=Py(idx0)): \
(idx1=getIdx(2),Px(idx1)-x0):(Py(idx1)-y0) w vec lw 2 lc rgb "black" nohead, \
'' index 0 u 2:3 w p pt 7 ps 4 lc rgb "white",\
'' index 0 u 2:3 w p pt 6 ps 4 lc rgb "black",\
'' index 0 u 2:3:1 w labels, \
'' index 1 u (getLxy(4,5)):(Ly):3 w labels tc rgb "red" boxed
### end of script
Result:

gnuplot Heatmap with label and score from different columns data

I have created heatmap graphs using gnuplot.
I have data.dat:
avail reli perf
stop 181 20 121 10 34 20
jitter 18 20 17 20 13 20
limp 12 20 5 30 20 20
and gnuplot script:
set term pos eps font 20
unset key
set nocbtics
set cblabel "Score"
set cbtics scale 0
set cbrange [ 0.00000 : 110.00000 ] noreverse nowriteback
set palette defined ( 0.0 "#FFFFFF",\
1 "#FFCCCC",\
20.2 "#FF9999 ",\
30.3 "#FF6666",\
40.4 "#FF3333",\
50.5 "#FF0000",\
60.6 "#CC0000",\
70.7 "#C00000",\
80.8 "#B00000",\
90.9 "#990000",\
100.0 "#A00000")
set title "Faults"
set ylabel "Hardware Faults"
set xlabel "Aspects"
set size 1, 0.5
set output 'c11.eps'
YTICS="`awk 'BEGIN{getline}{printf "%s ",$1}' 'data2.dat'`"
XTICS="`head -1 'data2.dat'`"
set for [i=1:words(XTICS)] xtics ( word(XTICS,i) i-1 )
set for [i=1:words(YTICS)] ytics ( word(YTICS,i) i-1 )
plot "<awk '{$1=\"\"}1' 'data2.dat' | sed '1 d'" matrix w image, '' matrix using 1:2:($3==0 ? " " : sprintf("%.1d",$3)) with labels
#######^ replace the first field with nothing
################################## ^ delete first line
My output is:
Here I have range 1-20,30-39,...,100 or more)
Now I have to 2 values in every axis. e.g stop and avail have(181 and 20). the 181 is the count and 20 is percentages. I want to create graphs which have colors base on percentages and the labels on my graphs from the counts of data.
I have experienced create some graph using for and do some modulo to select the data. But here, I have not idea to create that graphs. Any suggestion for creating this? Thanks!
You can use every to skip columns.
plot ... every 2 only uses every second column, which is what you can use for the labels. For the colors, you must start with the second column (numbered with 1), and you need every 2::1.
Following are the relevant changes only to your script:
set for [i=1:words(XTICS)] xtics ( word(XTICS,i) 2*i-1 )
plot "<awk '{$1=\"\"}1' 'data2.dat' | sed '1 d'" matrix every 2::1 w image, \
'' matrix using ($1+1):2:(sprintf('%d', $3)) every 2 with labels
The result with 4.6.5 is:

gnuplot: with x and y-axis label (rowstacked) with row and column names

I haven't answer the question after I google it.
I have data.txt like this:
a b c
sys1 3 2 0
sys2 4 4 4
sys3 5 2 4
sys4 6 4 1
I created graphs using rowstacked style with pattern, currently I select the patterns manually. I have to plotting my data.txt with sys1-sys4 and a-c. This matrix always have the same size, but I should do sorting and re generate with different order sequence.
this is my gnuplot script:
set term pos eps font 20
set style data histogram
set style histogram rowstacked
set key invert reverse right outside # above outside or left outside
set boxwidth 0.75
set ylabel "Count"
set xlabel "System"
set xtics nomirror rotate by -270
set output 'eps/a1-count.eps'
plot 'a1-count' \
using($2):xtic(1) title "data 1" lt -1 fs pattern 3, \
'' using($3) title "data 2" lt -1 fs pattern 4, \
'' using($3) title "data 3" lt -1 fs pattern 6
and this is the output:
I also found some solution here but it is for heat map. Anyone can help me?
Thanks a lot!
you can sort directly the data within gnuplot : (-nk[column]), with linux 'sort' command:
plot '<sort -nk1 data.txt' \
u 2:xtic(1) title "data 1" lt -1 fs pattern 3, \
'' u 3 title "data 2" lt -1 fs pattern 4, \
'' u 3 title "data 3" lt -1 fs pattern 6
The '' empty string file call, will keep the sorted datafile.
the title of your question is not correct, but thanks to you, i learnd the :xtic(column) feature and the correct way of doing :
set xtics nomirror rotate by -270
Regards,

blt graph with interval window?

I have a blt real time graph in tcl/tk, the graph collects data over time with no time limit and it keeps storing all the data points into vectors and the user is able to scroll back and forth in the graph. The problem is that if I let the graph collect the points for a long period of time the cpu and memory consumption increases dramatically, i figure that for a 24 hour interval window should be fine. When i try to "unset x(0)" from the graph i get an error saying "command name invalid" i also try with "x delete 0" and same thing. Any help is much appreciated
This is how i initialize the graph:
proc startGraph {} {
global btnColor
global backColor
global startTime
global txtActionLevel
global txtAlertLevel
global x y1 y2 flagTime inStart inTime vectorFlag
global resolution
global notFirstTime
global txtActionLevel
set notFirstTime 0
set resolution 0
# Create stripchart widget
blt::stripchart .s -width 625 -height 330 -background $backColor -plotbackground black -font defaultFont
scrollbar .scroll -command { ScrollToEnd
.s axis view x } -orient horizontal -relief flat -background black -troughcolor $backColor -activebackground black -elementborderwidth 5
.s axis configure x -scrollcommand { .scroll set }
# Create BLT vectors
blt::vector create x
blt::vector create y1
blt::vector create y2
set startTime 0
set flagTime 0
set inStart -1
set inTime 0
set vectorFlag 0
.s configure -borderwidth 0 \
-leftmargin 0 \
-rightmargin 0 \
-plotborderwidth 0 \
-plotpadx {0 0} \
-plotpady {0 0}
.s legend configure -hide yes
.s grid configure -color gray \
-dashes 1 \
-minor 0 \
-hide 0
# X-axis
.s axis configure x -autorange 60 \
-shiftby 1 \
-stepsize 10 \
-subdivisions 1 \
-command FormatXLabel
# Alert txtAlertLevel
#.s tag create line -mapx 2 -mapy 2
proc FormatXLabel {widget x} {
set x [expr round($x)]
return [clock format $x -format "%I:%M:%S"]
}
# Y-axis
#.s axis configure y -title "C o u n t s"
image create photo .countsIcon -format PNG -file counts.png
label .titleGraph -image .countsIcon -background $backColor
place .titleGraph -in .measureView -x 0 -y 160
# Particles
.s element create Particles -symbol {} -color yellow -linewidth 1 \
-smooth linear -xdata x -ydata y1
# Bio
.s element create Bio -symbol {} -color red -linewidth 1 \
-smooth linear -xdata x -ydata y2
.s marker create line -name actionLine -coords {-Inf $txtActionLevel Inf $txtActionLevel} -linewidth 1 -outline orange
.s marker create line -name alertLine -coords {-Inf $txtAlertLevel Inf $txtAlertLevel} -linewidth 1 -outline green
place .s -in .measureView -x 10 -y 50
place .scroll -in .measureView -x 60 -y 380 -width 515 -height 35
#chartTime
}
this is where i add the values to the vectors:
set x(++end) [clock seconds]
set flagTime 0
set vectorFlag 1
set len [y1 length]
if {$len == 0} {
set startTime $x(end)
set y1(++end) $particle_sec
set y2(++end) $x_summary(bio_sec)
#if {$inStart < 0} {
# .s axis configure x -min "" -max ""
# set inStart 0
#}
} else {
set y1(++end) $particle_sec
set y2(++end) $x_summary(bio_sec)
}
puts "Vector length [x length]------"
puts "First value $x(0)----------"
#This is where i'm trying to catch whenever it reaches 60 seconds in this case
#when the length of the vector reaches 60 seconds it will unset the first value
#but it doesn't work it throws and invalid command name error
if {[x length] > 60} {
[unset -nocomplain x(0)]
}
#incr everyten
add_Result $particle_sec $bioSec [format "%.2f" $fv_eff]
for some odd reason when you use blt::vector create the "[unset -nocomplain x(0)]" doesn't seem to work, so i change it back to "x delete 0" without the square brackets and it works now.
When you put unset -nocomplain x(0) in [square brackets] and have it on its own like that, what you get is this:
It tries to unset that variable (I don't know if that will have problems; I don't use BLT vectors in my own code). There will be no errors from this. The result will be the empty string (it's documented).
It takes the result (an empty string) and uses it as a word of a command. The whole word, as you're not concatenating anything with it. The whole first word, in fact. You're going to try to evaluate the command whose name is the empty string, and pass it no other arguments. This is general Tcl semantics.
Now, creating a command with an empty name is legal, slightly tricky (because rename to an empty string deletes it — fully-qualified names are the workaround), and highly unusual. In your case, you've no such command and what you've really got is a bug. The bug? Those square brackets.
Use unset -nocomplain x(0) instead of [unset -nocomplain x(0)].
Note also that in many places online, when Tclers are putting Tcl code fragments inline in a place without fancy formatting, they'll put square brackets around the code. It's just a convention to make things easier to read. You shouldn't be seeing such things here on Stack Overflow.

Large grouped data plotting

I have a large amount of data to plot, and I'm trying to use gnuplot. The data is a sorted array of around 80000 elements. By simply using
plot "myData.txt" using 1:2 with linespoints linetype 1 pointtype 1
I get the output, but: it takes time to render, and the points are often cluttered, with occasional gaps. To address the second, I thought of doing the bar chart: each of the entries
would correspond to a bar. However, I'm not sure how to achieve this. I would like to have some space between consecutive bars, but I don't expect that it would be visible. What would be your suggestion to plot the data?
........................
Due to large data volume, I guess it's best to group.
Note that my data looks like
1 11041.9
2 11041.9
3 9521.07
4 9521.07
5 9520.07
6 9519.07
7 9018.07
...
I would like to plot the data by a groups of 3, ie., the first vertical line should start at 9521.07 as a minimum of the points from 1, 2, 3, and end at 11041. The second vertical line should consider the following 3 points: 4, 5 and 6, and start at 9519.07 with an end at 9521.07, and so on.
Could this be achieved with gnuplot, given the data file as illustrated? If so, I would appreciate if someone posts a set of commands I should use.
To reduce the number of points gnuplot actually draws, you can use the every keyword, e.g.
plot "myData.txt" using 1:2 with linespoints linetype 1 pointtype 1 every 100
will plot every 100th data point.
I am not sure if it's possible to do what you want (plotting vertical lines) elegantly within gnuplot, but here is my solution (assuming a UNIX-y environment). First make an awk script called sort.awk:
BEGIN { RS = "" }
{
# the next two lines handle the case where
# there are not three lines in a record
xval = $1 + 1
ymin = ymax = $2
# find y minimum
if ($2 <= $4 && $2 <= $6)
ymin=$2
else if ($4 <= $2 && $4 <= $6 && $4 != "")
ymin=$4
else if ($6 <= $2 && $6 <= $4 && $6 != "")
ymin=$6
# find y maximum
if ($2 >= $4 && $2 >= $6)
ymax=$2
else if ($4 >= $2 && $4 >= $6)
ymax=$4
else if ($6 >= $2 && $6 >= $4)
ymax=$6
# print the formatted line
print ($1+1) " " ymin " " ymin " " ymax " " ymax
}
Now this gnuplot script will call it:
set terminal postscript enhanced color
set output 'plot.eps'
set boxwidth 3
set style fill solid
plot "<sed 'n;n;G;' myData.txt | awk -f sort.awk" with candlesticks title 'pretty data'
It's not pretty but it works. sed adds a blank line every 3 lines, and awk formats the output for the candlesticks style. You can also try embedding the awk script in the gnuplot script.
You can do something like that...(it'll be easiest on unix). You will need to insert a space every third line -- I don't see any way around that. If you're on unix, the command
awk 'NR % 3 == 0 {print ""} 1' myfile
should do it. ( see How do I insert a blank line every n lines using awk? )
Of course, you could (and probably should) pack that straight into your gnuplot file.
So, all said and done, you'd have something like this:
xval(x)=int(x)/3 #Return the x position on the plot
plot "< awk 'NR % 3 == 0 {print ""} 1' datafile" using (xval($1)):2 with lines

Resources