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

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:

Related

Gnuplot - plotting label with different lines in hypertext

Having the following text file
0 0 net0 aaaa bbbb cccc
1 1 net1 zzz
2 2 net2 xxx
3 3 net3 yyy
4 5 net4 ttt 0 0
5 5 net5
I need to plot all points described by the first two columns as x,y coordinates and anchoring the informations reported in the following columns (say 3:6) at each point.These info have to be plot separated by newlines, e.g. the point in (0,0) should report (when mouse over it)
net0
aaaa
bbbb
cccc
The script I'm using is the following but it works only with three columns
set terminal canvas enhanced mousing
set termoption enhanced
set label at 0,0 "Origin"
set title 'mouse over points'
plot 'test.txt' using 1:2:3 with labels hypertext point pt 7 ps var lc rgb "black"
It seems that the datafile modifier using works only with three entries.
Any help?
It is unfortunate that your text is not surrounded by "". Nevertheless, you can handle your issue with gnuplot without any external tool.
You didn't specify whether your data columns are separated by TAB or by space.
In the following, I assume that they are separated by single space (code needs to be adapted accordingly if not).
Procedure:
Read the data as full line by setting set datafile separator "\n"
extract the numbers with word()
take the rest of the line as your label text
replace spaces by '\n'
Code:
### Hypertext with columns
reset session
$Data <<EOD
0 0 net0 aaaa bbbb cccc
1 1 net1 zzz
2 2 net2 xxx
3 3 net3 yyy
4 5 net4 ttt 0 0
5 5 net5
EOD
# replace function
# replaces string s1 by string s2 in string s
Replace(s,s1,s2) = (RP_s="", RP_n=1, (sum[RP_i=1:strlen(s)] \
((s[RP_n:RP_n+strlen(s1)-1] eq s1 ? (RP_s=RP_s.s2, RP_n=RP_n+strlen(s1)) : \
(RP_s=RP_s.s[RP_n:RP_n], RP_n=RP_n+1)), 0)), RP_s)
set datafile separator "\n"
GetNumber(n) = real(word(strcol(1),n))
GetText(s) = (s[strstrt(s," ")+1:])[strstrt(s[strstrt(s," ")+1:]," ")+1:]
TextToColumn(s) = Replace(GetText(s),' ','\n')
plot $Data u (GetNumber(1)):(GetNumber(2)):(TextToColumn(strcol(1))) w labels hypertext \
point pt 7 ps 3 lc rgb "red" notitle
### end of code
Result:

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.

gnuplot: mark/highlight area (part of linegraph)

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

Gnuplot: Multiple Stacked Histograms, each group using the same key

I am trying to create a plot with multiple stacked histograms like example 8 here. But for my data, each group has the same four categories.
How do I change the colors and the key so that colors go Red, Green, Blue, Pink for every stacked column? And so the key only has one copy each of the 4 things I am plotting?
Here is the line I'm using to plot:
plot newhistogram "1", 'addresses.dat' using 2:xtic(1) t 2, '' u 3 t 3, \
'' u 4 t 4, '' u 5 t 5, newhistogram "2", '' u 6 t 6, '' u 7 t 7, '' u 8 t 8,\
'' u 9 t 9
My data is in the same format as the example I linked to above:
Address PAL_Code BASH App Kernel PAL_Code BASH App Kernel
FFT 1 1 2 2 1 1 3 4
RADIX 1 2 3 4 1 2 4 5
LU 1 3 4 5 1 3 5 6
Thank you so much if you can help!
use the ltspecifier behind newhistogram in order to specify the first color gnuplot should use. I wrote a little script that might does what you want;)
set style data histogram
set style histogram rowstack gap 1
set style fill solid border -1
set boxwidth 0.9
set key autotitle columnheader
set key outside below center horizontal
plot newhistogram "1" lt 1, 'addresses.dat' u 2:xtic(1), '' u 3, '' u 4, '' u 5,\
newhistogram "2" lt 1, 'addresses.dat' u 6:xtic(1) notitle, '' u 7 notitle, \
'' u 8 notitle, '' u 9 notitle
Hope that helps
Cherio
Woltan

Resources