skip to Main Content

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

2

Answers


  1. If I understand correctly the description of the things you have tried, they are all based on the palette definition option set palette defined. This is inherently subject to range interpolation artifacts, although the artifacts become less noticeably as you increase the number of increments used in the palette definition.

    Since your primary aim is "to be able to correctly display an arbitrary number of colours", you probably would do better to use a different method to define the palette, one based on a set of continuous functions for the RGB components. And you do not want to use set palette maxcolors, because the whole point of that command is to limit the palette to a discrete set of colors rather than a continuum.

    One pre-defined option is to use set palette cubehelix, which uses a fixed set of continuous function but allows you to adjust various control parameters. For example set palette cubehelix start 0.15 cycles 1.0 saturation 1.0 produces the palette below. However a defining property of this family of palettes is that the intensity runs from 0 to 1, which you may not want.
    cubehelix palette

    A more general solution is to provide your own continuous functions for the palette definition. For example, set palette model HSV functions gray, 1, 0.9 produces the palette below. This is basically the same as you show except that it is defined in terms of continuous functions.
    enter image description here

    Note that the output from test palette shows only 128 samples in the color bar at the bottom. But that isn’t an intrinsic limitation of the palette, it’s just chosen for convenience in generating the test output. I will attempt to show the distinction (not sure it will survive display on this web site)

    set palette model HSV functions gray, 1, 0.9
    set colorbox horiz user origin 0.05, 0.01 size 0.9, 0.05
    set lmargin at screen 0.05; set rmargin at screen 0.95
    unset ytics
    set title "x sampling 1000 intervals"
    set cblabel "colorbox sampling 128 intervals" norotate offset 0,1.5
    set view map
    set sample 1000
    splot x with pm3d
    

    enter image description here

    You might also have to worry about limitations of the color system used by the document you are producing. Not all output formats can use a full 24-bit RGB color specification. pdf/svg/cairo should be fine. Old-style color-indexed gif or png, on the other hand, are limited to 256 distinct colors total.

    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search