Skip to content

Commit 7429642

Browse files
committed
adding documentation for the sequential scales and initial interpolators
1 parent f280034 commit 7429642

File tree

207 files changed

+478
-197
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

207 files changed

+478
-197
lines changed

Sources/SwiftVizScale/ArrayInterpolator.swift

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,18 @@
44

55
import CoreGraphics
66

7-
public struct ArrayInterpolator: Interpolator {
7+
///// A type that provides an interpolated result types between two corresponding instances.
8+
// public protocol Interpolator {
9+
// /// The type that the interpolator accepts as instances, and returns as an interpolated result.
10+
// associatedtype OutputType
11+
// /// Provide an instance that is the interpolated value between two others.
12+
// /// - Parameter t: A unit value between `0` and `1` that represents the distance between the two values.
13+
// /// - Returns: An instance of a type that is the interpolated result based on the value you provide.
14+
// func interpolate(_ t: Double) -> OutputType
15+
// }
16+
17+
/// An interpolator that maps a unit value into a color based on the position between the colors.
18+
public struct ArrayInterpolator {
819
// Color pallets for interpolation and presentation:
920
// https://github.com/d3/d3-scale-chromatic/blob/main/README.md
1021
var colors: [CGColor]
@@ -33,23 +44,41 @@ public struct ArrayInterpolator: Interpolator {
3344
return (lowerIndex, tValueBetweenSteps)
3445
}
3546

47+
/// Returns the color mapped from the unit value you provide.
48+
/// - Parameter t: A unit value between `0` and `1`.
3649
public func interpolate(_ t: Double) -> CGColor {
3750
let (colorIndex, tBetweenIndicies) = Self.interpolateIntoSteps(t, colors.count - 1)
3851
return LCH.interpolate(colors[colorIndex], colors[colorIndex + 1], t: tBetweenIndicies)
3952
}
4053

54+
/// Creates a new color interpolator that maps between the two colors you provide.
55+
/// - Parameters:
56+
/// - from: The color at the beginning.
57+
/// - to: The color at the end.
4158
public init(_ from: CGColor, _ to: CGColor) {
4259
colors = [from, to]
4360
}
4461

62+
/// Creates a new color interpolator that maps between the colors you provide.
63+
/// - Parameters:
64+
/// - colors: The sequences of colors to map through.
65+
public init(_ colors: [CGColor]) {
66+
precondition(colors.count > 2, "ArrayInterpolator requires at least 2 colors.")
67+
self.colors = colors
68+
}
69+
4570
static let white = CGColor(srgbRed: 1, green: 1, blue: 1, alpha: 1)
4671
static let black = CGColor(srgbRed: 0, green: 0, blue: 0, alpha: 1)
4772
static let red = CGColor(srgbRed: 1, green: 0, blue: 0, alpha: 1)
4873
static let blue = CGColor(srgbRed: 0, green: 0, blue: 1, alpha: 1)
4974
static let green = CGColor(srgbRed: 0, green: 1, blue: 0, alpha: 1)
5075

76+
/// An interpolator that maps to various shades between white to black.
5177
public static let Grays = Self(white, black)
78+
/// An interpolator that maps to various shades between white to blue.
5279
public static let Blues = Self(white, blue)
80+
/// An interpolator that maps to various shades between white to green.
5381
public static let Greens = Self(white, green)
82+
/// An interpolator that maps to various shades between white and red.
5483
public static let Reds = Self(white, red)
5584
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# ``SwiftVizScale/ArrayInterpolator``
2+
3+
## Topics
4+
5+
### Creating an Interpolator
6+
7+
- ``SwiftVizScale/ArrayInterpolator/Grays``
8+
- ``SwiftVizScale/ArrayInterpolator/Blues``
9+
- ``SwiftVizScale/ArrayInterpolator/Greens``
10+
- ``SwiftVizScale/ArrayInterpolator/Reds``
11+
- ``SwiftVizScale/ArrayInterpolator/init(_:_:)``
12+
- ``SwiftVizScale/ArrayInterpolator/init(_:)``
13+
14+
### Mapping values to colors
15+
16+
- ``SwiftVizScale/ArrayInterpolator/interpolate(_:)``

Sources/SwiftVizScale/Documentation.docc/Documentation.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ Loosely based on the APIs and the visualization constructs created by Mike Bosto
2929
- ``SwiftVizScale/DiscreteScale``
3030
- ``SwiftVizScale/DiscreteScaleType``
3131

32+
### Sequential Scales
33+
34+
- ``SwiftVizScale/SequentialScale``
35+
- ``SwiftVizScale/ArrayInterpolator``
36+
- ``SwiftVizScale/LCH``
37+
3238
### Ticks
3339

3440
- ``SwiftVizScale/Tick``
@@ -37,8 +43,6 @@ Loosely based on the APIs and the visualization constructs created by Mike Bosto
3743

3844
- ``SwiftVizScale/Scale``
3945
- ``SwiftVizScale/ReversibleScale``
40-
- ``SwiftVizScale/Interpolator``
41-
- ``SwiftVizScale/LCH``
4246
- ``SwiftVizScale/NiceValue``
4347
- ``SwiftVizScale/ConvertibleWithDouble``
4448

Sources/SwiftVizScale/Documentation.docc/Interpolator.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

Sources/SwiftVizScale/SequentialScale.swift

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,121 @@
22
// SequentialScale.swift
33
//
44

5+
import CoreGraphics
56
import Foundation
67

7-
/// A type that maps values from a continuous input _domain_ to an output _range_.
8-
public struct SequentialScale<InputType: ConvertibleWithDouble, OutputType>: Scale, CustomStringConvertible {
8+
/// A type that maps values from a continuous input _domain_ to a color.
9+
public struct SequentialScale<InputType: ConvertibleWithDouble>: CustomStringConvertible {
10+
/// The lower bound of the input domain.
11+
public let domainLower: InputType
12+
/// The upper bound of the input domain.
13+
public let domainHigher: InputType
14+
/// A Boolean value that indicates if the mapping from domain to range is inverted.
15+
public let reversed: Bool
16+
17+
let interpolator: ArrayInterpolator
18+
19+
/// Creates a new sequential scale that maps a _domain_ value to a color.
20+
/// - Parameters:
21+
/// - lower: The lowest value expected for the scale.
22+
/// - higher: The highest value expected for the scale.
23+
/// - reversed: A Boolean value that indicates the color range is reversed.
24+
/// - interpolator: The interpolator that provides the color range to map.
25+
public init(lower: InputType = 0,
26+
higher: InputType = 1,
27+
reversed: Bool = false,
28+
interpolator: ArrayInterpolator)
29+
{
30+
precondition(lower <= higher, "attempting to set an inverted domain: \(lower) to \(higher)")
31+
precondition(lower != higher, "attempting to set an empty domain: \(lower) to \(higher)")
32+
domainLower = lower
33+
domainHigher = higher
34+
self.reversed = reversed
35+
self.interpolator = interpolator
36+
}
37+
38+
// MARK: - description
39+
40+
public var description: String {
41+
"sequential[\(domainLower):\(domainHigher)]->\(type(of: interpolator)))"
42+
}
43+
44+
// MARK: - scaling
45+
946
/// Converts a value comparing it to the input domain, transforming the value, and mapping it between the range values you provide.
1047
///
1148
/// - Parameter inputValue: The value to be scaled.
1249
/// - Returns: A value within the bounds of the range values you provide, or `nil` if the value was dropped.
13-
public func scale(_: InputType) -> OutputType? {
14-
nil
50+
public func scale(_ x: InputType) -> CGColor {
51+
let clampedX: InputType
52+
if x < domainLower {
53+
clampedX = domainLower
54+
} else if x > domainHigher {
55+
clampedX = domainHigher
56+
} else {
57+
clampedX = x
58+
}
59+
let t = normalize(clampedX.toDouble(), lower: domainLower.toDouble(), higher: domainHigher.toDouble())
60+
return interpolator.interpolate(t)
1561
}
1662

1763
// MARK: - modifier functions
1864

19-
/// Returns a new scale with the domain set to the span of values you provide.
65+
/// Returns a new scale with the interpolator set to the instance you provide.
66+
/// - Parameter interpolator: An interpolator instance.
67+
/// - Returns: A copy of the scale with the domain values you provide.
68+
public func interpolator(_ interpolator: ArrayInterpolator) -> Self {
69+
Self(lower: domainLower, higher: domainHigher, reversed: reversed, interpolator: interpolator)
70+
}
71+
72+
/// Returns a new scale with the domain set to the values you provide.
73+
/// - Parameters:
74+
/// - lower: The lower bound for the scale's domain.
75+
/// - higher: The upper bound for the scale's domain.
76+
/// - Returns: A copy of the scale with the domain values you provide.
77+
public func domain(lower: InputType, higher: InputType) -> Self {
78+
Self(lower: lower, higher: higher, reversed: reversed, interpolator: interpolator)
79+
}
80+
81+
/// Returns a new scale with the domain set to the values you provide.
82+
/// - Parameters:
83+
/// - range: The range to apply as the scale's domain
84+
/// - Returns: A copy of the scale with the domain values you provide.
85+
public func domain(_ range: ClosedRange<InputType>) -> Self {
86+
Self(lower: range.lowerBound, higher: range.upperBound, reversed: reversed, interpolator: interpolator)
87+
}
88+
89+
/// Returns a new scale with the domain set to span the values you provide.
2090
/// - Parameter values: An array of input values.
21-
public func domain(_: [InputType]) -> Self {
22-
self
91+
public func domain(_ values: [InputType]) -> Self {
92+
domain(values, nice: true)
2393
}
2494

25-
public var description: String {
26-
"A SEQUENTIAL SCALE"
95+
/// Returns a new scale with the domain inferred from the list of values you provide.
96+
/// - Parameters:
97+
/// - values: The list of values to use to determine the scale's domain.
98+
/// - nice: A Boolean value that indicates whether to expand the domain to visually nice values.
99+
/// - Returns: A copy of the scale with the domain values you provide.
100+
public func domain(_ values: [InputType], nice: Bool) -> Self {
101+
guard let min = values.min(), let max = values.max() else {
102+
return self
103+
}
104+
if values.count == 1 || min == max {
105+
if nice {
106+
let bottom: Double = 0
107+
let top = Double.niceVersion(for: max.toDouble(), trendTowardsZero: false)
108+
return domain(lower: InputType.fromDouble(bottom), higher: InputType.fromDouble(top))
109+
} else {
110+
return domain(lower: 0, higher: max)
111+
}
112+
} else {
113+
if nice {
114+
let bottom = Double.niceMinimumValueForRange(min: min.toDouble(), max: max.toDouble())
115+
let top = Double.niceVersion(for: max.toDouble(), trendTowardsZero: false)
116+
return domain(lower: InputType.fromDouble(bottom), higher: InputType.fromDouble(top))
117+
} else {
118+
return domain(lower: min, higher: max)
119+
}
120+
}
27121
}
28122
}

Sources/SwiftVizScale/interpolation.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,3 @@ func interpolate<T: Real>(_ t: T, lower: T, higher: T) -> T {
1717
// strict interpolation would require: precondition(t >= 0 && t <= 1)
1818
lower + (higher - lower) * t
1919
}
20-
21-
/// A type that provides an interpolated result types between two corresponding instances.
22-
public protocol Interpolator {
23-
/// The type that the interpolator accepts as instances, and returns as an interpolated result.
24-
associatedtype OutputType
25-
/// Provide an instance that is the interpolated value between two others.
26-
/// - Parameter t: A unit value between `0` and `1` that represents the distance between the two values.
27-
/// - Returns: An instance of a type that is the interpolated result based on the value you provide.
28-
func interpolate(_ t: Double) -> OutputType
29-
}

0 commit comments

Comments
 (0)