4

I would like to plot a curve with a variable line width. I normally would do the following if I wanted to use points instead of a line:

gnuplot> plot 'curve.dat' u ($1):($2):($1) ps var

where curve.dat is filled with:

0  0
1  1
2  4
3  9
4  16
5  25

and so on. Now if I try something similar for the line width:

gnuplot> plot 'curve.dat' u ($1):($2):($1) lw var

I get the error message:

undefined variable: var

Or is this something that cannot be done with gnuplot?

G. LC
  • 794
  • 1
  • 8
  • 27

3 Answers3

3

You're right that linewidth doesn't accept var like pointsize does. But you can have a similar effect by using filledcurves:

WIDTH_FACTOR=20
plot 'curve.dat' u ($1):($2+$1/WIDTH_FACTOR):($2-$1/WIDTH_FACTOR) w filledcurves

1

Gavin Portwood
  • 1,217
  • 8
  • 9
  • What a beautiful loop hole, I couldn't find anything in the Gnuplot docs which would help, but this is great. I appreciate it. – G. LC Sep 11 '18 at 02:42
1

This addresses a problem with Gavin’s answer: his method creates a certain line height (as opposed to line width). I found a different way, which works with widths.

enter image description here

The defects in my solution: one needs to know the “coordinate space aspect ratio” in advance, and there are artifacts at joins.

Ilya Zakharevich
  • 1,210
  • 1
  • 9
  • 6
1

So far, there is no variable linewidth in gnuplot. Furthermore, if your data has N points you will have N-1 lines, although, you give N linewidths in your data. Which linewidth of which data point should be skipped? The first one or the last one? If you draw tapered lines you don't have this problem. You can use filledcurves for this, but as @Ilya Zakharevich mentioned, @Gavin Portwood's solution is actually plotting a line height, not a line width.

The solution below is using filledcurves as well, but plotting real linewidths. For this, you have to go to pixel coordinates, do some calculations and go back to axis coordinates (will not yet work for log scale). gnuplot can easily fill curves between two y-values with identical x-values, which, however, would not help here. But gnuplot can also fill closed curves. Hence, the script is creating a closed curve by first creating the "left" outline of the path and then the reversed "right" outline of the path. Since the script uses indexing of datablocks it requires gnuplot>=5.2.0.

Script: (works with gnuplot>=5.2.0, Sept. 2017)

### variable linewidth / tapered lines plot 
reset session

$Data <<EOD
1   1    1.0
9   2   25.0
2   3   15.0
4   2    5.0
7   4    5.0
3   7    1.0
2   5   25.0
4   4    3.0
7   7   30.0
9   4   80.0
EOD

set size ratio -1
set angle degrees
set key noautotitle

# plot data to get GPVAL_... values
plot $Data u 1:2 w l
 
# terminal constants
xmin   = GPVAL_X_MIN
ymin   = GPVAL_Y_MIN
xtmin  = GPVAL_TERM_XMIN
ytmin  = GPVAL_TERM_YMIN
Factor = GPVAL_VERSION==5.2 && int(GPVAL_PATCHLEVEL)<=7 ? \
         GPVAL_TERM eq "wxt" ? 20 : GPVAL_TERM eq "qt" ? 10 : 1 : 1
Rxaupu = (GPVAL_X_MAX-xmin)/(GPVAL_TERM_XMAX-xtmin)*Factor   # x ratio axes units to pixel units
Ryaupu = (GPVAL_Y_MAX-ymin)/(GPVAL_TERM_YMAX-ytmin)*Factor   # y
 
ax2px(x)     = (x-xmin)/Rxaupu  + xtmin   # x axes coordinates to pixel coordinates
ay2py(y)     = (y-ymin)/Ryaupu  + ytmin   # y
px2ax(x)     = (x-xtmin)*Rxaupu + xmin    # x pixel coordinates to axes coordinates
py2ay(y)     = (y-ytmin)*Ryaupu + ymin    # y
 
# convert into pixel coordinates
set table $PixelCoords
    plot $Data u (ax2px($1)):(ay2py($2)):3 w table
unset table

# various functions
x(i)            = word($PixelCoords[i],1)
y(i)            = word($PixelCoords[i],2)
lw(i)           = word($PixelCoords[i],3)
a(i,j)          = a2(x(i),y(i),x(j),y(j))
a2(x0,y0,x1,y1) = atan2(y1-y0,x1-x0)+90
dx(i)           = lw(i)*0.5*cos(a)
dy(i)           = lw(i)*0.5*sin(a)

set print $Outlines
    do for [i=1:|$PixelCoords|-1] {
        a  = a(i,i+1)
        do for [j=i:i+1] {
            print sprintf("%g %g", px2ax(x(j)+dx(j)), py2ay(y(j)+dy(j)))
        }
    }
    do for [i=|$PixelCoords|:2:-1] {
        a = a(i,i-1)
        do for [j=i:i-1:-1] {
            print sprintf("%g %g", px2ax(x(j)+dx(j)), py2ay(y(j)+dy(j)))
        }
    }
set print

set style fill solid 1.0 noborder
set grid x,y

plot $Outlines u 1:2 w filledcurves fc "web-green"
### end of script

Result:

enter image description here

theozh
  • 22,244
  • 5
  • 28
  • 72