Skip to content
This repository has been archived by the owner on Jul 9, 2023. It is now read-only.

Minimal API for generating color scheme for a chart that needs n colors #12

Closed
dtolnay opened this issue Jan 21, 2019 · 18 comments
Closed

Comments

@dtolnay
Copy link
Owner

dtolnay commented Jan 21, 2019

In cargo tally I need to display a plot with some number of lines on it. I wish there were a crate where I could call:

pub fn get_color_scheme(size: u32) -> Vec<HexColor>;

and get back n different colors in a cohesive color scheme suitable for a chart.

@Shadlock0133
Copy link

Possible reference: https://github.com/medialab/iwanthue

@BartMassey
Copy link

For up to 64 colors, a suitable permutation of the old X11 RGB.txt "Crayola Crayon" colors is not a bad way to go. (If you need more than 64 distinct colors, results are likely to be sketchy anyhow.)

I tend to prefer a deterministic scheme with a predefined order rather than the randomization scheme specced in the IWantHue link above. That way the distribution can be hand-tuned. I have used @dtolnay's scheme from cargo-tally with some success, but I prefer to use darker and lighter pastels of each hue and spin things so that adjacent colors are more distinct.

This brings up an interesting issue: sometimes you want nearby color indices to be as distinct as possible, sometimes you want them to be distinct but related. Should the API provide/reflect this?

@inferiorhumanorgans
Copy link

What about something like ColorBrewer?

@BartMassey
Copy link

Interesting! It's got some great ideas in it. It's not obvious what algorithms etc it's using. It only goes up to 12 colors or so in the current implementation. It seems pretty tuned for maps.

I suspect one would have to figure out what's going on there, and then build a crate that incorporated that learning. It would be a great project.

@veldsla
Copy link

veldsla commented Jan 23, 2019

A popular R implementation can be found here https://cran.r-project.org/web/packages/RColorBrewer/index.html. It's implemented as predefined sets of colors, but often used in R in combination with functionality that does interpolation (grDevices::colorRamp)

@BartMassey
Copy link

Cool. Documentation about how it works anyplace?

@veldsla
Copy link

veldsla commented Jan 23, 2019

About colorRamp? Sure: https://www.rdocumentation.org/packages/grDevices/versions/3.5.2/topics/colorRamp

@inferiorhumanorgans
Copy link

The canonical ColorBrewer implementation is written in JavaScript and available on github here: axismaps/colorbrewer, however the implementation I'm familiar with comes with d3 (also JS). It's very much map-centric as Dr. Brewer is a cartographer at Penn State. The CMYK and RGB specs are available here.

Personally I think that more than twelve colors for a chart seems a bit much, but GraphIQ's design lead made an interesting post on their blog summarizing various ideas of how to generate color sets for data visualizations (unfortunately it's hosted on Medium so it's awkward to read).

@inferiorhumanorgans
Copy link

inferiorhumanorgans commented Jan 24, 2019

That said, how about some bikeshedding? Is there interest in CMYK and HSV support as well? 16-bit RGB?

I'm thinking instead of a HexColor struct an enum like:

enum Color {
  RGB(u8, u8, u8),
  CMYK(u8, u8, u8, u8),
  HSV(u8, u8, u8),
}

would be a good idea assuming ColorBrewer were the starting point as these are already defined.

And then maybe a trait that defines functions for each color space that take an argument indicating number of colors desired and returns a Color enum? Maybe metadata functions as well for the attributes listed on the site (e.g. safe for colorblind folks)?

In the back of my head I'm thinking a proper charting library (even if backed by Cairo) modeled after d3 would be really awesome (both for server side rendering and client side w/ WASM).

@BrandtM
Copy link

BrandtM commented Jan 24, 2019

Hey everyone.
I'm still new to Rust and this is my first published lib (though it's not on crates.io yet because I don't know if something this small should pollute their archives).
I am open to criticism and appreciate any feedback you can give a newbie like me.

I went through a few iterations on how to generate a random color palette but I'm not at all familiar with color science so I ran into a few dead ends.
The current implementation actually uses the HSV color space to generate random hues by simply shifting the hue of each color in the palette by 85° plus a little extra for each iteration.

Because everything internally is calculated using floats (f32) and I don't like robbing precision from the users the user-facing Color struct only outputs RGB in floats from 0 to 1 (not the traditional 0 to 255).

Anyway here's the code: https://github.com/BrandtM/colourado

@dtolnay
Copy link
Owner Author

dtolnay commented Jan 24, 2019

Sweet! Would it be possible to add screenshots of color schemes of various sizes to the readme? It is hard to tell from the code what they might look like.

@dtolnay
Copy link
Owner Author

dtolnay commented Jan 24, 2019

Maybe also, if you're interested: add a little companion binary that pops up a window showing n lines or boxes with your color scheme (or writes out a png file if that is easier). If you stick a file with a main function into examples/preview.rs then Cargo will pick it up like this:

cargo run --example preview 4
                            ^ number of colors

@BrandtM
Copy link

BrandtM commented Jan 24, 2019

Oh wow thanks.
I did actually test this before but I wasn't aware of this functionality.
Should be done in a couple of minutes.

@BrandtM
Copy link

BrandtM commented Jan 24, 2019

@dtolnay alright it's done.

@dtolnay
Copy link
Owner Author

dtolnay commented Jan 24, 2019

Nicely done. Once you get it published to crates.io, I'll close out this issue and mark it off the list with a link to your crate.

For cargo tally I might want some brighter colors that are easier to differentiate on a line graph, but we can sort that out on the issue tracker. Thanks!

Regarding the other folks' suggestions earlier in the thread, I would love to see those take form as well! Let me know if any of those get turned into a library and I can link to them as well.

@BartMassey
Copy link

This crate looks like a great start: a nice place to work on the API and color generation schemes. Thanks for taking the lead @BrandtM !

@BrandtM
Copy link

BrandtM commented Jan 25, 2019

Thanks for your encouragement!
I had some minor troubles but nothing that I couldn't fix easily but now it's published to crates.io
https://crates.io/crates/colourado

@dtolnay dtolnay closed this as completed Jan 25, 2019
@mazznoer
Copy link

Hope I am not too late. Using colorgrad we can do something like this easily. There is lot of preset gradients, and we can create custom gradient too.

let grad = colorgrad::sinebow();
let hex_colors = Vec::new();

for c in grad.colors(35) {
    hex_colors.push(c.to_hex_string());
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants