Search code examples
gnuplot

How to get rid of small glitches in intersecting curves in gnuplot?


This is as much of a question as it is a thank you letter to theozh who has helped me a lot to create the figures I want in gnuplot.

I tried to get the best looking image of a plot they've shared a couple of times.

Here's my script

reset session
set output 'Wavy_curve.svg'

samps = 2500
set samples samps, samps
set isosamples samps, samps

f(x,y) = sin(1.3*x)*cos(0.9*y)+cos(.8*x)*sin(1.9*y)+cos(y*.2*x)
set table $Data01
    splot f(x,y)
unset table

g(x,y) = y
set table $Data02
    splot g(x,y)
unset table

h(x,y) = 0.5*x
set table $Data03
    splot h(x,y)
unset table

Zmin = -3
Zmax= 3

set xrange[-5:5]
set yrange[-5:5]
set zrange[Zmin:Zmax]
set hidden3d
set angle degree

Frac(z) = (z-Zmin)/(Zmax-Zmin)
# MyPalette01
Red01(z) = 65536 * ( Frac(z) > 0.75 ? 255 : int(255*abs(2*Frac(z)-0.5)))
Green01(z) = int(255*sin(180*Frac(z)))*256
Blue01(z) = int(255*cos(90*Frac(z)))
MyPalette01(z) =  Red01(z) + Green01(z) + Blue01(z) 

# MyPalette02
Red02(z)   = 65536 * int(255*Frac(z))
Green02(z) = 256 * (Frac(z) > 0.333 ? 255 : int(255*Frac(z)*3))
Blue02(z)  = (Frac(z) > 0.5 ? 255 : int(255*Frac(z)*2))
MyPalette02(z) =  Red02(z) + Green02(z) + Blue02(z) 

# MyPalette03
Red03(z)   = 65536 * (Frac(z) > 0.5 ? 255 : int(255*Frac(z)*2))
Green03(z) = 256 * (Frac(z) > 0.333 ? 255 : int(255*Frac(z)*3))  
Blue03(z)  = int(255*Frac(z)) 
MyPalette03(z) =  Red03(z) + Green03(z) + Blue03(z) 

set pm3d
set pm3d depthorder
set pm3d lighting primary 0.5 specular 0.2
set pm3d ftriangles
set style fill transparent solid 0.8 noborder 

unset colorbox

set view 44,316
splot $Data01 u 1:2:3:(MyPalette01($3)) w l lc rgb var notitle, \
      $Data02 u 1:2:3:(MyPalette02($3)) w l lc rgb var notitle, \
      $Data03 u 1:2:3:(MyPalette03($3)) w l lc rgb var notitle
### end of code 

And the result

Wavy curve

It took my poor laptop 16 hours to render, but I was satisfied with the result. I got a couple of glitches, it seems. This usually happens with these translucent plots. There is a darker circle at the bottom left. Barely noticeable, only with darker backgrounds. I think I'd need even more samples, but it gets ridiculously slow after a while. I only used 2500 to get the sharp intersections, 1000 is good enough for a single surface. I also got what looked like missing textures when I used 0.2 for the transparency, it got solved by increasing it to 0.8.

I used the svg terminal as the qt one gives ugly lines for these plots which needs increased transparency and still ends up with moire patterns. The wxt handles it better without the lines, but it doesn't give full transparency, it seems it can only show one intersection. Any tips to reduce the computing cost to get these kind of results?

Edit: With Ethan's answer, I got this result in only 30 seconds with the svg terminal. The new problem is that Inkscape really struggles to open the file which ended up being ~300MB in order to export it as a png, which is only 1.4MB. Is there another terminal which gives such nice results as svg, but which can output directly as png? Can the svg terminal directly output as png? I'll try to do the file conversion from the command line without opening the inkscape gui, but it's still not ideal given the large file size. Other wavy curve


Solution

  • I do not know what constraints or requirements you have for your plot, but I suspect you are making it much harder than necessary to get a smooth result.

    Here is a smooth version of approximately the same plot that executes in less than 2 seconds on my not particularly powerful desktop. I have stacked three different palette ranges into a single palette so that the splot command can use the palette directly rather than chopping it up into discrete samples as your example script does.

    By using the palette directly you also have the option to increase the smoothness by adding set pm3d interpolation N,N although I don't think it is needed here.

    If this approach fails to address some requirement, feel free to modify the question.

    set term pngcairo size 700,500
    set output 'Waves.png'
    
    samps = 250
    
    set samples samps, samps
    set isosamples samps, samps
    
    f(x,y) = sin(1.3*x)*cos(0.9*y)+cos(.8*x)*sin(1.9*y)+cos(y*.2*x)
    g(x,y) = y
    h(x,y) = 0.5*x
    
    Zmin = -3
    Zmax= 3
    
    set xrange[-5:5]
    set yrange[-5:5]
    set zrange[Zmin:Zmax]
    
    set pm3d depthorder
    set pm3d lighting primary 0.5 specular 0.2
    
    set style fill transparent solid 0.8 noborder 
    
    unset colorbox
    unset key
    
    set view 44,316
    
    set palette defined (-3 "0x0000df", 0 "0xddff40", 3 "0xdf0000", \
                          3 "gray40", 9 "0x8fffff", \
                          9 "gray40", 15 "0xffff8f")
    set cbrange [-3:15]
    
    splot '++' u 1:2:(f(x,y)) with pm3d, \
          '++' u 1:2:(g(x,y)):(6+g(x,y)) with pm3d, \
          '++' u 1:2:(h(x,y)):(12+h(x,y)) with pm3d
    

    enter image description here