Skip to content
Snippets Groups Projects
Commit 9d6e6e7a authored by STEVAN Antoine's avatar STEVAN Antoine :crab:
Browse files

mix colors for hybrid recoding strategies (!112)

- define `scripts/color.nu` to manipulate RGB colors, especially mix two colors together
- compute the color of _hybrid recoding strategies_ as a weighted sum of the two _simple recoding strategies_ involved, e.g. if the strategy is "10% of the time recode 2 shards and 90% of the time recode 3", then the color of that curve will be 10% the color of the simple strategy recoding 2 shards and 90% the color of the other simple strategy recoding 3 shards
- make the _hybrid_ curves transparent and dashed

## example
![foo](/uploads/71afca07a87fc38e3fa005cebfab4e50/foo.png)
parent 1f16e7e2
No related branches found
No related tags found
No related merge requests found
export const WHITE = { r: 1.0, g: 1.0, b: 1.0 }
export const BLACK = { r: 0.0, g: 0.0, b: 0.0 }
export const RED = { r: 1.0, g: 0.0, b: 0.0 }
export const GREEN = { r: 0.0, g: 1.0, b: 0.0 }
export const BLUE = { r: 0.0, g: 0.0, b: 1.0 }
def "error throw" [err: record<err: string, label: string, span: record<start: int, end: int>>] {
error make {
msg: $"(ansi red_bold)($err.err)(ansi reset)",
label: {
text: $err.label,
span: $err.span,
},
}
}
export def "color from-floats" [
r: float,
g: float,
b: float
]: nothing -> record<r: float, g: float, b: float> {
if $r < 0.0 or $r > 1.0 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 1, found ($r)",
span: (metadata $r).span,
}
}
if $g < 0.0 or $g > 1.0 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 1, found ($g)",
span: (metadata $g).span,
}
}
if $b < 0.0 or $b > 1.0 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 1, found ($b)",
span: (metadata $b).span,
}
}
{ r: $r, g: $g, b: $b }
}
export def "color from-ints" [
r: int,
g: int,
b: int
]: nothing -> record<r: float, g: float, b: float> {
if $r < 0 or $r > 255 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 255, found ($r)",
span: (metadata $r).span,
}
}
if $g < 0 or $g > 255 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 255, found ($g)",
span: (metadata $g).span,
}
}
if $b < 0 or $b > 255 {
error throw {
err: "invalid RGB channel",
label: $"should be between 0 and 255, found ($b)",
span: (metadata $b).span,
}
}
{ r: ($r / 255 | into float), g: ($g / 255 | into float), b: ($b / 255 | into float) }
}
def try-string-to-int []: string -> int {
try {
$"0x($in)" | into int
} catch {
get debug | parse --regex 'CantConvert { to_type: "(?<to>.*)", from_type: "(?<from>.*)", span: Span { (?<span>.*) }, help: Some\("(?<help>.*)"\) }' | into record | error make --unspanned { msg: ($in.help | str replace --all '\"' '"') }
}
}
export def "color from-string" [s: string]: nothing -> record<r: float, g: float, b: float> {
let res = $s
| parse --regex '^#(?<r>..)(?<g>..)(?<b>..)$'
| into record
if $res == {} {
error throw {
err: "invalid HEX color format",
label: $"format should be '#RRGGBB', found ($s)",
span: (metadata $s).span,
}
}
{
r: ($res.r | try-string-to-int | $in / 255),
g: ($res.g | try-string-to-int | $in / 255),
b: ($res.b | try-string-to-int | $in / 255),
}
}
export def "color mix" [
c1: record<r: float, g: float, b: float>,
c2: record<r: float, g: float, b: float>,
c: float,
]: nothing -> record<r: float, g: float, b: float> {
{
r: ($c * $c1.r + (1 - $c) * $c2.r),
g: ($c * $c1.g + (1 - $c) * $c2.g),
b: ($c * $c1.b + (1 - $c) * $c2.b),
}
}
def float-to-u8-hex []: float -> string {
$in * 255
| math round --precision 0
| into int
| fmt
| get lowerhex
| parse "0x{n}"
| into record
| get n
| into string
| fill --alignment "right" --character '0' --width 2
}
export def "color to-hex" []: record<r: float, g: float, b: float> -> string {
$"#($in.r | float-to-u8-hex)($in.g | float-to-u8-hex)($in.b | float-to-u8-hex)"
}
......@@ -3,6 +3,7 @@
use std repeat
use ../plot.nu gplt
use ../color.nu *
def "parse strategy" []: string -> record<type: string> {
let s = $in
......@@ -24,6 +25,21 @@ def "parse strategy" []: string -> record<type: string> {
}
}
def get-color []: int -> string {
match $in {
10 => "#d62728",
9 => "#ff7f0e",
8 => "#bcbd22",
7 => "#1f77b4",
6 => "#9467bd",
5 => "#2ca02c",
4 => "#17becf",
3 => "#8c564b",
2 => "#e377c2",
_ => "#7f7f7f",
}
}
export def main [data: path, --save: path, --options: record<k: int>] {
let data = open $data
let l = $data.diversity.0 | length
......@@ -58,20 +74,27 @@ export def main [data: path, --save: path, --options: record<k: int>] {
}
| rename --column { diversity: "points" }
| insert style {|it|
let color = match $it.strategy.n {
10 => "tab:red",
9 => "tab:orange",
8 => "tab:olive",
7 => "tab:blue",
6 => "tab:purple",
5 => "tab:green",
4 => "tab:cyan",
3 => "tab:brown",
2 => "tab:pink",
_ => "tab:gray",
let color = match $it.strategy.type {
"single" => { $it.strategy.n | get-color },
"double" => {
let c1 = $it.strategy.n | get-color | color from-string $in
let c2 = $it.strategy.m | get-color | color from-string $in
let c = $it.strategy.p
color mix $c1 $c2 $c | color to-hex
},
}
let alpha = match $it.strategy.type {
"single" => 1.0,
"double" => 0.3,
}
let type = match $it.strategy.type {
"single" => "solid",
"double" => "dashed",
}
{ color: $color, line: { alpha: ($it.strategy.p? | default 1.0) } }
{ color: $color, line: { alpha: $alpha, type: $type } }
}
| reject strategy
| save --force /tmp/graphs.json
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment