Gnuplot filledcurves with palette

后端 未结 6 977
有刺的猬
有刺的猬 2020-12-29 11:09

I have been trying to change the fillstyle for the filledcurves option in gnuplot so that the fill colour represents the difference between the two curves on a 2-dimensional

相关标签:
6条回答
  • 2020-12-29 11:17

    I am playing around with a patch for gnuplot to allow using linecolor rgb variable for filled curves. Then the following gnuplot code can be used:

    max_color=1
    # for a datafile one could extract the maximum diffference with e.g.
    # stats 'hotcold.dat' using 1:($3-$2)
    # max_color = (abs(STATS_min_y) > abs(STATS_max_y)) ? abs(STATS_min_y) : abs(STATS_max_y)
    
    red(val) = (val < 0 ? abs(1+val/max_color) : 1)
    green(val) = (1 - abs(val)/max_color)
    blue(val) = red(-val)
    rgb(val) = 65536*int(255*red(val)) + 256*int(255*green(val)) + int(255*blue(val))
    
    set yrange[0:1]
    set xrange[400:2500]
    set samples 200
    
    fhot(x) = 0.1*exp(-((x-400)/200)**2) + 0.8*exp(-((x-2000)/300)**2)
    fcold(x) = 0.25*exp(-((x-700)/100)**6)+ 0.4 - (2e-4*(x-2500))**2
    plot '+' using 1:(fhot($1)):(fcold($1)):(rgb(fhot($1)-fcold($1))) with filledcurves lc rgb var t '',\
         '' using 1:(fhot($1)) with lines lw 4 lc rgb rgb(max_color) t 'Hot',\
         '' using 1:(fcold($1)) with lines lw 4 lc rgb rgb(-max_color) t 'Cold'
    

    That gives this result: enter image description here

    I haven't submitted the patch, yet, because I don't know if I understood the question correctly and because I don't know if I covered all cases. So some fine-tuning may be required.

    0 讨论(0)
  • 2020-12-29 11:17

    The trick is to draw the lines, then fill between them with filledcurves. Here's how to do it (based on the examples at gnuplot):

    set style line 2 lc rgb 'forest-green'
    set style line 3 lc rgb 'plum'
    set style fill pattern 5 lc 'yellow'
    set xrange [0:3000]
    set yrange [0:1]
    plot 'data.txt' u 1:2:3 w filledcurves notitle, \
         '' u 1:2 ls 2 with lines notitle, \
         '' u 1:3 ls 3 with lines notitle
    

    The output looks like this: enter image description here

    The data file contains these dummy values (that resemble your second graph):

    500     0.90    0.90
    1000    0.90    0.75
    1500    0.92    0.40
    2000    0.95    0.30
    2500    0.94    0.23
    
    0 讨论(0)
  • 2020-12-29 11:19

    Another awkward workaround: instead of filledcurves using thick vertical vector lines.

    This will work when you have functions like in the example or equidistant data in x. If you don't have equidistant data in x, you would have to interpolate. Unfortunately, gnuplot does not have a feature for interpolating or resampling. You either can do this with external tools or neverthless with gnuplot which is getting a bit lenghty, see here: Resampling data with gnuplot

    For getting a good-looking color gradient you have to adjust the graph/canvas size, the sampling and/or the linewidth in order to find an optimum to eliminate gaps, overhang or aliasing. Too thin (lw 1) and too thick (lw 8) are not good. In the example below lw 3 seems to be a reasonable value. Maybe there are more ways to further optimize.

    The example below is using @Christoph's code, slightly modified.

    Code:

    max_color=1
    # for a datafile one could extract the maximum diffference with e.g.
    # stats 'hotcold.dat' using 1:($3-$2)
    # max_color = (abs(STATS_min_y) > abs(STATS_max_y)) ? abs(STATS_min_y) : abs(STATS_max_y)
    
    red(val) = (val < 0 ? abs(1+val/max_color) : 1)
    green(val) = (1 - abs(val)/max_color)
    blue(val) = red(-val)
    rgb(val) = 65536*int(255*red(val)) + 256*int(255*green(val)) + int(255*blue(val))
    
    set yrange[0:1]
    set xrange[400:2500]
    set samples 200
    
    fhot(x) = 0.1*exp(-((x-400)/200)**2) + 0.8*exp(-((x-2000)/300)**2)
    fcold(x) = 0.25*exp(-((x-700)/100)**6)+ 0.4 - (2e-4*(x-2500))**2
    
    plot \
         '+' using 1:(fhot($1)):(0):(fcold($1)-fhot($1)):(rgb(fhot($1)-fcold($1))) with vectors nohead lw 3 lc rgb var t '',\
         '' using 1:(fhot($1)) with lines lw 4 lc rgb rgb(max_color) t 'Hot',\
         '' using 1:(fcold($1)) with lines lw 4 lc rgb rgb(-max_color) t 'Cold'
         
    

    Result: (wxt 640x480, lw 1)

    Result: (wxt 640x480, lw 3)

    Result: (wxt 640x480, lw 8)

    0 讨论(0)
  • 2020-12-29 11:35

    AFAIK, this is still not implemented in gnuplot. You can however have a dirty(*) work around by overlaying several transparent filled curves.

    E.g.,

    max_color=1
    max_diff=0.5
    N_col=6
    TRSP="E0"
    HOTCOL="FF0000"
    COLDCOL="0000FF"
    RGBA_HOT="#".TRSP.HOTCOL
    RGBA_COLD="#".TRSP.COLDCOL
    RGB_HOT="#".HOTCOL
    RGB_COLD="#".COLDCOL
    #red(val) = (val < 0 ? abs(1+val/max_color) : 1)
    #green(val) = (1 - abs(val)/max_color)
    #blue(val) = red(-val)
    #rgb(val) = 65536*int(255*red(val)) + 256*int(255*green(val)) + int(255*blue(val))
    fhot(x) = 0.1*exp(-((x-400)/200)**2) + 0.8*exp(-((x-2000)/300)**2)
    fcold(x) = 0.25*exp(-((x-700)/100)**6)+ 0.4 - (2e-4*(x-2500))**2
    plot [400:2600] for [thr=0:N_col] '+' using (((fhot($1)-fcold($1))/max_diff*N_col>thr)?$1:1/0):(fhot($1)):(fcold($1)) with filledcurves lc rgb RGBA_HOT title '',\
         for [thr=0:N_col] '+' using ((-(fhot($1)-fcold($1))/max_diff*N_col>thr)?$1:1/0):(fhot($1)):(fcold($1)) with filledcurves lc rgb RGBA_COLD title '',\
         '' using 1:(fhot($1)) with lines lw 4 lc rgb RGB_HOT t 'Hot',\
         '' using 1:(fcold($1)) with lines lw 4 lc rgb RGB_COLD t 'Cold'
    

    Adjust N_col and TRSP to change the gradient: number of filled curves overlaid and transparency of each (more curves implies to be closer to max transparency FE).

    (*) This is less dirty in case the information you want to plot is a discrete variable, e.g. the number of datasets available at given abscissae.

    0 讨论(0)
  • 2020-12-29 11:36

    Try to use filled histograms.

    set style fill solid 1.0
    plot \
     datafile u 1:2:3 lt palette w boxes,\
     datafile u 1:2:3 lt palette lw 2 w l
    

    Column 3 defines color filling color according to palette settings, columns 1 and 2 define data points. You can also use background color histogram for clearing parts under graph.

    I'd like to add image but I can't because of low reputation.

    0 讨论(0)
  • 2020-12-29 11:41

    Yet Another Solution

    If the pm3d 2D map is allowed without filledcurves, then the following code could be used to achieve this

    In the data processing part, the grid data for splot is constructed from the original input data. The color of the fill area is determined by the z-value given for splot.

    set table $first
    plot "test.dat" using 1:2:($3-$2) with table
    set table $second
    plot "test.dat" using 1:3:($3-$2) with table
    unset table
    
    set print $data
    do for [i=1:|$first|] {
      print $first[i]
      print $second[i]
      print ""
    }
    set print
    
    set yrange [-2:2]
    set palette define (-1 "skyblue", 0 "gray90", 1 "pink")
    
    splot $data using 1:2:3 with pm3d 
    
    0 讨论(0)
提交回复
热议问题