How can I draw arrows between circles where
the arrows point to the centers of the circles,
but have reduced length such that they only touch the circumference,
independent of the terminal size ratio?
Sounds easy, but I haven't found a shorter solution than the example below. You need to to some coordinate transformations between axes coordinates and terminal coordinates.
For this, you need to know the terminal size of the plot and you'll get these values into the GPVAL_... variables only after plotting you have to do a dummy plot first and then replot.
If I overlooked some obvious and simpler procedure, please let me know.
Code:
### arrows touching circles
reset session
# Factor between axes and terminal coordinates
FactorX(n) = real(GPVAL_X_MAX-GPVAL_X_MIN)/(GPVAL_TERM_XMAX-GPVAL_TERM_XMIN)
FactorY(n) = real(GPVAL_Y_MAX-GPVAL_Y_MIN)/(GPVAL_TERM_YMAX-GPVAL_TERM_YMIN)
# Axis coordinates to terminal coordinates
AxisToTermX(x) = (x-GPVAL_X_MIN)/FactorX(0)+GPVAL_TERM_XMIN
AxisToTermY(y) = (y-GPVAL_Y_MIN)/FactorY(0)+GPVAL_TERM_YMIN
xt(x) = AxisToTermX(x)
yt(y) = AxisToTermY(y)
rt(r) = r/FactorX(0)
Lt(x1,y1,x2,y2) = sqrt((xt(x2)-xt(x1))**2 + (yt(y2)-yt(y1))**2)
# terminal coordinates reduced by radii
x1tr(x1,y1,r1,x2,y2,r2) = rt(r1)*(xt(x2)-xt(x1))/Lt(x1,y1,x2,y2)+xt(x1)
y1tr(x1,y1,r1,x2,y2,r2) = rt(r1)*(yt(y2)-yt(y1))/Lt(x1,y1,x2,y2)+yt(y1)
x2tr(x1,y1,r1,x2,y2,r2) = (Lt(x1,y1,x2,y2)-rt(r2))*(xt(x2)-xt(x1))/Lt(x1,y1,x2,y2) + xt(x1)
y2tr(x1,y1,r1,x2,y2,r2) = (Lt(x1,y1,x2,y2)-rt(r2))*(yt(y2)-yt(y1))/Lt(x1,y1,x2,y2) + yt(y1)
# Terminal coordinates to axis coordinates
TermToAxisX(xt) = real(xt-GPVAL_TERM_XMIN)*FactorX(0)+GPVAL_X_MIN
TermToAxisY(yt) = real(yt-GPVAL_TERM_YMIN)*FactorY(0)+GPVAL_Y_MIN
# axis coordinates reduced by radii
x1r(x1,y1,r1,x2,y2,r2) = TermToAxisX(x1tr(x1,y1,r1,x2,y2,r2))
y1r(x1,y1,r1,x2,y2,r2) = TermToAxisY(y1tr(x1,y1,r1,x2,y2,r2))
x2r(x1,y1,r1,x2,y2,r2) = TermToAxisX(x2tr(x1,y1,r1,x2,y2,r2))
y2r(x1,y1,r1,x2,y2,r2) = TermToAxisY(y2tr(x1,y1,r1,x2,y2,r2))
# dummy plot
set xrange [-10:10]
set yrange [-10:10]
plot NaN notitle
$Data <<EOD
0 0 1.0
-6 2 3.0
0 5 0.75
7 -8 2.0
5 8 1.5
EOD
N = |$Data| # length of datablock
# draw N circles
do for [i=0:N-1] {
set obj i+1 circle at word($Data[i+1],1),word($Data[i+1],2) size word($Data[i+1],3) fc "blue"
}
# draw N arrows
do for [i=0:N-1] {
x1 = word($Data[i+1],1)
y1 = word($Data[i+1],2)
r1 = word($Data[i+1],3)
x2 = word($Data[(i+1)%N+1],1)
y2 = word($Data[(i+1)%N+1],2)
r2 = word($Data[(i+1)%N+1],3)
set arrow i+1 from x1r(x1,y1,r1,x2,y2,r2), y1r(x1,y1,r1,x2,y2,r2) \
to x2r(x1,y1,r1,x2,y2,r2), y2r(x1,y1,r1,x2,y2,r2) heads lc "red"
}
replot
### end of code
Result: (wxt size 600,600)
The same code with (wxt size 700,300)
How would you make a symlog plot in gnuplot?
matplolib has such a feature:
I'm thinking about some axis + tics manipulation or multiplot where on panel has reversed axis.
Finally, I need this for the z axis (cbrange) the show the residuals as an image.
symlog(x) = (-1 < x && x < 1) ? x/10. \
: (x < 0) ? -log(-x) - 0.1 \
: log(x) + 0.1
invsymlog(x) = (-0.1 < x && x < 0.1) ? x*10. \
: (x < 0) ? -exp(-(x+0.1)) \
: exp(x-0.1)
set xlabel "Symlog axis"
set nonlinear x via symlog(x) inv invsymlog(x)
set xrange [-4*pi : 4*pi]
set sample 500
set xtics -10,1,10 nomirror
set xtics add ("//" 0)
set xtics font ",10"
plot x*cos(x)
The region between -1 and +1 is linear, the rest is log scale.
In the figure below, each row corresponds to a different case/parameter. Parameters from top to bottom are nmesh-2, nmesh-4, nmesh-6, nmesh-8. I would like to write each parameter to the left of ylabel or Elapsed time. In other words, I want a "row title". It would also be nice if parameter name was bigger than and rotated as Elapsed time. My code includes filenames but in case I included it as well.
set key autotitle columnhead
set boxwidth 0.5
set style fill transparent solid
set nokey
set terminal wxt size 1900,990
set multiplot layout 4, 7
set xtics rotate by -45
np = "8 12 16 20 24 28 32"
do for [IDX=1:7] {
if (IDX == 1) {
set ylabel 'Elapsed time'
}
else {
unset ylabel
}
set title sprintf("np-%s", word(np, IDX))
plot sprintf("run-1/np-%s/nmesh-2/load-estim-0/hole-cut-implicit/cpupertask-3/ncell-11/dominant-0.dat", word(np, IDX)) u 2:xtic(1) with boxes
}
set notitle
do for [IDX=1:7] {
if (IDX == 1) {
set ylabel 'Elapsed time'
}
else {
unset ylabel
}
plot sprintf("run-1/np-%s/nmesh-4/load-estim-0/hole-cut-implicit/cpupertask-3/ncell-11/dominant-0.dat", word(np, IDX)) u 2:xtic(1) with boxes
}
do for [IDX=1:7] {
if (IDX == 1) {
set ylabel 'Elapsed time'
}
else {
unset ylabel
}
plot sprintf("run-1/np-%s/nmesh-6/load-estim-0/hole-cut-implicit/cpupertask-3/ncell-11/dominant-0.dat", word(np, IDX)) u 2:xtic(1) with boxes
}
do for [IDX=1:7] {
if (IDX == 1) {
set ylabel 'Elapsed time'
}
else {
unset ylabel
}
plot sprintf("run-1/np-%s/nmesh-10/load-estim-0/hole-cut-implicit/cpupertask-3/ncell-11/dominant-0.dat", word(np, IDX)) u 2:xtic(1) with boxes
}
Perhaps the easiest approach to do this would be to use a multiline y label:
set ylabel "nmesh-2\n\nElapsed time"
However, the flexibility of this solution is rather limited. As an alternative, one might use set multiplot with the margins option in order to make sure that there is enough space for the "row titles" in the global left margin of the entire multiplot, calculate the coordinates of the individual "row titles" in screen coordinates manually and render them within the last plot:
set terminal pngcairo size 1900,990 enhanced
set output 'fig.png'
numOfRows = 4
marginLeft = 0.1
marginRight = marginLeft/2
marginV = 0.1
plotSpacing = marginV / 2
plotHeight = (1. - 2*marginV - (numOfRows-1)*plotSpacing) / numOfRows
labelPos(i) = 1. - (marginV + plotHeight/2 + i*(plotHeight + plotSpacing))
params = "nmesh-2 nmesh-4 nmesh-6 nmesh-8"
set multiplot layout numOfRows,7 margins marginLeft,1-marginRight,marginV,1-marginV spacing plotSpacing
set key autotitle columnhead
set boxwidth 0.5
set style fill transparent solid
set nokey
set xtics rotate by -45
np = "8 12 16 20 24 28 32"
do for [IDX=1:7] {
if (IDX == 1) {
set ylabel 'Elapsed time'
}
else {
unset ylabel
}
set title sprintf("np-%s", word(np, IDX))
plot sin(x) w l
}
set notitle
do for [IDX=1:7] {
if (IDX == 1) {
set ylabel 'Elapsed time'
}
else {
unset ylabel
}
plot sin(x) w l
}
do for [IDX=1:7] {
if (IDX == 1) {
set ylabel 'Elapsed time'
}
else {
unset ylabel
}
plot sin(x) w l
}
do for [IDX=1:7] {
if (IDX == 1) {
set ylabel "Elapsed time"
}
else {
unset ylabel
}
if (IDX == 7) {
do for [j=1:4] {
set label word(params, j) at screen marginLeft/2, screen labelPos(j-1) offset char -2, 0 center rotate by 90 font "Arial,16"
}
}
plot sin(x) w l
}
This should yield:
I have a CSV file with data like:
name,age
raju,23
anju,34
manju,56
sanju,56
I'm trying to generate a pie chart using gnuplot.
Here's the command I'm executing:
#!/usr/bin/gnuplot -persist
reset
set terminal wxt
unset key
set datafile separator ","
set xlabel "USERS"
set ylabel "AGE"
plot 'file.csv' using ($0):2:($0):xticlabels(1) with circles lc variable notitle
What am I doing wrong?
Apparently, Gnuplot does not support pie charts yet; but we can draw it by hand.
First, we need to obtain the angles and percentages related to the second column in your datafile:
set datafile separator ','
stats 'file.csv' u 2 noout # get STATS_sum (sum of column 2)
ang(x)=x*360.0/STATS_sum # get angle (grades)
perc(x)=x*100.0/STATS_sum # get percentage
Then configure the canvas:
set size square # square canvas
set xrange [-1:1.5]
set yrange [-1.25:1.25]
set style fill solid 1
unset border
unset tics
unset key
and draw the pie chart:
Ai = 0.0; Bi = 0.0; # init angle
mid = 0.0; # mid angle
i = 0; j = 0; # color
yi = 0.0; yi2 = 0.0; # label position
plot 'file.csv' u (0):(0):(1):(Ai):(Ai=Ai+ang($2)):(i=i+1) with circle linecolor var,\
'file.csv' u (1.5):(yi=yi+0.5/STATS_records):($1) w labels,\
'file.csv' u (1.3):(yi2=yi2+0.5/STATS_records):(j=j+1) w p pt 5 ps 2 linecolor var,\
'file.csv' u (mid=Bi+ang($2)*pi/360.0, Bi=2.0*mid-Bi, 0.5*cos(mid)):(0.5*sin(mid)):(sprintf('%.0f (%.1f\%)', $2, perc($2))) w labels
The first line in the plot command draws the pie chart, where the columns (0):(0):(1):(Ai):(Ai=Ai+ang($2)):(i=i+1) are:
columns 1-2: x and y coordinates of the center of the disk
column 3: radius of the disk
column 4-5: begin and end angles of the region
column 6: color of the region
The second and third lines in the plot command place the labels, and the last line puts the percentages in the middle of each region.
The result:
References: (1) Gnuplot surprising (2) Gnuplot tricks
EDIT:
Based on two related questions (this and this), a new script is proposed:
filename = 'test.csv'
rowi = 1
rowf = 7
# obtain sum(column(2)) from rows `rowi` to `rowf`
set datafile separator ','
stats filename u 2 every ::rowi::rowf noout prefix "A"
# rowf should not be greater than length of file
rowf = (rowf-rowi > A_records - 1 ? A_records + rowi - 1 : rowf)
angle(x)=x*360/A_sum
percentage(x)=x*100/A_sum
# circumference dimensions for pie-chart
centerX=0
centerY=0
radius=1
# label positions
yposmin = 0.0
yposmax = 0.95*radius
xpos = 1.5*radius
ypos(i) = yposmax - i*(yposmax-yposmin)/(1.0*rowf-rowi)
#-------------------------------------------------------------------
# now we can configure the canvas
set style fill solid 1 # filled pie-chart
unset key # no automatic labels
unset tics # remove tics
unset border # remove borders; if some label is missing, comment to see what is happening
set size ratio -1 # equal scale length
set xrange [-radius:2*radius] # [-1:2] leaves space for labels
set yrange [-radius:radius] # [-1:1]
#-------------------------------------------------------------------
pos = 0 # init angle
colour = 0 # init colour
# 1st line: plot pie-chart
# 2nd line: draw colored boxes at (xpos):(ypos)
# 3rd line: place labels at (xpos+offset):(ypos)
plot filename u (centerX):(centerY):(radius):(pos):(pos=pos+angle($2)):(colour=colour+1) every ::rowi::rowf w circle lc var,\
for [i=0:rowf-rowi] '+' u (xpos):(ypos(i)) w p pt 5 ps 4 lc i+1,\
for [i=0:rowf-rowi] filename u (xpos):(ypos(i)):(sprintf('%05.2f%% %s', percentage($2), stringcolumn(1))) every ::i+rowi::i+rowi w labels left offset 3,0
This new code results in:
How do I draw a vertical plane that is represented by:
x + y = 1
^
|
1y | \
| \
| \ <-- this vertical plane
| \
| \
<-----------------------+----------------------->
-1x | -1x
|
|
|
-1y |
|
v
Additionally I need to display multiple complex 3D equations (without parametric) at the same time.
You can use parametric to plot your 3D equations like this:
f(x,y) = sin(x**2 + y**2)/(x**2 + y**2)
set parametric
splot u,v,f(u,v)
Together with the plane, a full script could look as follows:
set parametric
f(x,y) = sin(x**2 + y**2)/(x**2 + y**2)
const = 5
set xrange [-5:5]
set yrange [-5:5]
set ticslevel 0
splot u,const-u,v title 'plane', u,v,f(u,v) title '3D equation'
For you real use case you might need to scale the v used as z-axis of the plane and maybe also the urange and vrange.