What follows is the translation of Java code I found here, in the VisualizeCoords class. It returns an array reference holding the given number of array references. Each RGB tuple has a value from 0 to 1 -- simply multiply by 255 to get the "normal" value.
sub get_distinct_colors {
use POSIX 'ceil';
my $n = shift;
my $discrete = ceil($n ** (1/3));
my @vals = map 1 - (($_-1) / $discrete), 1 .. $discrete;
my @colors;
my ($r, $g, $b) = (0,0,0);
for my $i (1 .. $n) {
push @colors, [@vals[$r,$g,$b]];
if (++$b == $discrete) {
if (++$g == $discrete) {
$r = ($r + 1) % $discrete;
$g = 0;
}
$b = 0;
}
}
return \@colors;
}
_____________________________________________________
Jeff japhy Pinyan,
P.L., P.M., P.O.D, X.S.:
Perl,
regex,
and perl
hacker
How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: Generating Visually Distinct Colors
by Roy Johnson (Monsignor) on Mar 22, 2005 at 04:52 UTC
|
Nicely translated. I wanted to make it read a little nicer, and came up with this equivalent code:
sub my_gdc {
use POSIX 'ceil';
my $n = shift;
my $discrete = ceil($n ** (1/3));
my @colors;
GENERATE:
for my $r (0..$discrete-1) {
for my $g (0..$discrete-1) {
for my $b (0..$discrete-1) {
push @colors, [map {1-$_/$discrete} $r, $g, $b];
last GENERATE if @colors >= $n;
}
}
}
\@colors;
}
and then I wanted to use a single loop and came up with this:
sub my_gdc1 {
use POSIX 'ceil';
my $n = shift;
my $discrete = ceil($n ** (1/3));
my @colors = ([1,1,1]);
for my $i (1..$n-1) {
push @colors, [map {1-($_%$discrete)/$discrete}
$i/($discrete**2),
$i/$discrete,
$i];
}
\@colors;
}
Caution: Contents may have been coded under pressure.
| [reply] [d/l] [select] |
Re: Generating Visually Distinct Colors
by iblech (Friar) on Mar 22, 2005 at 15:36 UTC
|
#!/usr/bin/perl6
use v6;
# ceil() not yet implemented in Pugs
sub ceil ($n) { int($n) + ($n > int($n) ?? 1 :: 0) }
my $n = 10;
my $discrete = ceil($n ** (1/3));
my $r = any 0..$discrete-1;
my $g = any 0..$discrete-1;
my $b = any 0..$discrete-1;
# Now $r,$g,$b are Junctions containing all the possible values of
# red/green/blue.
$r = int( (1-$r/$discrete) * 255 );
$g = int( (1-$g/$discrete) * 255 );
$b = int( (1-$b/$discrete) * 255 );
# $color is a Junction containing all colors as "(red, green, blue)".
my $color = "($r, $g, $b)";
# Finally, print $color.
for $color -> $x { say $x }
Update: Hand-rolled ceil was wrong, fixed (thanks japhy!). | [reply] [d/l] |
|
Um, what's with that ceil() function? int($x+2)? I'd feel much safer with
sub ceil (Num $x) { $x == int($x) ?? $x :: int($x+1) }
I'm pretty sure that's the appropriate P6 code.
_____________________________________________________
Jeff japhy Pinyan,
P.L., P.M., P.O.D, X.S.:
Perl,
regex,
and perl
hacker
How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
| [reply] [d/l] [select] |
|
| [reply] [d/l] [select] |
|
|
| [reply] |
Re: Generating Visually Distinct Colors
by sfink (Deacon) on Mar 22, 2005 at 18:07 UTC
|
I implemented something like this for an application I wrote once. The algorithm you're implementing chooses N evenly-spaced 3D grid points in the RGB color space. I found that this didn't give a terribly good result, because our eyes are far from being equally sensitive to changes in red, green, and blue at different points in the color space.
Anyone know of a better algorithm? As a first cut, probably using HSV space would be better, but you wouldn't want to sample it evenly -- you'd probably use a whole bunch of gradations in hue, but only a few in saturation and value.
I probably just ought to spend some quality time with Google. Given how important this is for things like MPEG encoding, I'm sure somebody's come up with a color space that approximates an even spreading of perceptual differences. Well, "approximates" it for "most" people, or something.
Then you'd just have to implement a "red/green colorblind" mode that a user could select, with a very different sampling space...
| [reply] |
|
| [reply] |
Re: Generating Visually Distinct Colors
by cosimo (Hermit) on Mar 23, 2005 at 12:18 UTC
|
I usually use something like this to generate colors for sections of histogram or pie charts.
sub getColor
{
my $index = shift; # Numerical index (integer from 0 to ..
+.)
my @color; # Color components
my @hue_matrix = (
#
# R G B Component to modify(0=R, 1=G, 2=B)
# | | | |
# V V V V Add or subtract the offset
# | from (r,g,b) triplet
# V
[ 255, 0, 0, 2, 1 ], # Sector 1 R -> R+B
[ 255, 0, 255, 0, -1 ], # Sector 2 R+B -> B
[ 0, 0, 255, 1, 1 ], # ... B -> Cyan
[ 0, 255, 255, 2, -1 ], # ... Cyan-> G
[ 0, 255, 0, 0, 1 ], # ... ...
[ 255, 255, 0, 1, -1 ],
[ 255, 0, 0, 2, 1 ]
);
# Select a "spectrum sector", according to my hue matrix
my $sector = $hue_matrix[ int($index / 42) % @hue_matrix ];
# Calculate an offset to be applied to starting color
my $offset = ($index % 42) * 6;
@color = @$sector[0..2];
# Modify selected component to generate a "continuous gradient"
$color[$sector->[3]] += ($sector->[4] > 0 ? $offset : -$offset);
return(@color);
}
# Generate visually distinct colors...
print '<HTML><BODY>', "\n";
# How much distinct you decide with this factor
my $distinct_factor = 10;
for( 1 .. 30 )
{
printf(
"<TABLE BGCOLOR=#%02X%02X%02X><TR><TD>" . ' ' x 20 . "</T
+D></TR></TABLE>\n",
getColor($distinct_factor * $_)
);
}
print '</BODY></HTML>';
# Or you can choose getColor() parameter at random...
The final result is:
... that of course is not perfect, but adjusting the $distinct_factor can provide satisfying results.
Update: Sorry, it was missing the last piece of code...
| [reply] [d/l] [select] |
Re: Generating Visually Distinct Colors
by iblech (Friar) on Mar 23, 2005 at 13:39 UTC
|
japhy, you might find Coloring IRC logs nicely interesting, too.
This is the algorithm my IRC bot iblechbot uses, too (screenshot).
First, a raw IRC log is read to find out which nicks were online (and talked) at the same time. This information is used to build a interference graph. Then, using the graph, all nicks get distict colors.
Because of the interference graph, the colors used are reduced to a minimum:
- 10:00 - A joins - color: 1/3 # notice: three colors needed
- 10:03 - B joins - color: 2/3
- 10:05 - C joins - color: 3/3
- (Time passes...)
- 20:00 - D joins - color: 1/2 # notice: only two colors used here
- 20:02 - E joins - color: 2/2
Using the colornum/total_num_of_colors information, the actual color pair (foreground, background) is built:
| [reply] [d/l] |
|
|