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