Skip to content

Commit fb5b684

Browse files
committed
Add Brewer color schemes
1 parent 6d67952 commit fb5b684

File tree

4 files changed

+2309
-1
lines changed

4 files changed

+2309
-1
lines changed

src/Aardvark.Base.FSharp/Aardvark.Base.FSharp.fsproj

+3-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
<Compile Include="Datastructures\Geometry\KdTree.fs" />
6161
<Compile Include="Datastructures\Geometry\Bvh.fs" />
6262
<Compile Include="Algorithms\PolygonSimplification.fs" />
63+
<Compile Include="Color\ColorBrewer.fs" />
64+
<Compile Include="Color\ColorBrewerSchemes.fs" />
65+
<None Include="color\ColorBrewerSchemes.fsx" />
6366
<Compile Include="Reflection\TypeInfo.fs" />
6467
<Compile Include="Reflection\FunctionReflection.fs" />
6568
<Compile Include="Reflection\Formatf.fs" />
@@ -89,6 +92,5 @@
8992
<ItemGroup>
9093
<ProjectReference Include="..\Aardvark.Base\Aardvark.Base.csproj" />
9194
</ItemGroup>
92-
<ItemGroup />
9395
<Import Project="..\..\.paket\Paket.Restore.targets" />
9496
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
namespace Aardvark.Base
2+
3+
open System
4+
open System.Collections
5+
open System.Collections.Generic
6+
7+
/// Brewer color schemes designed for chloropleth map visualizations.
8+
module ColorBrewer =
9+
10+
[<Flags>]
11+
type PaletteUsage =
12+
| None = 0
13+
14+
/// Does not confuse people with red-green color blindness.
15+
| ColorBlind = 1
16+
17+
/// Suitable for desktop color printing.
18+
| Print = 2
19+
20+
/// Suitable for viewing on a laptop LCD display.
21+
/// Small, portable LCD monitors tend to wash-out colors which results in noticeable differences from computer-to-computer.
22+
| LCD = 4
23+
24+
/// Withstands black and white photocopying.
25+
/// Diverging schemes can not be photocopied successfully.
26+
/// Differences in lightness should be preserved with sequential schemes.
27+
| PhotoCopy = 8
28+
29+
[<Struct>]
30+
type Palette =
31+
{
32+
/// The color values of the palette.
33+
Colors : C3b[]
34+
35+
/// Usage properties of the palette.
36+
Usage : PaletteUsage
37+
}
38+
39+
member inline x.Length =
40+
x.Colors.Length
41+
42+
member inline x.Item (index : int) =
43+
x.Colors.[index]
44+
45+
interface IEnumerable with
46+
member x.GetEnumerator() = x.Colors.GetEnumerator()
47+
48+
interface IEnumerable<C3b> with
49+
member x.GetEnumerator() = (x.Colors :> IEnumerable<C3b>).GetEnumerator()
50+
51+
52+
type SchemeType =
53+
54+
/// Diverging schemes put equal emphasis on mid-range critical values and extremes at both ends of the data range.
55+
/// The critical class or break in the middle of the legend is emphasized with light colors and low and high extremes are
56+
/// emphasized with dark colors that have contrasting hues.
57+
| Diverging = 0
58+
59+
/// Qualitative schemes do not imply magnitude differences between legend classes, and hues are used to
60+
/// create the primary visual differences between classes. Qualitative schemes are best suited to representing nominal or categorical data.
61+
| Qualitative = 1
62+
63+
/// Sequential schemes are suited to ordered data that progress from low to high.
64+
/// Lightness steps dominate the look of these schemes, with light colors for low data values to dark colors for high data values.
65+
| Sequential = 2
66+
67+
/// A color scheme containing palettes of various size.
68+
[<Struct>]
69+
type Scheme =
70+
{
71+
/// Name of the scheme.
72+
Name : Symbol
73+
74+
/// Type of the scheme.
75+
Type : SchemeType
76+
77+
/// The palettes of the scheme according to their size.
78+
Palettes : MapExt<int, Palette>
79+
}
80+
81+
/// Returns whether the scheme is empty (i.e. has no palettes).
82+
member inline x.IsEmpty =
83+
x.Palettes.IsEmpty
84+
85+
/// Size of the smallest palette.
86+
member inline x.MinSize =
87+
x.Palettes.TryMinKeyV |> ValueOption.defaultValue 0
88+
89+
/// Size of the largest palette.
90+
member inline x.MaxSize =
91+
x.Palettes.TryMaxKeyV |> ValueOption.defaultValue 0
92+
93+
/// Gets the palette with the given size.
94+
/// If the scheme is not defined for the requested size, gets the next larger palette.
95+
/// Throws an exception if the requested size is greater than the maximum size.
96+
member inline x.Item (requestedSize : int) =
97+
match x.Palettes |> MapExt.neighboursV requestedSize with
98+
| struct (_, ValueSome (struct (_, palette)), _)
99+
| struct (_, _, ValueSome (struct (_, palette))) ->
100+
palette
101+
102+
| struct (ValueSome (struct (max, _)), _, _) ->
103+
raise <| ArgumentOutOfRangeException("requestedSize", $"Scheme {x.Name} has a maximum palette size of {max} (requested {requestedSize}).")
104+
105+
| struct (ValueNone, ValueNone, ValueNone) ->
106+
raise <| ArgumentException($"Scheme {x.Name} is empty.")
107+
108+
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
109+
module Scheme =
110+
111+
/// Returns whether the scheme is empty (i.e. has no palettes).
112+
let inline isEmpty (scheme : Scheme) =
113+
scheme.IsEmpty
114+
115+
/// Return the size of the smallest palette for the given scheme.
116+
let inline minSize (scheme : Scheme) =
117+
scheme.MinSize
118+
119+
/// Return the size of the largest palette for the given scheme.
120+
let inline maxSize (scheme : Scheme) =
121+
scheme.MaxSize
122+
123+
/// Gets the palette with the given size.
124+
/// If the scheme is not defined for the requested size, gets the next larger palette.
125+
/// Throws an exception if the requested size is greater than the maximum size.
126+
let inline getPalette (requestedSize : int) (scheme : Scheme) =
127+
scheme.[requestedSize]
128+
129+
/// Returns a new scheme containing only the palettes for which the predicate returns true.
130+
let inline filter (predicate : Palette -> bool) (scheme : Scheme) =
131+
{ scheme with Palettes = scheme.Palettes |> MapExt.filter (fun _ -> predicate) }
132+
133+
/// Returns a new scheme containing only the palettes with the given usage flags.
134+
let inline filterUsage (usage : PaletteUsage) (scheme : Scheme) =
135+
scheme |> filter (fun p -> p.Usage &&& usage = usage)

0 commit comments

Comments
 (0)