Search code examples
gnuplot

Gnuplot plotting colours


I'm trying to make a graph of RGB values vs the colour such as this one: HSL hue sweep target output image

My approach has been based off of http://gnuplot.sourceforge.net/demo/pm3dcolors.html

For this it's important to be able to correctly display an arbitrary number of colours, lined up with a plot.

In the above image you can kinda see weird overlap between colours, and there are different widths, and it doesn't quite line up with the graph.

The rest of this post is demonstrating the minimum required to make it look weird.

I've found that it starts messing things up after 33 colours.

#!/usr/bin/env gnuplot

set format cb "%3.1f"

set style function pm3d
set view map scale 1

unset xtics
unset ytics
unset ztics
unset colorbox
unset key


set title "33 colours"
set palette model RGB
set palette file "-"
1 0 0
0 1 0
0 0 1
... repeat many times ...
1 0 0
0 1 0
0 0 1
e
set palette maxcolors 33
g(x)=x
splot g(x)

pause mouse any "press the any key to exit gnuplot
  • This is what happens with 33 and below colours: 33 colours working fine
  • This is what happens with 34 (the middle green is less wide): 34 colours working fine
  • If we go up to 66 you can see even more stuff wrong: 66 is very wrong

So overall, this is pretty clearly an abuse of gnuplot.

Is there some other approach that would work better? If not, how should I go about debugging this?

I'm running gnuplot 5.4 patchlevel 1 from the debian repos on debian bullseye.

Thank you for any suggestions.


EDIT:

I fell into the trap of the XY problem. I want the first graph in the question to not have weird stuff like how you can see different color widths, when they should all be the same width. I asked about the minimum way I found to show the weird thing I'm seeing with set palette.

My current input data looks like this:

Hue, Red, Green, Blue

0.0100, 255,  15,   0
0.0300, 255,  46,   0
0.0400, 255,  61,   0
0.0600, 255,  92,   0
0.0700, 255, 107,   0
...

My script to generate that plot is http://ix.io/3BE2


Solution

  • Alternative answer attempting to address modified question

    Modified question:

    Thanks for your reply but by "display an arbitrary number of colors" I meant that I have a list of colors and I want to display them, I don't have a way to represent them as a function.

    # snippet of code from your attachment
    set palette file 'plotData/rgb.csv' using (($2/255)):(($3/255)):(($4)/255)
    set palette maxcolors system("wc -l plotData/rgb.csv | sed 's/ .*//'")
      
    g(x)=x
    splot g(x)
    

    I will start by noting a number of issues with this approach. I still don't quite understand what the requirements are for the output, but I gather than part of the problem is that it does not produce a set of evenly-spaced regions that match the number of palette colors. This is understandable because

    • the number of colors Ncol is known only by counting the number of lines in an external file.
    • the number of filled intervals along x generated by splot F(x) is determined by set samples, which has no intrinsic connection to Ncol.
    • you could try to align the two by saying set samples Ncol, but this still allows for a mismatch between the interval boundaries along x axis and the the interval boundaries along the color axis cb. Possibly you could resolve this by fixing set xrange [A:B]; set cbrange [A:B] but it would require knowing the limiting values A and B in advance. Also, in most applications it is quite possible the desirable spatial resolution on x is much greater than the number of colors supported by an indexed palette.

    I suggest that you really don't want a palette for your case at all. You just want the RGB color values. Here are two variants based on the code fragment above

    # convert file of numerical RGB components (0-255) to 24-bit hex representation
    # $RGBtable will be a datablock containing Ncol string values
    set table $RGBtable
    plot 'rgbvalues.csv' using (sprintf("0x%2x%2x%2x", $2, $3, $4)) with table
    unset table
    Ncol = |$RGBtable|
    
    # create an array containing the same set of colors as integer values
    array RGBarray[Ncol]
    do for [i=1:Ncol] { RGBarray[i] = int($RGBtable[i]) }
    
    # Now we can use either the string form or the integer form to plot with.
    # I still don't understand exactly what it is you are plotting, but here
    # is an example using either the datablock or the array to access colors
    set xrange [0 : Ncol+1]
    set yrange [0 : 3]
    plot sample [i=1:Ncol] '+' using 1:(1):(RGBarray[i]) with points pt 5 lc rgb variable, \
         [i=1:Ncol] '+' using 1:(2):(int($RGBtable[i])) with points pt 7 lc rgb variable
    

    enter image description here

    And finally, here is something similar to your original splot command using high-resolution sampling along the horizontal direction but a discrete set of colors from integral values in the range [1:Ncol]. Note that the nominal z value in field 3 of the using specifier is not relevant to this plot, since the color information is coming separately from field 4 as requested by lc rgb variable.

    set view map
    set sample 999
    set urange [1:Ncol]
    splot '++' using 1:2:(0):(RGBarray[int($1)]) with pm3d lc rgb variable
    

    enter image description here