├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .spi.yml ├── .swift-version ├── Brewfile ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Snippets └── ExampleSnippet.swift ├── Sources ├── SwiftVizScale │ ├── BandScale.swift │ ├── Color │ │ ├── CGColor+hex.swift │ │ └── LCH.swift │ ├── ContinuousScale.swift │ ├── ContinuousScaleType.swift │ ├── DateScale.swift │ ├── DiscreteScale.swift │ ├── Documentation.docc │ │ ├── Band.md │ │ ├── BandScale.md │ │ ├── ColorInterpolator.md │ │ ├── ColorScheme.md │ │ ├── ColorScheme_Cyclical.md │ │ ├── ColorScheme_Diverging.md │ │ ├── ColorScheme_SequentialMultiHue.md │ │ ├── ColorScheme_SequentialSingleHue.md │ │ ├── ComputedRGBInterpolator.md │ │ ├── ContinuousScale.md │ │ ├── DiscreteScale.md │ │ ├── Documentation.md │ │ ├── DomainDataTransform.md │ │ ├── Histogram.md │ │ ├── HistogramBinRange.md │ │ ├── HistogramIterator.md │ │ ├── IndexedColorInterpolator.md │ │ ├── LCH.md │ │ ├── LCHColorInterpolator.md │ │ ├── MakingAndUsingScales.md │ │ ├── PointScale.md │ │ ├── Resources │ │ │ ├── Blues@2x.png │ │ │ ├── BrBG@2x.png │ │ │ ├── BuGn@2x.png │ │ │ ├── BuPu@2x.png │ │ │ ├── Cividis@2x.png │ │ │ ├── GnBu@2x.png │ │ │ ├── Grays@2x.png │ │ │ ├── Greens@2x.png │ │ │ ├── Inferno@2x.png │ │ │ ├── LAB_vs_LCH@2x.png │ │ │ ├── Magma@2x.png │ │ │ ├── OrRd@2x.png │ │ │ ├── Oranges@2x.png │ │ │ ├── PiYG@2x.png │ │ │ ├── Plasma@2x.png │ │ │ ├── PrGN@2x.png │ │ │ ├── PuBu@2x.png │ │ │ ├── PuBuGn@2x.png │ │ │ ├── PuOr@2x.png │ │ │ ├── PuRd@2x.png │ │ │ ├── Purples@2x.png │ │ │ ├── RdBu@2x.png │ │ │ ├── RdGy@2x.png │ │ │ ├── RdPu@2x.png │ │ │ ├── RdYlBu@2x.png │ │ │ ├── RdYlGn@2x.png │ │ │ ├── Reds@2x.png │ │ │ ├── Sinebow@2x.png │ │ │ ├── Spectral@2x.png │ │ │ ├── Turbo@2x.png │ │ │ ├── Viridis@2x.png │ │ │ ├── YlGn@2x.png │ │ │ ├── YlGnBu@2x.png │ │ │ ├── YlOrBr@2x.png │ │ │ └── YlOrRd@2x.png │ │ ├── ReversibleScale.md │ │ ├── Scale.md │ │ ├── SequentialScale.md │ │ ├── Snippets.md │ │ └── Tick.md │ ├── DomainDataTransform.swift │ ├── Histogram │ │ ├── Collection+SimpleStats.swift │ │ ├── Histogram.swift │ │ └── HistogramBinRange.swift │ ├── Interpolation.swift │ ├── Interpolators │ │ ├── ColorInterpolator.swift │ │ ├── ColorScheme.swift │ │ ├── ComputedRGBInterpolator.swift │ │ ├── IndexedColorInterpolator.swift │ │ └── LCHColorInterpolator.swift │ ├── NiceValue.swift │ ├── PointScale.swift │ ├── ReversibleScale.swift │ ├── Scale.swift │ ├── SequentialScale.swift │ └── Tick.swift ├── VisualTests │ ├── ColorInterpolatorView.swift │ ├── InterpolationView.swift │ └── LCHAssembler.swift └── scale-benchmark │ └── main.swift ├── Tests └── SwiftVizScaleTests │ ├── ArrayInterpolatorTests.swift │ ├── BandScaleTests.swift │ ├── ContinuousScaleTests.swift │ ├── DateNiceValueTests.swift │ ├── DateScaleTests.swift │ ├── DiscreteScaleTests.swift │ ├── ExternalPackageTests.swift │ ├── Histogram │ ├── HistogramTests.swift │ └── RandomAccessCollectionStatTests.swift │ ├── InterpolateTests.swift │ ├── LCHTests.swift │ ├── LogScaleTests.swift │ ├── NiceValueTests.swift │ ├── NormalizeTests.swift │ ├── PointScaleTests.swift │ ├── PowerScaleTests.swift │ ├── RadialScaleTests.swift │ ├── ScaleAssertions.swift │ ├── ScaleFactoryTests.swift │ ├── ScaleTemplateTests.swift │ ├── TickTests.swift │ └── TimeScaleTests.swift ├── docbuild.bash ├── docreport.bash ├── docs ├── assets.json ├── css │ ├── chunk-384ef189.7ede1ea3.css │ ├── documentation-topic.29351f99.css │ ├── documentation-topic~topic.fccbd76c.css │ ├── documentation-topic~topic~tutorials-overview.1099452b.css │ ├── index.d5b499b0.css │ ├── topic.726a35dc.css │ └── tutorials-overview.2a582c39.css ├── data │ └── documentation │ │ ├── swiftvizscale.json │ │ └── swiftvizscale │ │ ├── band.json │ │ ├── band │ │ ├── higher.json │ │ ├── lower.json │ │ ├── middle.json │ │ └── value.json │ │ ├── bandscale.json │ │ ├── bandscale │ │ ├── customstringconvertible-implementations.json │ │ ├── defaulttickvalues(formatter:).json │ │ ├── description.json │ │ ├── discretescale-implementations.json │ │ ├── domain(_:).json │ │ ├── domain.json │ │ ├── init(_:paddinginner:paddingouter:round:reversed:from:to:).json │ │ ├── invert(_:)-63wv8.json │ │ ├── invert(_:)-9z1xu.json │ │ ├── invert(_:from:to:).json │ │ ├── invert(_:reversed:from:to:).json │ │ ├── paddinginner(_:).json │ │ ├── paddinginner.json │ │ ├── paddingouter(_:).json │ │ ├── paddingouter.json │ │ ├── range(_:).json │ │ ├── range(lower:higher:).json │ │ ├── range(reversed:_:).json │ │ ├── range(reversed:lower:higher:).json │ │ ├── rangehigher.json │ │ ├── rangelower.json │ │ ├── reversed.json │ │ ├── round(_:).json │ │ ├── round.json │ │ ├── scale(_:).json │ │ ├── scale(_:from:to:).json │ │ ├── scale(_:reversed:from:to:).json │ │ ├── scaletype.json │ │ ├── ticks(rangelower:rangehigher:formatter:).json │ │ └── ticks(reversed:rangelower:rangehigher:formatter:).json │ │ ├── colorinterpolator.json │ │ ├── colorinterpolator │ │ └── interpolate(_:).json │ │ ├── colorscheme.json │ │ ├── colorscheme │ │ ├── cyclical.json │ │ ├── cyclical │ │ │ └── sinebow.json │ │ ├── diverging.json │ │ ├── diverging │ │ │ ├── brbg.json │ │ │ ├── piyg.json │ │ │ ├── prgn.json │ │ │ ├── puor.json │ │ │ ├── rdbu.json │ │ │ ├── rdgy.json │ │ │ ├── rdylbu.json │ │ │ ├── rdylgn.json │ │ │ └── spectral.json │ │ ├── sequentialmultihue.json │ │ ├── sequentialmultihue │ │ │ ├── bugn.json │ │ │ ├── bupu.json │ │ │ ├── cividis.json │ │ │ ├── gnbu.json │ │ │ ├── inferno.json │ │ │ ├── magma.json │ │ │ ├── orrd.json │ │ │ ├── plasma.json │ │ │ ├── pubu.json │ │ │ ├── pubugn.json │ │ │ ├── purd.json │ │ │ ├── rdpu.json │ │ │ ├── turbo.json │ │ │ ├── viridis.json │ │ │ ├── ylgn.json │ │ │ ├── ylgnbu.json │ │ │ ├── ylorbr.json │ │ │ └── ylorrd.json │ │ ├── sequentialsinglehue.json │ │ └── sequentialsinglehue │ │ │ ├── blues.json │ │ │ ├── grays.json │ │ │ ├── greens.json │ │ │ ├── oranges.json │ │ │ ├── purples.json │ │ │ └── reds.json │ │ ├── computedrgbinterpolator.json │ │ ├── computedrgbinterpolator │ │ ├── init(name:r:g:b:).json │ │ └── interpolate(_:).json │ │ ├── continuousscale.json │ │ ├── continuousscale │ │ ├── defaulttickvalues(formatter:).json │ │ ├── description.json │ │ ├── desiredticks.json │ │ ├── domain(_:)-63bua.json │ │ ├── domain(_:)-6qxk9.json │ │ ├── domain(_:)-7oobb.json │ │ ├── domain(_:)-91w7x.json │ │ ├── domain(_:nice:).json │ │ ├── domain(lower:higher:)-5u2ks.json │ │ ├── domain(lower:higher:)-78pku.json │ │ ├── domainhigher.json │ │ ├── domainlower.json │ │ ├── init(_:type:transform:desiredticks:reversed:rangelower:rangehigher:)-4twbk.json │ │ ├── init(_:type:transform:desiredticks:reversed:rangelower:rangehigher:)-5y3b5.json │ │ ├── init(_:type:transform:desiredticks:reversed:rangelower:rangehigher:)-7c7g6.json │ │ ├── init(_:type:transform:desiredticks:reversed:rangelower:rangehigher:)-7n1l8.json │ │ ├── init(lower:higher:type:transform:desiredticks:reversed:rangelower:rangehigher:)-1dq3o.json │ │ ├── init(lower:higher:type:transform:desiredticks:reversed:rangelower:rangehigher:)-6xgot.json │ │ ├── init(type:transform:desiredticks:reversed:rangelower:rangehigher:).json │ │ ├── inputtype.json │ │ ├── invert(_:).json │ │ ├── invert(_:from:to:).json │ │ ├── invert(_:reversed:from:to:).json │ │ ├── invert(_:to:).json │ │ ├── invert(_:to:reversed:).json │ │ ├── range(_:).json │ │ ├── range(lower:higher:).json │ │ ├── range(reversed:_:).json │ │ ├── range(reversed:lower:higher:).json │ │ ├── rangehigher.json │ │ ├── rangelower.json │ │ ├── reversed.json │ │ ├── scale(_:).json │ │ ├── scale(_:from:to:).json │ │ ├── scale(_:reversed:from:to:).json │ │ ├── scale(_:to:).json │ │ ├── scale(_:to:reversed:).json │ │ ├── scaletype(_:).json │ │ ├── scaletype.json │ │ ├── ticks(rangelower:rangehigher:formatter:).json │ │ ├── ticks(reversed:rangelower:rangehigher:formatter:).json │ │ ├── ticksfromvalues(_:reversed:from:to:formatter:)-3u6d8.json │ │ ├── ticksfromvalues(_:reversed:from:to:formatter:)-7mb58.json │ │ ├── transform(_:).json │ │ ├── transformagainstdomain(_:).json │ │ ├── transformtype.json │ │ ├── validtickvalues(_:formatter:)-9dbw.json │ │ └── validtickvalues(_:formatter:)-9ytj1.json │ │ ├── continuousscaletype.json │ │ ├── continuousscaletype │ │ ├── !=(_:_:).json │ │ ├── equatable-implementations.json │ │ ├── linear.json │ │ ├── log.json │ │ ├── power(_:).json │ │ └── radial.json │ │ ├── datemagnitude.json │ │ ├── datemagnitude │ │ ├── !=(_:_:).json │ │ ├── days.json │ │ ├── equatable-implementations.json │ │ ├── hours.json │ │ ├── magnitudeofdaterange(_:_:).json │ │ ├── minutes.json │ │ ├── months.json │ │ ├── seconds-swift.enum.case.json │ │ ├── seconds-swift.property.json │ │ ├── subsecond.json │ │ └── years.json │ │ ├── datescale.json │ │ ├── datescale │ │ ├── defaulttickvalues(formatter:calendar:).json │ │ ├── description.json │ │ ├── desiredticks.json │ │ ├── domain(_:).json │ │ ├── domain(_:nice:).json │ │ ├── domain(lower:higher:).json │ │ ├── domainhigher.json │ │ ├── domainlower.json │ │ ├── init(lower:higher:type:transform:desiredticks:reversed:rangelower:rangehigher:).json │ │ ├── inputtype.json │ │ ├── invert(_:).json │ │ ├── range(_:).json │ │ ├── range(lower:higher:).json │ │ ├── range(reversed:_:).json │ │ ├── range(reversed:lower:higher:).json │ │ ├── rangehigher.json │ │ ├── rangelower.json │ │ ├── reversed.json │ │ ├── scale(_:).json │ │ ├── scaletype(_:).json │ │ ├── scaletype.json │ │ ├── ticks(reversed:rangelower:rangehigher:formatter:calendar:).json │ │ ├── ticksfromvalues(_:reversed:from:to:formatter:).json │ │ ├── transform(_:).json │ │ ├── transformtype.json │ │ └── validtickvalues(_:formatter:).json │ │ ├── discretescale.json │ │ ├── discretescale │ │ ├── defaulttickvalues(formatter:).json │ │ ├── domain.json │ │ ├── rangehigher.json │ │ ├── rangelower.json │ │ ├── scaletype.json │ │ ├── ticks(rangelower:rangehigher:formatter:).json │ │ └── ticks(reversed:rangelower:rangehigher:formatter:).json │ │ ├── discretescaletype.json │ │ ├── discretescaletype │ │ ├── !=(_:_:).json │ │ ├── band.json │ │ ├── equatable-implementations.json │ │ └── point.json │ │ ├── domaindatatransform.json │ │ ├── domaindatatransform │ │ ├── !=(_:_:).json │ │ ├── clamp.json │ │ ├── drop.json │ │ ├── equatable-implementations.json │ │ └── none.json │ │ ├── histogram.json │ │ ├── histogram │ │ ├── allsatisfy(_:).json │ │ ├── compactmap(_:).json │ │ ├── compare(_:_:).json │ │ ├── contains(where:).json │ │ ├── customstringconvertible-implementations.json │ │ ├── description.json │ │ ├── drop(while:).json │ │ ├── dropfirst(_:).json │ │ ├── droplast(_:).json │ │ ├── element.json │ │ ├── elementsequal(_:by:).json │ │ ├── enumerated().json │ │ ├── filter(_:).json │ │ ├── first(where:).json │ │ ├── flatmap(_:)-84z54.json │ │ ├── flatmap(_:)-9hzot.json │ │ ├── foreach(_:).json │ │ ├── formatted(_:).json │ │ ├── histogramiterator.json │ │ ├── histogramiterator │ │ │ └── next().json │ │ ├── init(data:)-4w0u8.json │ │ ├── init(data:)-6k9pg.json │ │ ├── init(data:minimumstride:bounds:desiredcount:)-1kxi5.json │ │ ├── init(data:minimumstride:bounds:desiredcount:)-2c242.json │ │ ├── init(data:thresholds:).json │ │ ├── isempty.json │ │ ├── iterator.json │ │ ├── lazy.json │ │ ├── lexicographicallyprecedes(_:by:).json │ │ ├── lowerbound.json │ │ ├── makeiterator().json │ │ ├── map(_:).json │ │ ├── max(by:).json │ │ ├── min(by:).json │ │ ├── prefix(_:).json │ │ ├── prefix(while:).json │ │ ├── publisher.json │ │ ├── reduce(_:_:).json │ │ ├── reduce(into:_:).json │ │ ├── reversed().json │ │ ├── sequence-implementations.json │ │ ├── shuffled().json │ │ ├── shuffled(using:).json │ │ ├── sorted(by:).json │ │ ├── sorted(using:)-5g2oz.json │ │ ├── sorted(using:)-9hgqm.json │ │ ├── split(maxsplits:omittingemptysubsequences:whereseparator:).json │ │ ├── starts(with:by:).json │ │ ├── suffix(_:).json │ │ ├── underestimatedcount.json │ │ ├── upperbound.json │ │ └── withcontiguousstorageifavailable(_:).json │ │ ├── histogrambinrange.json │ │ ├── histogrambinrange │ │ ├── !=(_:_:).json │ │ ├── '...(_:)-3wsp6.json │ │ ├── '...(_:)-67v4z.json │ │ ├── '...(_:_:).json │ │ ├── '.._(_:).json │ │ ├── '.._(_:_:).json │ │ ├── _(_:_:)-56efr.json │ │ ├── _(_:_:)-9kvsv.json │ │ ├── _=(_:_:)-468vq.json │ │ ├── _=(_:_:)-o5le.json │ │ ├── comparable-implementations.json │ │ ├── contains(_:).json │ │ ├── customstringconvertible-implementations.json │ │ ├── description.json │ │ ├── equatable-implementations.json │ │ ├── lowerbound.json │ │ ├── rangeexpression-implementations.json │ │ ├── relative(to:).json │ │ ├── upperbound.json │ │ └── ~=(_:_:).json │ │ ├── indexedcolorinterpolator.json │ │ ├── indexedcolorinterpolator │ │ ├── init(_:)-3gpbm.json │ │ ├── init(_:)-6i0o1.json │ │ └── interpolate(_:).json │ │ ├── lch.json │ │ ├── lch │ │ ├── color(from:).json │ │ ├── components(from:).json │ │ └── interpolate(_:_:t:).json │ │ ├── lchcolorinterpolator.json │ │ ├── lchcolorinterpolator │ │ ├── init(_:_:).json │ │ └── interpolate(_:).json │ │ ├── makingandusingscales.json │ │ ├── pointscale.json │ │ ├── pointscale │ │ ├── customstringconvertible-implementations.json │ │ ├── defaulttickvalues(formatter:).json │ │ ├── description.json │ │ ├── discretescale-implementations.json │ │ ├── domain(_:).json │ │ ├── domain.json │ │ ├── init(_:padding:round:reversed:from:to:).json │ │ ├── invert(_:).json │ │ ├── invert(_:from:to:).json │ │ ├── invert(_:reversed:from:to:).json │ │ ├── padding(_:).json │ │ ├── padding.json │ │ ├── range(_:).json │ │ ├── range(lower:higher:).json │ │ ├── range(reversed:_:).json │ │ ├── range(reversed:lower:higher:).json │ │ ├── rangehigher.json │ │ ├── rangelower.json │ │ ├── reversed.json │ │ ├── round(_:).json │ │ ├── round.json │ │ ├── scale(_:).json │ │ ├── scale(_:from:to:).json │ │ ├── scale(_:reversed:from:to:).json │ │ ├── scaletype.json │ │ ├── ticks(rangelower:rangehigher:formatter:).json │ │ └── ticks(reversed:rangelower:rangehigher:formatter:).json │ │ ├── reversiblescale.json │ │ ├── reversiblescale │ │ ├── invert(_:).json │ │ ├── range(_:).json │ │ ├── range(lower:higher:).json │ │ ├── range(reversed:_:).json │ │ ├── range(reversed:lower:higher:).json │ │ └── rangetype.json │ │ ├── scale.json │ │ ├── scale │ │ ├── domain(_:).json │ │ ├── inputtype.json │ │ ├── outputtype.json │ │ └── scale(_:).json │ │ ├── sequentialscale.json │ │ ├── sequentialscale │ │ ├── description.json │ │ ├── domain(_:)-5m2g6.json │ │ ├── domain(_:)-ct2c.json │ │ ├── domain(_:nice:).json │ │ ├── domain(lower:higher:).json │ │ ├── domainhigher.json │ │ ├── domainlower.json │ │ ├── init(lower:higher:reversed:interpolator:).json │ │ ├── interpolator(_:).json │ │ ├── reversed.json │ │ └── scale(_:).json │ │ ├── snippets.json │ │ ├── tick.json │ │ └── tick │ │ ├── init(value:location:formatter:).json │ │ ├── label.json │ │ └── rangelocation.json ├── developer-og-twitter.jpg ├── developer-og.jpg ├── diagnostics.json ├── documentation │ └── swiftvizscale │ │ ├── band │ │ ├── higher │ │ │ └── index.html │ │ ├── index.html │ │ ├── lower │ │ │ └── index.html │ │ ├── middle │ │ │ └── index.html │ │ └── value │ │ │ └── index.html │ │ ├── bandscale │ │ ├── customstringconvertible-implementations │ │ │ └── index.html │ │ ├── defaulttickvalues(formatter:) │ │ │ └── index.html │ │ ├── description │ │ │ └── index.html │ │ ├── discretescale-implementations │ │ │ └── index.html │ │ ├── domain(_:) │ │ │ └── index.html │ │ ├── domain │ │ │ └── index.html │ │ ├── index.html │ │ ├── init(_:paddinginner:paddingouter:round:reversed:from:to:) │ │ │ └── index.html │ │ ├── invert(_:)-63wv8 │ │ │ └── index.html │ │ ├── invert(_:)-9z1xu │ │ │ └── index.html │ │ ├── invert(_:from:to:) │ │ │ └── index.html │ │ ├── invert(_:reversed:from:to:) │ │ │ └── index.html │ │ ├── paddinginner(_:) │ │ │ └── index.html │ │ ├── paddinginner │ │ │ └── index.html │ │ ├── paddingouter(_:) │ │ │ └── index.html │ │ ├── paddingouter │ │ │ └── index.html │ │ ├── range(_:) │ │ │ └── index.html │ │ ├── range(lower:higher:) │ │ │ └── index.html │ │ ├── range(reversed:_:) │ │ │ └── index.html │ │ ├── range(reversed:lower:higher:) │ │ │ └── index.html │ │ ├── rangehigher │ │ │ └── index.html │ │ ├── rangelower │ │ │ └── index.html │ │ ├── reversed │ │ │ └── index.html │ │ ├── round(_:) │ │ │ └── index.html │ │ ├── round │ │ │ └── index.html │ │ ├── scale(_:) │ │ │ └── index.html │ │ ├── scale(_:from:to:) │ │ │ └── index.html │ │ ├── scale(_:reversed:from:to:) │ │ │ └── index.html │ │ ├── scaletype │ │ │ └── index.html │ │ ├── ticks(rangelower:rangehigher:formatter:) │ │ │ └── index.html │ │ └── ticks(reversed:rangelower:rangehigher:formatter:) │ │ │ └── index.html │ │ ├── colorinterpolator │ │ ├── index.html │ │ └── interpolate(_:) │ │ │ └── index.html │ │ ├── colorscheme │ │ ├── cyclical │ │ │ ├── index.html │ │ │ └── sinebow │ │ │ │ └── index.html │ │ ├── diverging │ │ │ ├── brbg │ │ │ │ └── index.html │ │ │ ├── index.html │ │ │ ├── piyg │ │ │ │ └── index.html │ │ │ ├── prgn │ │ │ │ └── index.html │ │ │ ├── puor │ │ │ │ └── index.html │ │ │ ├── rdbu │ │ │ │ └── index.html │ │ │ ├── rdgy │ │ │ │ └── index.html │ │ │ ├── rdylbu │ │ │ │ └── index.html │ │ │ ├── rdylgn │ │ │ │ └── index.html │ │ │ └── spectral │ │ │ │ └── index.html │ │ ├── index.html │ │ ├── sequentialmultihue │ │ │ ├── bugn │ │ │ │ └── index.html │ │ │ ├── bupu │ │ │ │ └── index.html │ │ │ ├── cividis │ │ │ │ └── index.html │ │ │ ├── gnbu │ │ │ │ └── index.html │ │ │ ├── index.html │ │ │ ├── inferno │ │ │ │ └── index.html │ │ │ ├── magma │ │ │ │ └── index.html │ │ │ ├── orrd │ │ │ │ └── index.html │ │ │ ├── plasma │ │ │ │ └── index.html │ │ │ ├── pubu │ │ │ │ └── index.html │ │ │ ├── pubugn │ │ │ │ └── index.html │ │ │ ├── purd │ │ │ │ └── index.html │ │ │ ├── rdpu │ │ │ │ └── index.html │ │ │ ├── turbo │ │ │ │ └── index.html │ │ │ ├── viridis │ │ │ │ └── index.html │ │ │ ├── ylgn │ │ │ │ └── index.html │ │ │ ├── ylgnbu │ │ │ │ └── index.html │ │ │ ├── ylorbr │ │ │ │ └── index.html │ │ │ └── ylorrd │ │ │ │ └── index.html │ │ └── sequentialsinglehue │ │ │ ├── blues │ │ │ └── index.html │ │ │ ├── grays │ │ │ └── index.html │ │ │ ├── greens │ │ │ └── index.html │ │ │ ├── index.html │ │ │ ├── oranges │ │ │ └── index.html │ │ │ ├── purples │ │ │ └── index.html │ │ │ └── reds │ │ │ └── index.html │ │ ├── computedrgbinterpolator │ │ ├── index.html │ │ ├── init(name:r:g:b:) │ │ │ └── index.html │ │ └── interpolate(_:) │ │ │ └── index.html │ │ ├── continuousscale │ │ ├── defaulttickvalues(formatter:) │ │ │ └── index.html │ │ ├── description │ │ │ └── index.html │ │ ├── desiredticks │ │ │ └── index.html │ │ ├── domain(_:)-63bua │ │ │ └── index.html │ │ ├── domain(_:)-6qxk9 │ │ │ └── index.html │ │ ├── domain(_:)-7oobb │ │ │ └── index.html │ │ ├── domain(_:)-91w7x │ │ │ └── index.html │ │ ├── domain(_:nice:) │ │ │ └── index.html │ │ ├── domain(lower:higher:)-5u2ks │ │ │ └── index.html │ │ ├── domain(lower:higher:)-78pku │ │ │ └── index.html │ │ ├── domainhigher │ │ │ └── index.html │ │ ├── domainlower │ │ │ └── index.html │ │ ├── index.html │ │ ├── init(_:type:transform:desiredticks:reversed:rangelower:rangehigher:)-4twbk │ │ │ └── index.html │ │ ├── init(_:type:transform:desiredticks:reversed:rangelower:rangehigher:)-5y3b5 │ │ │ └── index.html │ │ ├── init(_:type:transform:desiredticks:reversed:rangelower:rangehigher:)-7c7g6 │ │ │ └── index.html │ │ ├── init(_:type:transform:desiredticks:reversed:rangelower:rangehigher:)-7n1l8 │ │ │ └── index.html │ │ ├── init(lower:higher:type:transform:desiredticks:reversed:rangelower:rangehigher:)-1dq3o │ │ │ └── index.html │ │ ├── init(lower:higher:type:transform:desiredticks:reversed:rangelower:rangehigher:)-6xgot │ │ │ └── index.html │ │ ├── init(type:transform:desiredticks:reversed:rangelower:rangehigher:) │ │ │ └── index.html │ │ ├── inputtype │ │ │ └── index.html │ │ ├── invert(_:) │ │ │ └── index.html │ │ ├── invert(_:from:to:) │ │ │ └── index.html │ │ ├── invert(_:reversed:from:to:) │ │ │ └── index.html │ │ ├── invert(_:to:) │ │ │ └── index.html │ │ ├── invert(_:to:reversed:) │ │ │ └── index.html │ │ ├── range(_:) │ │ │ └── index.html │ │ ├── range(lower:higher:) │ │ │ └── index.html │ │ ├── range(reversed:_:) │ │ │ └── index.html │ │ ├── range(reversed:lower:higher:) │ │ │ └── index.html │ │ ├── rangehigher │ │ │ └── index.html │ │ ├── rangelower │ │ │ └── index.html │ │ ├── reversed │ │ │ └── index.html │ │ ├── scale(_:) │ │ │ └── index.html │ │ ├── scale(_:from:to:) │ │ │ └── index.html │ │ ├── scale(_:reversed:from:to:) │ │ │ └── index.html │ │ ├── scale(_:to:) │ │ │ └── index.html │ │ ├── scale(_:to:reversed:) │ │ │ └── index.html │ │ ├── scaletype(_:) │ │ │ └── index.html │ │ ├── scaletype │ │ │ └── index.html │ │ ├── ticks(rangelower:rangehigher:formatter:) │ │ │ └── index.html │ │ ├── ticks(reversed:rangelower:rangehigher:formatter:) │ │ │ └── index.html │ │ ├── ticksfromvalues(_:reversed:from:to:formatter:)-3u6d8 │ │ │ └── index.html │ │ ├── ticksfromvalues(_:reversed:from:to:formatter:)-7mb58 │ │ │ └── index.html │ │ ├── transform(_:) │ │ │ └── index.html │ │ ├── transformagainstdomain(_:) │ │ │ └── index.html │ │ ├── transformtype │ │ │ └── index.html │ │ ├── validtickvalues(_:formatter:)-9dbw │ │ │ └── index.html │ │ └── validtickvalues(_:formatter:)-9ytj1 │ │ │ └── index.html │ │ ├── continuousscaletype │ │ ├── !=(_:_:) │ │ │ └── index.html │ │ ├── equatable-implementations │ │ │ └── index.html │ │ ├── index.html │ │ ├── linear │ │ │ └── index.html │ │ ├── log │ │ │ └── index.html │ │ ├── power(_:) │ │ │ └── index.html │ │ └── radial │ │ │ └── index.html │ │ ├── datemagnitude │ │ ├── !=(_:_:) │ │ │ └── index.html │ │ ├── days │ │ │ └── index.html │ │ ├── equatable-implementations │ │ │ └── index.html │ │ ├── hours │ │ │ └── index.html │ │ ├── index.html │ │ ├── magnitudeofdaterange(_:_:) │ │ │ └── index.html │ │ ├── minutes │ │ │ └── index.html │ │ ├── months │ │ │ └── index.html │ │ ├── seconds-swift.enum.case │ │ │ └── index.html │ │ ├── seconds-swift.property │ │ │ └── index.html │ │ ├── subsecond │ │ │ └── index.html │ │ └── years │ │ │ └── index.html │ │ ├── datescale │ │ ├── defaulttickvalues(formatter:calendar:) │ │ │ └── index.html │ │ ├── description │ │ │ └── index.html │ │ ├── desiredticks │ │ │ └── index.html │ │ ├── domain(_:) │ │ │ └── index.html │ │ ├── domain(_:nice:) │ │ │ └── index.html │ │ ├── domain(lower:higher:) │ │ │ └── index.html │ │ ├── domainhigher │ │ │ └── index.html │ │ ├── domainlower │ │ │ └── index.html │ │ ├── index.html │ │ ├── init(lower:higher:type:transform:desiredticks:reversed:rangelower:rangehigher:) │ │ │ └── index.html │ │ ├── inputtype │ │ │ └── index.html │ │ ├── invert(_:) │ │ │ └── index.html │ │ ├── range(_:) │ │ │ └── index.html │ │ ├── range(lower:higher:) │ │ │ └── index.html │ │ ├── range(reversed:_:) │ │ │ └── index.html │ │ ├── range(reversed:lower:higher:) │ │ │ └── index.html │ │ ├── rangehigher │ │ │ └── index.html │ │ ├── rangelower │ │ │ └── index.html │ │ ├── reversed │ │ │ └── index.html │ │ ├── scale(_:) │ │ │ └── index.html │ │ ├── scaletype(_:) │ │ │ └── index.html │ │ ├── scaletype │ │ │ └── index.html │ │ ├── ticks(reversed:rangelower:rangehigher:formatter:calendar:) │ │ │ └── index.html │ │ ├── ticksfromvalues(_:reversed:from:to:formatter:) │ │ │ └── index.html │ │ ├── transform(_:) │ │ │ └── index.html │ │ ├── transformtype │ │ │ └── index.html │ │ └── validtickvalues(_:formatter:) │ │ │ └── index.html │ │ ├── discretescale │ │ ├── defaulttickvalues(formatter:) │ │ │ └── index.html │ │ ├── domain │ │ │ └── index.html │ │ ├── index.html │ │ ├── rangehigher │ │ │ └── index.html │ │ ├── rangelower │ │ │ └── index.html │ │ ├── scaletype │ │ │ └── index.html │ │ ├── ticks(rangelower:rangehigher:formatter:) │ │ │ └── index.html │ │ └── ticks(reversed:rangelower:rangehigher:formatter:) │ │ │ └── index.html │ │ ├── discretescaletype │ │ ├── !=(_:_:) │ │ │ └── index.html │ │ ├── band │ │ │ └── index.html │ │ ├── equatable-implementations │ │ │ └── index.html │ │ ├── index.html │ │ └── point │ │ │ └── index.html │ │ ├── domaindatatransform │ │ ├── !=(_:_:) │ │ │ └── index.html │ │ ├── clamp │ │ │ └── index.html │ │ ├── drop │ │ │ └── index.html │ │ ├── equatable-implementations │ │ │ └── index.html │ │ ├── index.html │ │ └── none │ │ │ └── index.html │ │ ├── histogram │ │ ├── allsatisfy(_:) │ │ │ └── index.html │ │ ├── compactmap(_:) │ │ │ └── index.html │ │ ├── compare(_:_:) │ │ │ └── index.html │ │ ├── contains(where:) │ │ │ └── index.html │ │ ├── customstringconvertible-implementations │ │ │ └── index.html │ │ ├── description │ │ │ └── index.html │ │ ├── drop(while:) │ │ │ └── index.html │ │ ├── dropfirst(_:) │ │ │ └── index.html │ │ ├── droplast(_:) │ │ │ └── index.html │ │ ├── element │ │ │ └── index.html │ │ ├── elementsequal(_:by:) │ │ │ └── index.html │ │ ├── enumerated() │ │ │ └── index.html │ │ ├── filter(_:) │ │ │ └── index.html │ │ ├── first(where:) │ │ │ └── index.html │ │ ├── flatmap(_:)-84z54 │ │ │ └── index.html │ │ ├── flatmap(_:)-9hzot │ │ │ └── index.html │ │ ├── foreach(_:) │ │ │ └── index.html │ │ ├── formatted(_:) │ │ │ └── index.html │ │ ├── histogramiterator │ │ │ ├── index.html │ │ │ └── next() │ │ │ │ └── index.html │ │ ├── index.html │ │ ├── init(data:)-4w0u8 │ │ │ └── index.html │ │ ├── init(data:)-6k9pg │ │ │ └── index.html │ │ ├── init(data:minimumstride:bounds:desiredcount:)-1kxi5 │ │ │ └── index.html │ │ ├── init(data:minimumstride:bounds:desiredcount:)-2c242 │ │ │ └── index.html │ │ ├── init(data:thresholds:) │ │ │ └── index.html │ │ ├── isempty │ │ │ └── index.html │ │ ├── iterator │ │ │ └── index.html │ │ ├── lazy │ │ │ └── index.html │ │ ├── lexicographicallyprecedes(_:by:) │ │ │ └── index.html │ │ ├── lowerbound │ │ │ └── index.html │ │ ├── makeiterator() │ │ │ └── index.html │ │ ├── map(_:) │ │ │ └── index.html │ │ ├── max(by:) │ │ │ └── index.html │ │ ├── min(by:) │ │ │ └── index.html │ │ ├── prefix(_:) │ │ │ └── index.html │ │ ├── prefix(while:) │ │ │ └── index.html │ │ ├── publisher │ │ │ └── index.html │ │ ├── reduce(_:_:) │ │ │ └── index.html │ │ ├── reduce(into:_:) │ │ │ └── index.html │ │ ├── reversed() │ │ │ └── index.html │ │ ├── sequence-implementations │ │ │ └── index.html │ │ ├── shuffled() │ │ │ └── index.html │ │ ├── shuffled(using:) │ │ │ └── index.html │ │ ├── sorted(by:) │ │ │ └── index.html │ │ ├── sorted(using:)-5g2oz │ │ │ └── index.html │ │ ├── sorted(using:)-9hgqm │ │ │ └── index.html │ │ ├── split(maxsplits:omittingemptysubsequences:whereseparator:) │ │ │ └── index.html │ │ ├── starts(with:by:) │ │ │ └── index.html │ │ ├── suffix(_:) │ │ │ └── index.html │ │ ├── underestimatedcount │ │ │ └── index.html │ │ ├── upperbound │ │ │ └── index.html │ │ └── withcontiguousstorageifavailable(_:) │ │ │ └── index.html │ │ ├── histogrambinrange │ │ ├── !=(_:_:) │ │ │ └── index.html │ │ ├── '...(_:)-3wsp6 │ │ │ └── index.html │ │ ├── '...(_:)-67v4z │ │ │ └── index.html │ │ ├── '...(_:_:) │ │ │ └── index.html │ │ ├── '.._(_:) │ │ │ └── index.html │ │ ├── '.._(_:_:) │ │ │ └── index.html │ │ ├── _(_:_:)-56efr │ │ │ └── index.html │ │ ├── _(_:_:)-9kvsv │ │ │ └── index.html │ │ ├── _=(_:_:)-468vq │ │ │ └── index.html │ │ ├── _=(_:_:)-o5le │ │ │ └── index.html │ │ ├── comparable-implementations │ │ │ └── index.html │ │ ├── contains(_:) │ │ │ └── index.html │ │ ├── customstringconvertible-implementations │ │ │ └── index.html │ │ ├── description │ │ │ └── index.html │ │ ├── equatable-implementations │ │ │ └── index.html │ │ ├── index.html │ │ ├── lowerbound │ │ │ └── index.html │ │ ├── rangeexpression-implementations │ │ │ └── index.html │ │ ├── relative(to:) │ │ │ └── index.html │ │ ├── upperbound │ │ │ └── index.html │ │ └── ~=(_:_:) │ │ │ └── index.html │ │ ├── index.html │ │ ├── indexedcolorinterpolator │ │ ├── index.html │ │ ├── init(_:)-3gpbm │ │ │ └── index.html │ │ ├── init(_:)-6i0o1 │ │ │ └── index.html │ │ └── interpolate(_:) │ │ │ └── index.html │ │ ├── lch │ │ ├── color(from:) │ │ │ └── index.html │ │ ├── components(from:) │ │ │ └── index.html │ │ ├── index.html │ │ └── interpolate(_:_:t:) │ │ │ └── index.html │ │ ├── lchcolorinterpolator │ │ ├── index.html │ │ ├── init(_:_:) │ │ │ └── index.html │ │ └── interpolate(_:) │ │ │ └── index.html │ │ ├── makingandusingscales │ │ └── index.html │ │ ├── pointscale │ │ ├── customstringconvertible-implementations │ │ │ └── index.html │ │ ├── defaulttickvalues(formatter:) │ │ │ └── index.html │ │ ├── description │ │ │ └── index.html │ │ ├── discretescale-implementations │ │ │ └── index.html │ │ ├── domain(_:) │ │ │ └── index.html │ │ ├── domain │ │ │ └── index.html │ │ ├── index.html │ │ ├── init(_:padding:round:reversed:from:to:) │ │ │ └── index.html │ │ ├── invert(_:) │ │ │ └── index.html │ │ ├── invert(_:from:to:) │ │ │ └── index.html │ │ ├── invert(_:reversed:from:to:) │ │ │ └── index.html │ │ ├── padding(_:) │ │ │ └── index.html │ │ ├── padding │ │ │ └── index.html │ │ ├── range(_:) │ │ │ └── index.html │ │ ├── range(lower:higher:) │ │ │ └── index.html │ │ ├── range(reversed:_:) │ │ │ └── index.html │ │ ├── range(reversed:lower:higher:) │ │ │ └── index.html │ │ ├── rangehigher │ │ │ └── index.html │ │ ├── rangelower │ │ │ └── index.html │ │ ├── reversed │ │ │ └── index.html │ │ ├── round(_:) │ │ │ └── index.html │ │ ├── round │ │ │ └── index.html │ │ ├── scale(_:) │ │ │ └── index.html │ │ ├── scale(_:from:to:) │ │ │ └── index.html │ │ ├── scale(_:reversed:from:to:) │ │ │ └── index.html │ │ ├── scaletype │ │ │ └── index.html │ │ ├── ticks(rangelower:rangehigher:formatter:) │ │ │ └── index.html │ │ └── ticks(reversed:rangelower:rangehigher:formatter:) │ │ │ └── index.html │ │ ├── reversiblescale │ │ ├── index.html │ │ ├── invert(_:) │ │ │ └── index.html │ │ ├── range(_:) │ │ │ └── index.html │ │ ├── range(lower:higher:) │ │ │ └── index.html │ │ ├── range(reversed:_:) │ │ │ └── index.html │ │ ├── range(reversed:lower:higher:) │ │ │ └── index.html │ │ └── rangetype │ │ │ └── index.html │ │ ├── scale │ │ ├── domain(_:) │ │ │ └── index.html │ │ ├── index.html │ │ ├── inputtype │ │ │ └── index.html │ │ ├── outputtype │ │ │ └── index.html │ │ └── scale(_:) │ │ │ └── index.html │ │ ├── sequentialscale │ │ ├── description │ │ │ └── index.html │ │ ├── domain(_:)-5m2g6 │ │ │ └── index.html │ │ ├── domain(_:)-ct2c │ │ │ └── index.html │ │ ├── domain(_:nice:) │ │ │ └── index.html │ │ ├── domain(lower:higher:) │ │ │ └── index.html │ │ ├── domainhigher │ │ │ └── index.html │ │ ├── domainlower │ │ │ └── index.html │ │ ├── index.html │ │ ├── init(lower:higher:reversed:interpolator:) │ │ │ └── index.html │ │ ├── interpolator(_:) │ │ │ └── index.html │ │ ├── reversed │ │ │ └── index.html │ │ └── scale(_:) │ │ │ └── index.html │ │ ├── snippets │ │ └── index.html │ │ └── tick │ │ ├── index.html │ │ ├── init(value:location:formatter:) │ │ └── index.html │ │ ├── label │ │ └── index.html │ │ └── rangelocation │ │ └── index.html ├── favicon.ico ├── favicon.svg ├── images │ ├── Blues@2x.png │ ├── BrBG@2x.png │ ├── BuGn@2x.png │ ├── BuPu@2x.png │ ├── Cividis@2x.png │ ├── GnBu@2x.png │ ├── Grays@2x.png │ ├── Greens@2x.png │ ├── Inferno@2x.png │ ├── LAB_vs_LCH@2x.png │ ├── Magma@2x.png │ ├── OrRd@2x.png │ ├── Oranges@2x.png │ ├── PiYG@2x.png │ ├── Plasma@2x.png │ ├── PrGN@2x.png │ ├── PuBu@2x.png │ ├── PuBuGn@2x.png │ ├── PuOr@2x.png │ ├── PuRd@2x.png │ ├── Purples@2x.png │ ├── RdBu@2x.png │ ├── RdGy@2x.png │ ├── RdPu@2x.png │ ├── RdYlBu@2x.png │ ├── RdYlGn@2x.png │ ├── Reds@2x.png │ ├── Sinebow@2x.png │ ├── Spectral@2x.png │ ├── Turbo@2x.png │ ├── Viridis@2x.png │ ├── YlGn@2x.png │ ├── YlGnBu@2x.png │ ├── YlOrBr@2x.png │ └── YlOrRd@2x.png ├── img │ ├── added-icon.d6f7e47d.svg │ ├── deprecated-icon.015b4f17.svg │ ├── modified-icon.f496e73d.svg │ └── no-image@2x.df2a0a50.png ├── index.html ├── index │ └── index.json ├── indexing-records.json ├── js │ ├── chunk-2d0d3105.cd72cc8e.js │ ├── chunk-384ef189.bb1ed903.js │ ├── chunk-vendors.b24b7aaa.js │ ├── documentation-topic.2ed269e3.js │ ├── documentation-topic~topic.900fc80c.js │ ├── documentation-topic~topic~tutorials-overview.5b27b87b.js │ ├── highlight-js-bash.1b52852f.js │ ├── highlight-js-c.d1db3f17.js │ ├── highlight-js-cpp.eaddddbe.js │ ├── highlight-js-css.75eab1fe.js │ ├── highlight-js-custom-markdown.7cffc4b3.js │ ├── highlight-js-custom-swift.5cda5c20.js │ ├── highlight-js-diff.62d66733.js │ ├── highlight-js-http.163e45b6.js │ ├── highlight-js-java.8326d9d8.js │ ├── highlight-js-javascript.acb8a8eb.js │ ├── highlight-js-json.471128d2.js │ ├── highlight-js-llvm.6100b125.js │ ├── highlight-js-markdown.90077643.js │ ├── highlight-js-objectivec.bcdf5156.js │ ├── highlight-js-perl.757d7b6f.js │ ├── highlight-js-php.cc8d6c27.js │ ├── highlight-js-python.c214ed92.js │ ├── highlight-js-ruby.f889d392.js │ ├── highlight-js-scss.62ee18da.js │ ├── highlight-js-shell.dd7f411f.js │ ├── highlight-js-swift.84f3e88c.js │ ├── highlight-js-xml.9c3688c7.js │ ├── index.aa320932.js │ ├── topic.bb695832.js │ └── tutorials-overview.2cadc732.js ├── linkable-entities.json └── metadata.json ├── preview.bash └── utils ├── .gitignore ├── Package.swift ├── README.md └── Sources └── GenerateDocImages ├── GeneratedDocImagesCommand.swift └── SwiftUI+snapshot.swift /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM swift:5.6.2-focal 2 | 3 | # Install SPM build dependencies 4 | RUN apt-get update && apt-get install -y curl git make unzip \ 5 | sqlite3 libsqlite3-dev 6 | 7 | # Install front-end dependencies 8 | # RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - 9 | # RUN apt-get install -y nodejs 10 | # RUN npm install --global yarn 11 | 12 | RUN apt-get update && apt-get install -y zsh 13 | RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended 14 | RUN curl https://raw.githubusercontent.com/heckj/dotfiles/master/zshrc > ~/.zshrc 15 | RUN chsh -s $(which zsh) 16 | RUN cd /tmp 17 | RUN git clone https://github.com/nicklockwood/SwiftFormat ~/.swiftformat 18 | # RUN cd ~/.swiftformat 19 | # RUN ls -altr 20 | # RUN swift build -c release 21 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spi-base", 3 | "build": { "dockerfile": "Dockerfile" }, 4 | "extensions": [ 5 | "sswg.swift-lang", 6 | ], 7 | "settings": { 8 | "lldb.library": "/usr/lib/liblldb.so" 9 | }, 10 | //"forwardPorts": [8080, 5432, 6432], 11 | 12 | // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 13 | // "remoteUser": "vscode" 14 | } -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | 11 | analyze: 12 | name: Analyze 13 | runs-on: macos-14 14 | permissions: 15 | actions: read 16 | contents: read 17 | security-events: write 18 | 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | language: [ 'swift' ] 23 | 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | 28 | - name: Initialize CodeQL 29 | uses: github/codeql-action/init@v3 30 | with: 31 | languages: ${{ matrix.language }} 32 | 33 | #- name: Autobuild 34 | # uses: github/codeql-action/autobuild@v2 35 | # ^^ doesn't work for a purely swift package 36 | - name: build 37 | run: swift build 38 | #- name: build and test 39 | # run: swift test --enable-code-coverage -v 40 | # or 41 | # - run: xcodebuild -scheme FooBar -sdk iphonesimulator build 42 | 43 | - name: Perform CodeQL Analysis 44 | uses: github/codeql-action/analyze@v2 45 | with: 46 | category: "/language:${{matrix.language}}" 47 | 48 | build: 49 | 50 | runs-on: macos-14 51 | 52 | steps: 53 | - name: Checkout Project 54 | uses: actions/checkout@v4 55 | 56 | - name: Show Build Version 57 | run: xcodebuild -version 58 | 59 | # - name: Show Build Settings 60 | # run: xcodebuild -scheme SwiftViz -showBuildSettings 61 | 62 | # - name: Show Build SDK 63 | # run: xcodebuild -scheme SwiftViz -showsdks 64 | # xcodebuild 65 | 66 | - name: build and test 67 | run: swift test --enable-code-coverage -v 68 | 69 | #- name: Xcode iOS build 70 | #run: xcodebuild clean build -scheme SwiftVizScale-Package -destination 'platform=iOS Simulator,OS=15.5,name=iPhone 8' -showBuildTimingSummary 71 | 72 | #- name: check against API breaking changes 73 | # run: swift package diagnose-api-breaking-changes 0.5.0 74 | 75 | # - name: env review 76 | # run: env 77 | 78 | #- name: doc utility build verification 79 | # run: | 80 | # cd utils 81 | # swift build 82 | 83 | - name: Prepare Code Coverage 84 | run: xcrun llvm-cov export -format="lcov" .build/debug/SwiftVizScalePackageTests.xctest/Contents/MacOS/SwiftVizScalePackageTests -instr-profile .build/debug/codecov/default.profdata > info.lcov 85 | 86 | - name: Upload to CodeCov.io 87 | run: bash <(curl https://codecov.io/bash) 88 | env: 89 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 90 | 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | .DS_Store 6 | /Packages 7 | /*.xcodeproj 8 | .swiftpm 9 | .build 10 | .scale-graphs 11 | Sources/SwiftVizScale/Documentation.docc/.docc-build/ 12 | 13 | utils/Package.resolved 14 | 15 | # docbuild helper sets - generated from docbuild script 16 | all_identifiers.txt 17 | all_symbols.txt 18 | 19 | ## User settings 20 | xcuserdata/ 21 | 22 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 23 | *.xcscmblueprint 24 | *.xccheckout 25 | 26 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 27 | build/ 28 | DerivedData/ 29 | *.moved-aside 30 | *.pbxuser 31 | !default.pbxuser 32 | *.mode1v3 33 | !default.mode1v3 34 | *.mode2v3 35 | !default.mode2v3 36 | *.perspectivev3 37 | !default.perspectivev3 38 | 39 | ## Obj-C/Swift specific 40 | *.hmap 41 | 42 | ## App packaging 43 | *.ipa 44 | *.dSYM.zip 45 | *.dSYM 46 | 47 | ## Playgrounds 48 | timeline.xctimeline 49 | playground.xcworkspace 50 | 51 | # Swift Package Manager 52 | # 53 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 54 | # Packages/ 55 | # Package.pins 56 | # Package.resolved 57 | # *.xcodeproj 58 | # 59 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 60 | # hence it is not needed unless you have added a package configuration file to your project 61 | # .swiftpm 62 | 63 | .build/ 64 | 65 | # CocoaPods 66 | # 67 | # We recommend against adding the Pods directory to your .gitignore. However 68 | # you should judge for yourself, the pros and cons are mentioned at: 69 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 70 | # 71 | # Pods/ 72 | # 73 | # Add this line if you want to avoid checking in source code from the Xcode workspace 74 | # *.xcworkspace 75 | 76 | # Carthage 77 | # 78 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 79 | # Carthage/Checkouts 80 | 81 | Carthage/Build/ 82 | 83 | # Accio dependency management 84 | Dependencies/ 85 | .accio/ 86 | 87 | # fastlane 88 | # 89 | # It is recommended to not store the screenshots in the git repo. 90 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 91 | # For more information about the recommended setup visit: 92 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 93 | 94 | fastlane/report.xml 95 | fastlane/Preview.html 96 | fastlane/screenshots/**/*.png 97 | fastlane/test_output 98 | 99 | # Code Injection 100 | # 101 | # After new code Injection tools there's a generated folder /iOSInjectionProject 102 | # https://github.com/johnno1962/injectionforxcode 103 | 104 | iOSInjectionProject/ 105 | -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | builder: 3 | configs: 4 | - documentation_targets: [SwiftVizScale] 5 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.8 2 | -------------------------------------------------------------------------------- /Brewfile: -------------------------------------------------------------------------------- 1 | brew "swiftformat" 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019, 2020 Joseph Heck 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "swift-collections", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/apple/swift-collections.git", 7 | "state" : { 8 | "revision" : "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb", 9 | "version" : "1.1.0" 10 | } 11 | }, 12 | { 13 | "identity" : "swift-docc-plugin", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/apple/swift-docc-plugin", 16 | "state" : { 17 | "revision" : "26ac5758409154cc448d7ab82389c520fa8a8247", 18 | "version" : "1.3.0" 19 | } 20 | }, 21 | { 22 | "identity" : "swift-docc-symbolkit", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/apple/swift-docc-symbolkit", 25 | "state" : { 26 | "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", 27 | "version" : "1.0.0" 28 | } 29 | } 30 | ], 31 | "version" : 2 32 | } 33 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.8 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import Foundation 5 | import PackageDescription 6 | 7 | let package = Package( 8 | name: "SwiftVizScale", 9 | platforms: [ 10 | .iOS(.v13), 11 | .macOS(.v10_15), 12 | .tvOS(.v13), 13 | .watchOS(.v6), 14 | ], 15 | products: [ 16 | .library( 17 | name: "SwiftVizScale", 18 | targets: ["SwiftVizScale"] 19 | ), 20 | .library(name: "ScaleVisualTests", targets: ["SwiftVizScale", "VisualTests"]), 21 | ], 22 | dependencies: [ 23 | .package( 24 | url: "https://github.com/apple/swift-collections.git", 25 | .upToNextMajor(from: "1.0.0") 26 | ), 27 | .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.1.0"), 28 | ], 29 | targets: [ 30 | .target( 31 | name: "SwiftVizScale", 32 | dependencies: [ 33 | .product(name: "Collections", package: "swift-collections"), 34 | ], 35 | swiftSettings: [ 36 | .enableExperimentalFeature("StrictConcurrency"), 37 | ] 38 | ), 39 | .target( 40 | name: "VisualTests", 41 | dependencies: ["SwiftVizScale"] 42 | ), 43 | .testTarget( 44 | name: "SwiftVizScaleTests", 45 | dependencies: [ 46 | "SwiftVizScale", 47 | ] 48 | ), 49 | ] 50 | ) 51 | 52 | // Checking macOS build w/ Xcode 14 beta 53 | // xcodebuild clean test -scheme SwiftVizScale-Package -destination 'platform=macOS,arch=arm64' 54 | 55 | // Checking iOS build w/ Xcode 14 beta 56 | // xcodebuild clean test -scheme SwiftVizScale-Package -destination 'platform=iOS Simulator,OS=16.0,name=iPhone 8' 57 | 58 | // Checking tvOS build w/ Xcode 14 beta 59 | // xcodebuild clean build -scheme SwiftVizScale-Package -destination 'platform=tvOS Simulator,OS=16.0,name=Apple TV' 60 | 61 | // Checking watchOS build w/ Xcode 14 beta 62 | // xcodebuild clean build -scheme SwiftVizScale-Package -destination 'platform=watchOS Simulator,OS=9.0,name=Apple Watch Series 6 - 44mm' 63 | 64 | if ProcessInfo.processInfo.environment["BENCHMARK"] != nil { 65 | package.products.append( 66 | .executable(name: "scale-benchmark", targets: ["scale-benchmark"]) 67 | ) 68 | package.dependencies.append( 69 | .package(url: "https://github.com/google/swift-benchmark", from: "0.1.0") 70 | ) 71 | package.targets.append( 72 | .executableTarget( 73 | name: "scale-benchmark", 74 | dependencies: [ 75 | "SwiftVizScale", 76 | .product(name: "Benchmark", package: "swift-benchmark"), 77 | ] 78 | ) 79 | ) 80 | } 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftVizScale 2 | 3 | [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fswiftviz%2FScale%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/swiftviz/Scale) 4 | [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fswiftviz%2FScale%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/swiftviz/Scale) 5 | 6 | [![codecov](https://codecov.io/gh/swiftviz/Scale/branch/main/graph/badge.svg?token=fbjd3ei11P)](https://codecov.io/gh/swiftviz/Scale) 7 | 8 | ![@heckj](https://img.shields.io/badge/twitter-@heckj-blue.svg?style=flat "Twitter: @heckj") 9 | 10 | Scale and related types to support creating visualizations. 11 | Loosely based on the APIs and mechanisms created by Mike Bostock and contributors to [D3.js](https://d3js.org) 12 | 13 | ## Build and test 14 | 15 | git clone https://github.com/swiftviz/scale 16 | cd scale 17 | swift test -v 18 | 19 | ## Generate documentation images for the included color scales 20 | 21 | cd utils 22 | swift run GenerateDocImages 23 | 24 | then optionally move the files into the DocC resources directory: 25 | 26 | mv *.png ../Sources/SwiftVizScale/Documentation.docc/Resources/ 27 | 28 | 29 | -------------------------------------------------------------------------------- /Snippets/ExampleSnippet.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SwiftVizScale 3 | 4 | // snippet.setup 5 | func doSomething() { 6 | let linear = ContinuousScale(0.0 ... 50.0) 7 | let scaledValue = linear.scale(3, from: 0, to: 100) 8 | print(String(describing: scaledValue)) 9 | } 10 | 11 | // snippet.end 12 | doSomething() 13 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/ContinuousScaleType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContinuousScaleType.swift 3 | // 4 | 5 | import Foundation 6 | 7 | /// The type of continuous scale. 8 | public enum ContinuousScaleType: Equatable { 9 | /// A linear continuous scale. 10 | case linear 11 | /// A logarithmic continuous scale. 12 | case log 13 | /// An exponential continuous scale. 14 | case power(Double) 15 | /// A linear continuous scale that squares the result. 16 | case radial 17 | 18 | var description: String { 19 | switch self { 20 | case .linear: 21 | "linear" 22 | case .log: 23 | "log" 24 | case let .power(exp): 25 | "power(\(exp))" 26 | case .radial: 27 | "radial" 28 | } 29 | } 30 | 31 | var transform: (Double) -> Double { 32 | switch self { 33 | case .log: 34 | { log10($0) } 35 | case .linear, .radial: 36 | { $0 } 37 | case let .power(exp): 38 | { pow($0, exp) } 39 | } 40 | } 41 | 42 | var invertedTransform: (Double) -> Double { 43 | switch self { 44 | case .log: 45 | { pow(10, $0) } 46 | case .linear, .radial: 47 | { $0 } 48 | case let .power(exp): 49 | { pow($0, 1.0 / exp) } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/DiscreteScale.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DiscreteScale.swift 3 | // 4 | 5 | import Foundation 6 | 7 | /// The type of discrete scale. 8 | public enum DiscreteScaleType: Equatable { 9 | /// A discrete scale that returns a point for the scaled value. 10 | case point 11 | /// A discrete scale that returns a band for the scaled value. 12 | case band 13 | 14 | var description: String { 15 | switch self { 16 | case .point: 17 | "point" 18 | case .band: 19 | "band" 20 | } 21 | } 22 | } 23 | 24 | /// A type that maps discrete values of an input _domain_ to an output _range_. 25 | public protocol DiscreteScale: ReversibleScale, CustomStringConvertible { 26 | var scaleType: DiscreteScaleType { get } 27 | /// The lower value of the range into which the discrete values map. 28 | var rangeLower: RangeType? { get } 29 | /// The upper value of the range into which the discrete values map. 30 | var rangeHigher: RangeType? { get } 31 | 32 | /// An array of the types the scale maps into. 33 | var domain: [InputType] { get } 34 | 35 | /// Returns an array of the strings that make up the ticks for the scale. 36 | /// - Parameter formatter: An optional formatter to convert the domain values into strings. 37 | func defaultTickValues(formatter: Formatter?) -> [String] 38 | 39 | /// Returns an array of the locations within the output range to locate ticks for the scale. 40 | /// - Parameters: 41 | /// - reversed: A Boolean value that indicates if the mapping from domain to range is inverted. 42 | /// - rangeLower: the lower value for the range into which to position the ticks. 43 | /// - rangeHigher: The higher value for the range into which to position the ticks. 44 | /// - formatter: An optional formatter to convert the domain values into strings. 45 | func ticks(reversed: Bool, rangeLower: RangeType, rangeHigher: RangeType, formatter: Formatter?) -> [Tick] 46 | 47 | /// Returns an array of the locations within the output range to locate ticks for the scale. 48 | /// - Parameters: 49 | /// - rangeLower: the lower value for the range into which to position the ticks. 50 | /// - rangeHigher: The higher value for the range into which to position the ticks. 51 | /// - formatter: An optional formatter to convert the domain values into strings. 52 | func ticks(rangeLower: RangeType, rangeHigher: RangeType, formatter: Formatter?) -> [Tick] 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Band.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/Band`` 2 | 3 | ## Topics 4 | 5 | ### Inspecting a Band 6 | 7 | - ``SwiftVizScale/Band/higher`` 8 | - ``SwiftVizScale/Band/middle`` 9 | - ``SwiftVizScale/Band/lower`` 10 | - ``SwiftVizScale/Band/value`` 11 | 12 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/BandScale.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/BandScale`` 2 | 3 | ## Topics 4 | 5 | ### Creating a Band Scale 6 | 7 | - ``SwiftVizScale/BandScale/init(_:paddingInner:paddingOuter:round:reversed:from:to:)`` 8 | 9 | ### Updating Scales 10 | 11 | - ``SwiftVizScale/BandScale/domain(_:)`` 12 | - ``SwiftVizScale/BandScale/round(_:)`` 13 | - ``SwiftVizScale/BandScale/paddingInner(_:)`` 14 | - ``SwiftVizScale/BandScale/paddingOuter(_:)`` 15 | - ``SwiftVizScale/BandScale/range(_:)`` 16 | - ``SwiftVizScale/BandScale/range(lower:higher:)`` 17 | - ``SwiftVizScale/BandScale/range(reversed:_:)`` 18 | - ``SwiftVizScale/BandScale/range(reversed:lower:higher:)`` 19 | 20 | ### Inspecting Scales 21 | 22 | - ``SwiftVizScale/BandScale/domain`` 23 | - ``SwiftVizScale/BandScale/round`` 24 | - ``SwiftVizScale/BandScale/paddingInner`` 25 | - ``SwiftVizScale/BandScale/paddingOuter`` 26 | - ``SwiftVizScale/BandScale/reversed`` 27 | - ``SwiftVizScale/BandScale/rangeLower`` 28 | - ``SwiftVizScale/BandScale/rangeHigher`` 29 | - ``SwiftVizScale/BandScale/scaleType`` 30 | 31 | ### Converting Values 32 | 33 | - ``SwiftVizScale/BandScale/scale(_:)`` 34 | - ``SwiftVizScale/BandScale/scale(_:from:to:)`` 35 | - ``SwiftVizScale/BandScale/scale(_:reversed:from:to:)`` 36 | - ``SwiftVizScale/BandScale/invert(_:)-63wv8`` 37 | - ``SwiftVizScale/BandScale/invert(_:)-9z1xu`` 38 | - ``SwiftVizScale/BandScale/invert(_:from:to:)`` 39 | - ``SwiftVizScale/BandScale/invert(_:reversed:from:to:)`` 40 | 41 | ### Creating Ticks 42 | 43 | - ``SwiftVizScale/BandScale/ticks(rangeLower:rangeHigher:formatter:)`` 44 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ColorInterpolator.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ColorInterpolator`` 2 | 3 | ## Topics 4 | 5 | ### Mapping values to colors 6 | 7 | - ``SwiftVizScale/ColorInterpolator/interpolate(_:)`` 8 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ColorScheme.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ColorScheme`` 2 | 3 | ## Topics 4 | 5 | ### Single Hue Color Schemesw 6 | 7 | - ``SwiftVizScale/ColorScheme/SequentialSingleHue`` 8 | 9 | ### Multi Hue Color Schemes 10 | 11 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue`` 12 | - ``SwiftVizScale/ColorScheme/Diverging`` 13 | - ``SwiftVizScale/ColorScheme/Cyclical`` 14 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ColorScheme_Cyclical.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ColorScheme/Cyclical`` 2 | 3 | 4 | 5 | ## Overview 6 | 7 | Color | Example 8 | --- | --- 9 | ``SwiftVizScale/ColorScheme/Cyclical/Sinebow`` | ![A visual sample of the sinebow cyclical color scheme.](Sinebow.png) 10 | 11 | ## Topics 12 | 13 | ### Cyclical Color Schemes 14 | 15 | - ``SwiftVizScale/ColorScheme/Cyclical/Sinebow`` 16 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ColorScheme_Diverging.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ColorScheme/Diverging`` 2 | 3 | ## Overview 4 | 5 | Color | Example 6 | --- | --- 7 | ``SwiftVizScale/ColorScheme/Diverging/BrBG`` | ![A visual sample of a brown to blue-green diverging color scheme..](BrBG.png) 8 | ``SwiftVizScale/ColorScheme/Diverging/PrGN`` | ![A visual sample of a purple to green diverging color scheme.](PrGN.png) 9 | ``SwiftVizScale/ColorScheme/Diverging/PiYG`` | ![A visual sample of a pink to yellow-green diverging color scheme.](PiYG.png) 10 | ``SwiftVizScale/ColorScheme/Diverging/PuOr`` | ![A visual sample of a purple to orange diverging color scheme.](PuOr.png) 11 | ``SwiftVizScale/ColorScheme/Diverging/RdBu`` | ![A visual sample of a red to blue diverging color scheme..](RdBu.png) 12 | ``SwiftVizScale/ColorScheme/Diverging/RdGy`` | ![A visual sample of a red to grey diverging color scheme.](RdGy.png) 13 | ``SwiftVizScale/ColorScheme/Diverging/RdYlBu`` | ![A visual sample of a red through yellow to green diverging color scheme.](RdYlBu.png) 14 | ``SwiftVizScale/ColorScheme/Diverging/RdYlGn`` | ![A visual sample a red through yellow to green diverging color scheme.](RdYlGn.png) 15 | ``SwiftVizScale/ColorScheme/Diverging/Spectral`` | ![A visual sample of the spectral diverging color scheme.](Spectral.png) 16 | 17 | ## Topics 18 | 19 | ### Diverging Color Schemes 20 | 21 | - ``SwiftVizScale/ColorScheme/Diverging/BrBG`` 22 | - ``SwiftVizScale/ColorScheme/Diverging/PrGN`` 23 | - ``SwiftVizScale/ColorScheme/Diverging/PiYG`` 24 | - ``SwiftVizScale/ColorScheme/Diverging/PuOr`` 25 | - ``SwiftVizScale/ColorScheme/Diverging/RdBu`` 26 | - ``SwiftVizScale/ColorScheme/Diverging/RdGy`` 27 | - ``SwiftVizScale/ColorScheme/Diverging/RdYlBu`` 28 | - ``SwiftVizScale/ColorScheme/Diverging/RdYlGn`` 29 | - ``SwiftVizScale/ColorScheme/Diverging/Spectral`` 30 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ColorScheme_SequentialMultiHue.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ColorScheme/SequentialMultiHue`` 2 | 3 | Color | Example 4 | --- | --- 5 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/BuPu`` | ![A visual sample of a blue through purple sequential color scheme.](BuPu.png) 6 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/GnBu`` | ![A visual sample of a blue to green sequential color scheme.](GnBu.png) 7 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/OrRd`` | ![A visual sample of an orange to red sequential color scheme.](OrRd.png) 8 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/PuBu`` | ![A visual sample of a purple to blue sequential color scheme.](PuBu.png) 9 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/PuBuGn`` | ![A visual sample of a purple through blue to green sequential color scheme.](PuBuGn.png) 10 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/PuRd`` | ![A visual sample of a purple to red sequential color scheme.](PuRd.png) 11 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/RdPu`` | ![A visual sample of a red to purple sequential color scheme.](RdPu.png) 12 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/YlGn`` | ![A visual sample of a yellow to green sequential color scheme.](YlGn.png) 13 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/YlGnBu`` | ![A visual sample of a yellow through green to blue sequential color scheme.](YlGnBu.png) 14 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/YlOrBr`` | ![A visual sample of a yellow through orange to brown sequential color scheme.](YlOrBr.png) 15 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/YlOrRd`` | ![A visual sample of a yellow through orange to red sequential color scheme.](YlOrRd.png) 16 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/Viridis`` | ![A visual sample of the viridis sequential color scheme.](Viridis.png) 17 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/Magma`` | ![A visual sample of the magma sequential color scheme.](Magma.png) 18 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/Inferno`` | ![A visual sample of the inferno sequential color scheme.](Inferno.png) 19 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/Plasma`` | ![A visual sample of the plasma sequential color scheme.](Plasma.png) 20 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/Cividis`` | ![A visual sample of the cividis sequential color scheme.](Cividis.png) 21 | ``SwiftVizScale/ColorScheme/SequentialMultiHue/Turbo`` | ![A visual sample of the turbo sequential color scheme.](Turbo.png) 22 | ## Topics 23 | 24 | ### Sequential Multi Hue Color Schemes 25 | 26 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/BuGn`` 27 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/BuPu`` 28 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/GnBu`` 29 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/OrRd`` 30 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/PuBu`` 31 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/PuBuGn`` 32 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/PuRd`` 33 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/RdPu`` 34 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/RdPu`` 35 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/YlGn`` 36 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/YlGnBu`` 37 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/YlOrBr`` 38 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/YlOrRd`` 39 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/Viridis`` 40 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/Inferno`` 41 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/Magma`` 42 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/Plasma`` 43 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/Cividis`` 44 | - ``SwiftVizScale/ColorScheme/SequentialMultiHue/Turbo`` 45 | 46 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ColorScheme_SequentialSingleHue.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ColorScheme/SequentialSingleHue`` 2 | 3 | ## Overview 4 | 5 | Color | Example 6 | --- | --- 7 | ``SwiftVizScale/ColorScheme/SequentialSingleHue/Oranges`` | ![A visual sample of the white to orange single-hue color scheme.](Oranges.png) 8 | ``SwiftVizScale/ColorScheme/SequentialSingleHue/Purples`` | ![A visual sample of the white to purple single-hue color scheme.](Purples.png) 9 | ``SwiftVizScale/ColorScheme/SequentialSingleHue/Grays`` | ![A visual sample of the white to black single-hue color scheme.](Grays.png) 10 | ``SwiftVizScale/ColorScheme/SequentialSingleHue/Blues`` | ![A visual sample of the white to blue single-hue color scheme.](Blues.png) 11 | ``SwiftVizScale/ColorScheme/SequentialSingleHue/Greens`` | ![A visual sample of the white to green single-hue color scheme.](Greens.png) 12 | ``SwiftVizScale/ColorScheme/SequentialSingleHue/Reds`` | ![A visual sample of the white to red single-hue color scheme.](Reds.png) 13 | 14 | ## Topics 15 | 16 | ### Sequential Single Hue Color Schemes 17 | 18 | - ``SwiftVizScale/ColorScheme/SequentialSingleHue/Oranges`` 19 | - ``SwiftVizScale/ColorScheme/SequentialSingleHue/Purples`` 20 | - ``SwiftVizScale/ColorScheme/SequentialSingleHue/Grays`` 21 | - ``SwiftVizScale/ColorScheme/SequentialSingleHue/Blues`` 22 | - ``SwiftVizScale/ColorScheme/SequentialSingleHue/Greens`` 23 | - ``SwiftVizScale/ColorScheme/SequentialSingleHue/Reds`` 24 | 25 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ComputedRGBInterpolator.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ComputedRGBInterpolator`` 2 | 3 | ## Topics 4 | 5 | ### Creating an Interpolator 6 | 7 | - ``SwiftVizScale/ComputedRGBInterpolator/init(name:r:g:b:)`` 8 | 9 | ### Mapping values to colors 10 | 11 | - ``SwiftVizScale/ComputedRGBInterpolator/interpolate(_:)`` 12 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ContinuousScale.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ContinuousScale`` 2 | 3 | ## Topics 4 | 5 | ### Creating a Continuous Scale 6 | 7 | - ``SwiftVizScale/ContinuousScale/init(_:type:transform:desiredTicks:reversed:rangeLower:rangeHigher:)-4twbk`` 8 | - ``SwiftVizScale/ContinuousScale/init(_:type:transform:desiredTicks:reversed:rangeLower:rangeHigher:)-5y3b5`` 9 | - ``SwiftVizScale/ContinuousScale/init(_:type:transform:desiredTicks:reversed:rangeLower:rangeHigher:)-7c7g6`` 10 | - ``SwiftVizScale/ContinuousScale/init(_:type:transform:desiredTicks:reversed:rangeLower:rangeHigher:)-7n1l8`` 11 | - ``SwiftVizScale/ContinuousScale/init(lower:higher:type:transform:desiredTicks:reversed:rangeLower:rangeHigher:)-1dq3o`` 12 | - ``SwiftVizScale/ContinuousScale/init(lower:higher:type:transform:desiredTicks:reversed:rangeLower:rangeHigher:)-6xgot`` 13 | - ``SwiftVizScale/ContinuousScale/init(type:transform:desiredTicks:reversed:rangeLower:rangeHigher:)`` 14 | 15 | ### Inspecting Scales 16 | 17 | - ``SwiftVizScale/ContinuousScale/domainLower`` 18 | - ``SwiftVizScale/ContinuousScale/domainHigher`` 19 | - ``SwiftVizScale/ContinuousScale/transformType`` 20 | - ``SwiftVizScale/DomainDataTransform`` 21 | - ``SwiftVizScale/ContinuousScale/scaleType`` 22 | - ``SwiftVizScale/ContinuousScaleType`` 23 | - ``SwiftVizScale/ContinuousScale/desiredTicks`` 24 | - ``SwiftVizScale/ContinuousScale/reversed`` 25 | - ``SwiftVizScale/ContinuousScale/rangeHigher`` 26 | - ``SwiftVizScale/ContinuousScale/rangeLower`` 27 | - ``SwiftVizScale/ContinuousScale/description`` 28 | 29 | ### Updating Scales 30 | 31 | - ``SwiftVizScale/ContinuousScale/domain(_:)-63bua`` 32 | - ``SwiftVizScale/ContinuousScale/domain(_:)-6qxk9`` 33 | - ``SwiftVizScale/ContinuousScale/domain(_:)-7oobb`` 34 | - ``SwiftVizScale/ContinuousScale/domain(_:)-91w7x`` 35 | - ``SwiftVizScale/ContinuousScale/domain(_:nice:)`` 36 | - ``SwiftVizScale/ContinuousScale/domain(lower:higher:)-5u2ks`` 37 | - ``SwiftVizScale/ContinuousScale/domain(lower:higher:)-78pku`` 38 | - ``SwiftVizScale/ContinuousScale/scaleType(_:)`` 39 | - ``SwiftVizScale/ContinuousScale/range(_:)`` 40 | - ``SwiftVizScale/ContinuousScale/range(lower:higher:)`` 41 | - ``SwiftVizScale/ContinuousScale/range(reversed:_:)`` 42 | - ``SwiftVizScale/ContinuousScale/range(reversed:lower:higher:)`` 43 | - ``SwiftVizScale/ContinuousScale/transform(_:)`` 44 | 45 | ### Converting Values 46 | 47 | - ``SwiftVizScale/ContinuousScale/scale(_:)`` 48 | - ``SwiftVizScale/ContinuousScale/scale(_:from:to:)`` 49 | - ``SwiftVizScale/ContinuousScale/scale(_:reversed:from:to:)`` 50 | - ``SwiftVizScale/ContinuousScale/scale(_:to:)`` 51 | - ``SwiftVizScale/ContinuousScale/scale(_:to:reversed:)`` 52 | - ``SwiftVizScale/ContinuousScale/invert(_:)`` 53 | - ``SwiftVizScale/ContinuousScale/invert(_:from:to:)`` 54 | - ``SwiftVizScale/ContinuousScale/invert(_:reversed:from:to:)`` 55 | - ``SwiftVizScale/ContinuousScale/invert(_:to:)`` 56 | - ``SwiftVizScale/ContinuousScale/invert(_:to:reversed:)`` 57 | 58 | ### Comparing Values 59 | 60 | - ``SwiftVizScale/ContinuousScale/transformAgainstDomain(_:)`` 61 | 62 | ### Creating Ticks 63 | 64 | - ``SwiftVizScale/ContinuousScale/defaultTickValues(formatter:)`` 65 | - ``SwiftVizScale/ContinuousScale/ticks(rangeLower:rangeHigher:formatter:)`` 66 | - ``SwiftVizScale/ContinuousScale/ticks(reversed:rangeLower:rangeHigher:formatter:)`` 67 | - ``SwiftVizScale/ContinuousScale/ticksFromValues(_:reversed:from:to:formatter:)-3u6d8`` 68 | - ``SwiftVizScale/ContinuousScale/ticksFromValues(_:reversed:from:to:formatter:)-7mb58`` 69 | - ``SwiftVizScale/ContinuousScale/validTickValues(_:formatter:)-9dbw`` 70 | - ``SwiftVizScale/ContinuousScale/validTickValues(_:formatter:)-9ytj1`` 71 | 72 | 73 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/DiscreteScale.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/DiscreteScale`` 2 | 3 | ## Topics 4 | 5 | ### Inspecting Scales 6 | 7 | - ``SwiftVizScale/DiscreteScale/domain`` 8 | - ``SwiftVizScale/DiscreteScale/rangeHigher`` 9 | - ``SwiftVizScale/DiscreteScale/rangeLower`` 10 | - ``SwiftVizScale/DiscreteScale/scaleType`` 11 | - ``SwiftVizScale/DiscreteScaleType`` 12 | 13 | ### Creating Ticks 14 | 15 | - ``SwiftVizScale/DiscreteScale/ticks(rangeLower:rangeHigher:formatter:)`` 16 | - ``SwiftVizScale/DiscreteScale/ticks(reversed:rangeLower:rangeHigher:formatter:)`` 17 | - ``SwiftVizScale/DiscreteScale/defaultTickValues(formatter:)`` 18 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Documentation.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale`` 2 | 3 | A collection of components to provide structures that support data visualization. 4 | 5 | ## Overview 6 | 7 | SwiftViz includes components useful to creating visualizations of data. 8 | Many such visualizations require mapping from an abstract set of input values to another output value. 9 | Continuous scales map from one continuous range to another, such as `0...10` to `5.0...36.0`. 10 | The continuous scales include scales that support linear, logarithmic, and exponential visualization transforms. 11 | Discrete scales map from a discrete range, defined by a collection, to a continuous range, as a point or as a band, with spacing considered in the scale's range. 12 | 13 | Loosely based on the APIs and the visualization constructs created by Mike Bostock and contributors to [D3.js](https://d3js.org) 14 | 15 | ## Topics 16 | 17 | ### Continuous Scales 18 | 19 | - 20 | - ``SwiftVizScale/ContinuousScale`` 21 | - ``SwiftVizScale/ContinuousScaleType`` 22 | - ``SwiftVizScale/DomainDataTransform`` 23 | - ``SwiftVizScale/DateScale`` 24 | - ``SwiftVizScale/DateMagnitude`` 25 | 26 | ### Discrete Scales 27 | 28 | - ``SwiftVizScale/BandScale`` 29 | - ``SwiftVizScale/Band`` 30 | - ``SwiftVizScale/PointScale`` 31 | - ``SwiftVizScale/DiscreteScale`` 32 | - ``SwiftVizScale/DiscreteScaleType`` 33 | 34 | ### Sequential Scales 35 | 36 | - ``SwiftVizScale/SequentialScale`` 37 | 38 | ### Color Interpolators 39 | 40 | - ``SwiftVizScale/ColorInterpolator`` 41 | - ``SwiftVizScale/LCHColorInterpolator`` 42 | - ``SwiftVizScale/LCH`` 43 | - ``SwiftVizScale/IndexedColorInterpolator`` 44 | - ``SwiftVizScale/ComputedRGBInterpolator`` 45 | - ``SwiftVizScale/ColorScheme`` 46 | 47 | ### Histograms 48 | 49 | - ``SwiftVizScale/Histogram`` 50 | - ``SwiftVizScale/HistogramBinRange`` 51 | 52 | ### Ticks 53 | 54 | - ``SwiftVizScale/Tick`` 55 | 56 | ### Supporting Types 57 | 58 | - ``SwiftVizScale/Scale`` 59 | - ``SwiftVizScale/ReversibleScale`` 60 | 61 | ### Snippets 62 | 63 | - 64 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/DomainDataTransform.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/DomainDataTransform`` 2 | 3 | ## Topics 4 | 5 | ### Domain Transform Values 6 | 7 | - ``SwiftVizScale/DomainDataTransform/none`` 8 | - ``SwiftVizScale/DomainDataTransform/clamp`` 9 | - ``SwiftVizScale/DomainDataTransform/drop`` 10 | 11 | ### Comparing Transform Settings 12 | 13 | - ``SwiftVizScale/DomainDataTransform/!=(_:_:)`` 14 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Histogram.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/Histogram`` 2 | 3 | ## Topics 4 | 5 | ### Creating a Histogram 6 | 7 | - ``SwiftVizScale/Histogram/init(data:)-4w0u8`` 8 | - ``SwiftVizScale/Histogram/init(data:)-6k9pg`` 9 | - ``SwiftVizScale/Histogram/init(data:minimumStride:bounds:desiredCount:)-1kxi5`` 10 | - ``SwiftVizScale/Histogram/init(data:minimumStride:bounds:desiredCount:)-2c242`` 11 | - ``SwiftVizScale/Histogram/init(data:thresholds:)`` 12 | 13 | ### Describing Histogram 14 | 15 | - ``SwiftVizScale/Histogram/description`` 16 | 17 | ### Iterating through a Histogram 18 | 19 | - ``SwiftVizScale/Histogram/HistogramIterator`` 20 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/HistogramBinRange.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/HistogramBinRange`` 2 | 3 | ## Topics 4 | 5 | ### Inspecting a HistogramBinRange 6 | 7 | - ``SwiftVizScale/HistogramBinRange/description`` 8 | - ``SwiftVizScale/HistogramBinRange/lowerBound`` 9 | - ``SwiftVizScale/HistogramBinRange/upperBound`` 10 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/HistogramIterator.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/Histogram/HistogramIterator`` 2 | 3 | ## Topics 4 | 5 | ### Iterating 6 | 7 | - ``SwiftVizScale/Histogram/HistogramIterator/next()`` 8 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/IndexedColorInterpolator.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/IndexedColorInterpolator`` 2 | 3 | ## Topics 4 | 5 | ### Creating an Interpolator 6 | 7 | - ``SwiftVizScale/IndexedColorInterpolator/init(_:)-3gpbm`` 8 | - ``SwiftVizScale/IndexedColorInterpolator/init(_:)-6i0o1`` 9 | 10 | ### Mapping values to colors 11 | 12 | - ``SwiftVizScale/IndexedColorInterpolator/interpolate(_:)`` 13 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/LCH.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/LCH`` 2 | 3 | ## Topics 4 | 5 | ### Interpolating Colors 6 | 7 | - ``SwiftVizScale/LCH/interpolate(_:_:t:)`` 8 | 9 | ### Converting Into and Out of LCH Color Space 10 | 11 | - ``SwiftVizScale/LCH/color(from:)`` 12 | - ``SwiftVizScale/LCH/components(from:)`` 13 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/LCHColorInterpolator.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/LCHColorInterpolator`` 2 | 3 | ## Topics 4 | 5 | ### Creating an Interpolator 6 | 7 | - ``SwiftVizScale/LCHColorInterpolator/init(_:_:)`` 8 | 9 | ### Mapping values to colors 10 | 11 | - ``SwiftVizScale/LCHColorInterpolator/interpolate(_:)`` 12 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/MakingAndUsingScales.md: -------------------------------------------------------------------------------- 1 | # Making and Using Scales 2 | 3 | Making Scales Summary 4 | 5 | ## Overview 6 | 7 | Here's something interesting. 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/PointScale.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/PointScale`` 2 | 3 | ## Topics 4 | 5 | ### Creating a Band Scale 6 | 7 | - ``SwiftVizScale/PointScale/init(_:padding:round:reversed:from:to:)`` 8 | 9 | ### Updating Scales 10 | 11 | - ``SwiftVizScale/PointScale/domain(_:)`` 12 | - ``SwiftVizScale/PointScale/round(_:)`` 13 | - ``SwiftVizScale/PointScale/padding(_:)`` 14 | - ``SwiftVizScale/PointScale/range(_:)`` 15 | - ``SwiftVizScale/PointScale/range(lower:higher:)`` 16 | - ``SwiftVizScale/PointScale/range(reversed:_:)`` 17 | - ``SwiftVizScale/PointScale/range(reversed:lower:higher:)`` 18 | 19 | ### Inspecting Scales 20 | 21 | - ``SwiftVizScale/PointScale/domain`` 22 | - ``SwiftVizScale/PointScale/round`` 23 | - ``SwiftVizScale/PointScale/padding`` 24 | - ``SwiftVizScale/PointScale/reversed`` 25 | - ``SwiftVizScale/PointScale/rangeLower`` 26 | - ``SwiftVizScale/PointScale/rangeHigher`` 27 | - ``SwiftVizScale/PointScale/scaleType`` 28 | 29 | ### Converting Values 30 | 31 | - ``SwiftVizScale/PointScale/scale(_:)`` 32 | - ``SwiftVizScale/PointScale/scale(_:from:to:)`` 33 | - ``SwiftVizScale/PointScale/scale(_:reversed:from:to:)`` 34 | - ``SwiftVizScale/PointScale/invert(_:)`` 35 | - ``SwiftVizScale/PointScale/invert(_:from:to:)`` 36 | - ``SwiftVizScale/PointScale/invert(_:reversed:from:to:)`` 37 | 38 | ### Creating Ticks 39 | 40 | - ``SwiftVizScale/PointScale/ticks(rangeLower:rangeHigher:formatter:)`` 41 | - ``SwiftVizScale/PointScale/ticks(reversed:rangeLower:rangeHigher:formatter:)`` 42 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Blues@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Blues@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/BrBG@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/BrBG@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/BuGn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/BuGn@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/BuPu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/BuPu@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Cividis@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Cividis@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/GnBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/GnBu@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Grays@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Grays@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Greens@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Greens@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Inferno@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Inferno@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/LAB_vs_LCH@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/LAB_vs_LCH@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Magma@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Magma@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/OrRd@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/OrRd@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Oranges@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Oranges@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/PiYG@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/PiYG@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Plasma@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Plasma@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/PrGN@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/PrGN@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/PuBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/PuBu@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/PuBuGn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/PuBuGn@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/PuOr@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/PuOr@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/PuRd@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/PuRd@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Purples@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Purples@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/RdBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/RdBu@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/RdGy@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/RdGy@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/RdPu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/RdPu@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/RdYlBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/RdYlBu@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/RdYlGn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/RdYlGn@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Reds@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Reds@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Sinebow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Sinebow@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Spectral@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Spectral@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Turbo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Turbo@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/Viridis@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/Viridis@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/YlGn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/YlGn@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/YlGnBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/YlGnBu@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/YlOrBr@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/YlOrBr@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Resources/YlOrRd@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/Sources/SwiftVizScale/Documentation.docc/Resources/YlOrRd@2x.png -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/ReversibleScale.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/ReversibleScale`` 2 | 3 | ## Topics 4 | 5 | ### Updating Scales 6 | 7 | - ``SwiftVizScale/Scale/domain(_:)`` 8 | - ``SwiftVizScale/ReversibleScale/range(_:)`` 9 | - ``SwiftVizScale/ReversibleScale/range(lower:higher:)`` 10 | - ``SwiftVizScale/ReversibleScale/range(reversed:_:)`` 11 | - ``SwiftVizScale/ReversibleScale/range(reversed:lower:higher:)`` 12 | 13 | ### Converting Values 14 | 15 | - ``SwiftVizScale/Scale/scale(_:)`` 16 | - ``SwiftVizScale/ReversibleScale/invert(_:)`` 17 | 18 | ### Scale Types 19 | 20 | - ``SwiftVizScale/Scale/InputType`` 21 | - ``SwiftVizScale/Scale/OutputType`` 22 | - ``SwiftVizScale/ReversibleScale/RangeType`` 23 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Scale.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/Scale`` 2 | 3 | ## Topics 4 | 5 | ### Updating Scales 6 | 7 | - ``SwiftVizScale/Scale/domain(_:)`` 8 | 9 | ### Converting Values 10 | 11 | - ``SwiftVizScale/Scale/scale(_:)`` 12 | 13 | ### Scale Types 14 | 15 | - ``SwiftVizScale/Scale/InputType`` 16 | - ``SwiftVizScale/Scale/OutputType`` 17 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/SequentialScale.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/SequentialScale`` 2 | 3 | ## Topics 4 | 5 | ### Creating a Sequential Scale 6 | 7 | - ``SwiftVizScale/SequentialScale/init(lower:higher:reversed:interpolator:)`` 8 | 9 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Snippets.md: -------------------------------------------------------------------------------- 1 | # Snippets 2 | 3 | ## Example 4 | 5 | @Snippet(path: "SwiftVizScale/Snippets/ExampleSnippet") 6 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Documentation.docc/Tick.md: -------------------------------------------------------------------------------- 1 | # ``SwiftVizScale/Tick`` 2 | 3 | ## Topics 4 | 5 | ### Creating Ticks 6 | 7 | - ``SwiftVizScale/Tick/init(value:location:formatter:)`` 8 | 9 | ### Inspecting Ticks 10 | 11 | - ``SwiftVizScale/Tick/label`` 12 | - ``SwiftVizScale/Tick/rangeLocation`` 13 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/DomainDataTransform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DomainDataTransform.swift 3 | // 4 | 5 | /// A value that represents how a scale handles data transformation that exceed the domain or range of the scale. 6 | public enum DomainDataTransform { 7 | /// Data processed against a scale isn't influenced by the scale's domain. 8 | case none 9 | /// Data processed against a scale is dropped if the value is outside of the scale's domain. 10 | case drop 11 | /// Data processed against a scale is clamped to the upper and lower values of the scale's domain. 12 | case clamp 13 | 14 | var description: String { 15 | switch self { 16 | case .none: 17 | "none" 18 | case .drop: 19 | "drop" 20 | case .clamp: 21 | "clamp" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Histogram/Collection+SimpleStats.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Collection+SimpleStats.swift 3 | // 4 | 5 | import Foundation 6 | 7 | // for more advanced statistics, consider: https://swiftpackageindex.com/evgenyneu/SigmaSwiftStatistics 8 | 9 | public extension Collection { 10 | func pairs() -> AnySequence<(Element, Element)> { 11 | AnySequence(zip(self, dropFirst())) 12 | } 13 | } 14 | 15 | public extension Collection where Element: BinaryFloatingPoint { 16 | var sum: Double { 17 | reduce(0.0) { $0 + Double($1) } 18 | } 19 | 20 | var sumSquared: Double { 21 | reduce(0.0) { $0 + Double($1) * Double($1) } 22 | } 23 | 24 | var avg: Double { 25 | guard count > 0 else { return 0 } 26 | return sum / Double(count) 27 | } 28 | 29 | var stdDev: Double? { 30 | guard count > 1 else { return nil } 31 | let c = Double(count) 32 | let sum = sum 33 | let s2: Double = (c * sumSquared - sum * sum) / (c * (c - 1)) 34 | return s2.squareRoot() 35 | } 36 | } 37 | 38 | public extension Collection where Element: BinaryInteger { 39 | var sum: Double { 40 | reduce(0.0) { $0 + Double($1) } 41 | } 42 | 43 | var sumSquared: Double { 44 | reduce(0.0) { $0 + Double($1) * Double($1) } 45 | } 46 | 47 | var avg: Double { 48 | guard count > 0 else { return 0 } 49 | return sum / Double(count) 50 | } 51 | 52 | var stdDev: Double? { 53 | guard count > 1 else { return nil } 54 | let c = Double(count) 55 | let sum = sum 56 | let s2: Double = (c * sumSquared - sum * sum) / (c * (c - 1)) 57 | return s2.squareRoot() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Histogram/HistogramBinRange.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HistogramBinRange.swift 3 | // 4 | 5 | import Foundation 6 | 7 | /// The range of data that a single bin of a histogram represents. 8 | /// 9 | /// The bins are expected to be used either independently as an ordered collection, or as the keys for an ordered dictionary. 10 | /// Within the collection, all bins except the last for a particular chart represent an open range. 11 | /// As an open range, the bin doesn’t include the threshold of the upper bound within it. 12 | /// The last bin of the collection is a closed range to include the final upper bound. 13 | public struct HistogramBinRange { 14 | /// The lower bound of the bin range. 15 | public let lowerBound: Bound 16 | /// The upper bound of the bin range. 17 | public let upperBound: Bound 18 | let _final: Bool 19 | 20 | init(lowerBound: Bound, upperBound: Bound, _final: Bool = false) { 21 | self.lowerBound = lowerBound 22 | self.upperBound = upperBound 23 | self._final = _final 24 | } 25 | } 26 | 27 | extension HistogramBinRange: Hashable {} 28 | 29 | extension HistogramBinRange: Comparable { 30 | public static func < (lhs: HistogramBinRange, rhs: HistogramBinRange) -> Bool { 31 | lhs.lowerBound < rhs.lowerBound 32 | } 33 | } 34 | 35 | extension HistogramBinRange: RangeExpression { 36 | /// Returns the range of indices described by this range expression within the given collection. 37 | /// - Parameter collection: The collection to evaluate this range expression in relation to. 38 | /// - Returns: A range suitable for slicing collection. The returned range is not guaranteed to be inside the bounds of collection. Callers should apply the same preconditions to the return value as they would to a range provided directly by the user. 39 | @inlinable 40 | public func relative(to collection: C) -> Range where C: Collection, Bound == C.Index { 41 | Range(uncheckedBounds: ( 42 | lower: lowerBound, 43 | upper: collection.index(after: upperBound) 44 | )) 45 | } 46 | 47 | /// Returns a Boolean value indicating whether the given element is contained within the range expression. 48 | /// - Parameter element: The element to check for containment. 49 | /// - Returns: `true` if element is contained in the range expression; otherwise, `false`. 50 | public func contains(_ element: Bound) -> Bool { 51 | if _final { 52 | element >= lowerBound && element <= upperBound 53 | } else { 54 | element >= lowerBound && element < upperBound 55 | } 56 | } 57 | } 58 | 59 | extension HistogramBinRange: CustomStringConvertible { 60 | /// The description of the bin. 61 | public var description: String { 62 | if _final { 63 | String(describing: lowerBound ... upperBound) 64 | } else { 65 | String(describing: lowerBound ..< upperBound) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Interpolation.swift: -------------------------------------------------------------------------------- 1 | // MARK: - general functions used in various implementations of Scale 2 | 3 | /// normalize(x, a ... b) takes a value x and normalizes it across the domain a...b 4 | /// It returns the corresponding parameter within the range [0...1] if it was within the domain of the scale 5 | /// If the value provided is outside of the domain of the scale, the resulting normalized value will be extrapolated 6 | @inlinable 7 | func normalize(_ x: T, lower: T, higher: T) -> T { 8 | precondition(lower < higher) 9 | let extent = higher - lower 10 | return (x - lower) / extent 11 | } 12 | 13 | /// interpolate(a, b)(t) takes a parameter t in [0,1] and 14 | /// returns the corresponding range value t in [a,b]. 15 | @inlinable 16 | func interpolate(_ t: T, lower: T, higher: T) -> T { 17 | // strict interpolation would require: precondition(t >= 0 && t <= 1) 18 | lower + (higher - lower) * t 19 | } 20 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Interpolators/ColorInterpolator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorInterpolator.swift 3 | // 4 | #if canImport(CoreGraphics) 5 | import CoreGraphics 6 | 7 | /// A type that can provide an interpolated color. 8 | public protocol ColorInterpolator { 9 | /// Returns the color mapped from the unit value you provide. 10 | /// - Parameter t: A unit value between `0` and `1`. 11 | @MainActor 12 | func interpolate(_ t: Double) -> CGColor 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Interpolators/ComputedRGBInterpolator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComputedRGBInterpolator.swift 3 | // 4 | #if canImport(CoreGraphics) 5 | import CoreGraphics 6 | 7 | /// A color interpolator that maps colors based on the output of red, green, and blue closures to compute a final color. 8 | @available(watchOS 6.0, *) 9 | public struct ComputedRGBInterpolator: ColorInterpolator { 10 | let rClosure: (Double) -> Double 11 | let gClosure: (Double) -> Double 12 | let bClosure: (Double) -> Double 13 | let name: String 14 | 15 | /// Creates a new color interpolator that maps between the two colors you provide. 16 | /// - Parameters: 17 | /// - from: The color at the beginning. 18 | /// - to: The color at the end. 19 | public init(name: String, 20 | r: @escaping (Double) -> Double, 21 | g: @escaping (Double) -> Double, 22 | b: @escaping (Double) -> Double) 23 | { 24 | rClosure = r 25 | gClosure = g 26 | bClosure = b 27 | self.name = name 28 | } 29 | 30 | /// Returns the color mapped from the unit value you provide. 31 | /// - Parameter t: A unit value between `0` and `1`. 32 | public func interpolate(_ t: Double) -> CGColor { 33 | let red: CGFloat = rClosure(t) 34 | let green: CGFloat = gClosure(t) 35 | let blue: CGFloat = bClosure(t) 36 | return CGColor(srgbRed: red, green: green, blue: blue, alpha: 1.0) 37 | } 38 | 39 | private static func clampAndNormalize(_ t: Double) -> Double { 40 | max(0, min(255.0, t)) / 255.0 41 | } 42 | 43 | // Equation ported from 44 | // https://github.com/d3/d3-scale-chromatic/blob/main/src/sequential-multi/cividis.js 45 | // Copyright 2010-2021 Mike Bostock, used under License 46 | @MainActor 47 | static let Cividis = ComputedRGBInterpolator(name: "Cividis", r: { t in 48 | clampAndNormalize(-4.54 - t * (35.34 - t * (2381.73 - t * (6402.7 - t * (7024.72 - t * 2710.57))))) 49 | }, g: { t in 50 | clampAndNormalize(32.49 + t * (170.73 + t * (52.82 - t * (131.46 - t * (176.58 - t * 67.37))))) 51 | }, b: { t in 52 | clampAndNormalize(81.24 + t * (442.36 - t * (2482.43 - t * (6167.24 - t * (6614.94 - t * 2475.67))))) 53 | }) 54 | 55 | // Equation ported from 56 | // https://github.com/d3/d3-scale-chromatic/blob/main/src/sequential-multi/turbo.js 57 | // Copyright 2010-2021 Mike Bostock, used under License 58 | @MainActor 59 | static let Turbo = ComputedRGBInterpolator(name: "Turbo", r: { t in 60 | clampAndNormalize(34.61 + t * (1172.33 - t * (10793.56 - t * (33300.12 - t * (38394.49 - t * 14825.05))))) 61 | }, g: { t in 62 | clampAndNormalize(23.31 + t * (557.33 + t * (1225.33 - t * (3574.96 - t * (1073.77 + t * 707.56))))) 63 | }, b: { t in 64 | clampAndNormalize(27.2 + t * (3211.1 - t * (15327.97 - t * (27814 - t * (22569.18 - t * 6838.66))))) 65 | }) 66 | 67 | // Equation ported from 68 | // https://github.com/d3/d3-scale-chromatic/blob/main/src/sequential-multi/sinebow.js 69 | // Copyright 2010-2021 Mike Bostock, used under License 70 | @MainActor 71 | static let Sinebow = ComputedRGBInterpolator(name: "Sinebow", r: { t in 72 | let tMod = (0.5 - t) * Double.pi 73 | return sin(tMod) * sin(tMod) 74 | }, g: { t in 75 | let tMod = (0.5 - t) * Double.pi 76 | return sin(tMod + Double.pi / 3.0) * sin(tMod + Double.pi / 3.0) 77 | }, b: { t in 78 | let tMod = (0.5 - t) * Double.pi 79 | return sin(tMod + 2 * Double.pi / 3.0) * sin(tMod + 2 * Double.pi / 3.0) 80 | }) 81 | } 82 | #endif 83 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Interpolators/LCHColorInterpolator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LCHColorInterpolator.swift 3 | // 4 | #if canImport(CoreGraphics) 5 | import CoreGraphics 6 | 7 | /// A color interpolator that maps colors between two colors through the LCH color space. 8 | @available(watchOS 6.0, *) 9 | public struct LCHColorInterpolator: ColorInterpolator { 10 | let startColor: CGColor 11 | let endColor: CGColor 12 | 13 | /// Creates a new color interpolator that maps between the two colors you provide. 14 | /// - Parameters: 15 | /// - from: The color at the beginning. 16 | /// - to: The color at the end. 17 | public init(_ from: CGColor, _ to: CGColor) { 18 | startColor = from 19 | endColor = to 20 | } 21 | 22 | /// Returns the color mapped from the unit value you provide. 23 | /// - Parameter t: A unit value between `0` and `1`. 24 | @MainActor 25 | public func interpolate(_ t: Double) -> CGColor { 26 | LCH.interpolate(startColor, endColor, t: t) 27 | } 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/ReversibleScale.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReversibleScale.swift 3 | // 4 | 5 | /// A type that maps values from an input _domain_ to an output _range_, or reversed from an output _range_ to a corresponding _domain_ value. 6 | public protocol ReversibleScale: Scale { 7 | /// The type used for the scale's range. 8 | associatedtype RangeType: BinaryFloatingPoint 9 | 10 | /// Converts back from the output _range_ to a value within the input _domain_. 11 | /// 12 | /// - Parameter rangeValue: The value to be scaled back from the range values to the domain. 13 | /// - Returns: A value within the bounds of the range values you provide, or `nil` if the value was dropped. 14 | func invert(_ rangeValue: OutputType) -> InputType? 15 | 16 | // MARK: - modifier functions 17 | 18 | /// Returns a new scale with the range set to the values you provide. 19 | /// - Parameters: 20 | /// - reversed: A Boolean value that indicates if the mapping from domain to range is inverted. 21 | /// - lower: The lower value of the range into which the discrete values map. 22 | /// - higher: The upper value of the range into which the discrete values map. 23 | func range(reversed: Bool, lower: RangeType, higher: RangeType) -> Self 24 | 25 | /// Returns a new scale with the range set to the range you provide. 26 | /// - Parameter reversed: A Boolean value that indicates if the mapping from domain to range is inverted. 27 | /// - Parameter range: The range of the values into which the discrete values map. 28 | func range(reversed: Bool, _ range: ClosedRange) -> Self 29 | 30 | /// Returns a new scale with the range set to the values you provide. 31 | /// - Parameters: 32 | /// - from: The lower value of the range into which the discrete values map. 33 | /// - to: The upper value of the range into which the discrete values map. 34 | func range(lower: RangeType, higher: RangeType) -> Self 35 | 36 | /// Returns a new scale with the range set to the range you provide. 37 | /// - Parameter range: The range of the values into which the discrete values map. 38 | func range(_ range: ClosedRange) -> Self 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Scale.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Scale.swift 3 | // 4 | 5 | /// A type that maps values from an input _domain_ to an output _range_. 6 | public protocol Scale { 7 | /// The type used for the scale's domain. 8 | associatedtype InputType: Comparable 9 | /// The type used for the scale's output. 10 | associatedtype OutputType 11 | 12 | /// Converts a value comparing it to the input domain, transforming the value, and mapping it between the range values you provide. 13 | /// 14 | /// - Parameter inputValue: The value to be scaled. 15 | /// - Returns: A value within the bounds of the range values you provide, or `nil` if the value was dropped. 16 | func scale(_ domainValue: InputType) -> OutputType? 17 | 18 | // MARK: - modifier functions 19 | 20 | /// Returns a new scale with the domain set to the span of values you provide. 21 | /// - Parameter values: An array of input values. 22 | func domain(_ values: [InputType]) -> Self 23 | } 24 | 25 | // Quantize scale: Quantize scales use a discrete range and a 26 | // continuous domain. Range mapping is done by dividing the domain 27 | // evenly by the number of elements in the range. Because the range 28 | // is discrete, the values do not have to be numbers. 29 | 30 | // Quantile scale: Quantile scales are similar to quantize scales, 31 | // but instead of evenly dividing the domain, they determine threshold 32 | // values based on the domain that are used as the cutoffs between 33 | // values in the range. Quantile scales take an array of values for a 34 | // domain (not just a lower and upper limit) and maps range to be an 35 | // even distribution over the input domain 36 | 37 | // Inspired by D3's scale concept - maps input values (domain) to an output range (range) 38 | // - https://github.com/d3/d3-scale 39 | // - https://github.com/pshrmn/notes/blob/master/d3/scales.md 40 | 41 | // import { scaleTime } from 'd3-scale'; 42 | // const time = scaleTime() 43 | // .domain([new Date('1910-1-1'), (new Date('1920-1-1'))]); 44 | // 45 | /// / for UTC 46 | // const utc = d3.scaleUtc(); 47 | // https://github.com/d3/d3-scale#scaleUtc 48 | // https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Scales.md 49 | // Time Scale 50 | // - https://github.com/d3/d3-scale/blob/master/src/time.js 51 | // - D3 has a time format (https://github.com/d3/d3-time-format), but we can probably use 52 | // IOS/MacOS NSTime, NSDate formatters and calendrical mechanisms 53 | -------------------------------------------------------------------------------- /Sources/SwiftVizScale/Tick.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tick.swift 3 | // 4 | 5 | import Foundation 6 | 7 | /// A visual representation of a point along an axis. 8 | /// 9 | /// When created based on a range, a tick includes a location along a single direction 10 | /// and a textual representation. It is meant to be created using a Scale, with some input domain 11 | /// being mapped to visualization using the Scale's output range. 12 | public struct Tick { 13 | /// The location where the tick should be placed within a chart's range. 14 | public let rangeLocation: OutputType 15 | 16 | /// The string value for the tick. 17 | public let label: String 18 | 19 | // Testing interface to make it "easier" to reverse the value into a numeric type 20 | var value: Double? { 21 | Double(label) 22 | } 23 | 24 | /// Creates a new tick. 25 | /// 26 | /// If the location value you provide is NaN, the initializer returns nil. 27 | /// - Parameters: 28 | /// - value: The value at the tick's location. 29 | /// - location: The location of the tick within the range for a scale. 30 | public init?(value: some Any, location: OutputType, formatter: Formatter? = nil) where OutputType: BinaryFloatingPoint { 31 | if location.isNaN { 32 | return nil 33 | } else { 34 | rangeLocation = location 35 | } 36 | if let formatter { 37 | label = formatter.string(for: value) ?? "" 38 | } else { 39 | label = String("\(value)") 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/VisualTests/ColorInterpolatorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorInterpolatorView.swift 3 | // 4 | 5 | #if swift(>=5.7) && canImport(SwiftUI) 6 | 7 | import SwiftUI 8 | @testable import SwiftVizScale 9 | 10 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 11 | public struct ColorInterpolatorView: View { 12 | var steps: CGFloat 13 | var interpolator: any ColorInterpolator 14 | 15 | @MainActor 16 | func color(_ stepValue: Int) -> CGColor { 17 | let t = normalize(Double(stepValue), 18 | lower: 0.0, 19 | higher: steps - 1) 20 | return interpolator.interpolate(t) 21 | } 22 | 23 | public var body: some View { 24 | GeometryReader { proxy in 25 | HStack(spacing: 0.0) { 26 | ForEach(0 ... Int(steps - 1), id: \.self) { stepValue in 27 | Color(cgColor: color(stepValue)) 28 | .frame(width: proxy.size.width / steps) 29 | } 30 | } 31 | } 32 | } 33 | 34 | public init(steps: CGFloat, interpolator: some ColorInterpolator) { 35 | self.steps = steps 36 | self.interpolator = interpolator 37 | } 38 | } 39 | 40 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 41 | struct ColorInterpolatorView_Previews: PreviewProvider { 42 | static var previews: some View { 43 | ColorInterpolatorView(steps: 128, interpolator: ColorScheme.SequentialMultiHue.Cividis) 44 | } 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /Sources/VisualTests/LCHAssembler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LCHAssembler.swift 3 | // 4 | #if canImport(SwiftUI) 5 | import SwiftUI 6 | @testable import SwiftVizScale 7 | 8 | /// Displays the Luminance, Chroma, Hue, and gamma values for LCH components of the color you provide. 9 | @available(watchOS 6.0, *) 10 | struct LCHValues: View { 11 | var values: [CGFloat] 12 | var name: String 13 | var body: some View { 14 | HStack { 15 | Text(name) 16 | Text("L: \(values[0])") 17 | Text("C: \(values[1])") 18 | Text("H: \(values[2])") 19 | Text("a: \(values[3])") 20 | } 21 | } 22 | 23 | @MainActor 24 | public init(color: CGColor, name: String) { 25 | values = LCH.components(from: color) 26 | self.name = name 27 | } 28 | } 29 | 30 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 31 | struct LCHAssembler: View { 32 | static let red = CGColor(srgbRed: 1, green: 0, blue: 0, alpha: 1) 33 | static let blue = CGColor(srgbRed: 0, green: 0, blue: 1, alpha: 1) 34 | static let green = CGColor(srgbRed: 0, green: 1, blue: 0, alpha: 1) 35 | static let white = CGColor(srgbRed: 1, green: 1, blue: 1, alpha: 1) 36 | static let black = CGColor(srgbRed: 0, green: 0, blue: 0, alpha: 1) 37 | 38 | static let yellow = CGColor(srgbRed: 1, green: 1, blue: 0, alpha: 1) 39 | static let purple = CGColor(srgbRed: 1, green: 0, blue: 1, alpha: 1) 40 | static let teal = CGColor(srgbRed: 0, green: 1, blue: 1, alpha: 1) 41 | @State private var L: CGFloat = 100 // luminance ( 0 - 100 ) 42 | @State private var C: CGFloat = 130 // chroma ( 0 - 130 ) 43 | @State private var H: CGFloat = 0 // hue ( iterations of 2*.pi ) 44 | 45 | let decimal: NumberFormatter = { 46 | let formatter = NumberFormatter() 47 | formatter.numberStyle = .decimal 48 | return formatter 49 | }() 50 | 51 | var tau: CGFloat { 52 | CGFloat(Double.pi * 2) 53 | } 54 | 55 | @MainActor 56 | func colorFromLCHComponents(_ l: CGFloat, _ c: CGFloat, _ h: CGFloat) -> CGColor { 57 | LCH.color(from: [l, c, h, 1.0]) 58 | } 59 | 60 | var body: some View { 61 | VStack { 62 | Group { 63 | LCHValues(color: LCHAssembler.red, name: "red") 64 | LCHValues(color: LCHAssembler.blue, name: "blue") 65 | LCHValues(color: LCHAssembler.green, name: "green") 66 | 67 | LCHValues(color: LCHAssembler.white, name: "white") 68 | LCHValues(color: LCHAssembler.black, name: "black") 69 | 70 | LCHValues(color: LCHAssembler.yellow, name: "yellow") 71 | LCHValues(color: LCHAssembler.purple, name: "purple") 72 | LCHValues(color: LCHAssembler.teal, name: "teal") 73 | } 74 | Form { 75 | TextField("L", value: $L, formatter: decimal) 76 | TextField("C", value: $C, formatter: decimal) 77 | TextField("H", value: $H, formatter: decimal) 78 | #if !os(tvOS) 79 | Slider(value: $H, in: -tau ... tau, step: 0.1) 80 | #endif 81 | } 82 | Text("\(L), \(C), \(H)") 83 | Color(cgColor: colorFromLCHComponents(L, C, H)) 84 | .frame(width: 40, height: 40) 85 | } 86 | .padding() 87 | } 88 | } 89 | 90 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 91 | struct LCHAssembler_Previews: PreviewProvider { 92 | static var previews: some View { 93 | LCHAssembler() 94 | } 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /Sources/scale-benchmark/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift - scale-benchmark 3 | // 4 | 5 | import Benchmark 6 | 7 | // BENCHMARK=1 swift build -c release && .build/release/scale-benchmark --iterations 1000 --time-unit ms 8 | 9 | // Dump data into files using additional CLI arguments: 10 | // --format csv > out 11 | // --format json > out 12 | 13 | // CSV results: 14 | // name,time,std,iterations 15 | // add string.no capacity,0.029583,13.01280188086373,1000.0 16 | // add string.reserved capacity,0.023542,9.177574092911641,1000.0 17 | 18 | // JSON results: 19 | // { 20 | // "benchmarks": [ 21 | // { 22 | // "name": "add string.no capacity", 23 | // "time": 0.038417, 24 | // "std": 18.551188319727753, 25 | // "iterations": 1000.0 26 | // }, 27 | // { 28 | // "name": "add string.reserved capacity", 29 | // "time": 0.02575, 30 | // "std": 9.736185458645437, 31 | // "iterations": 1000.0 32 | // } 33 | // ] 34 | // } 35 | 36 | public let addStringBenchmarks = BenchmarkSuite(name: "add string", settings: Iterations(10000)) { 37 | suite in 38 | suite.benchmark("no capacity") { 39 | var x1 = "" 40 | for _ in 1 ... 1000 { 41 | x1 += "hi" 42 | } 43 | } 44 | 45 | suite.benchmark("reserved capacity", settings: Iterations(10001)) { 46 | var x2 = "" 47 | x2.reserveCapacity(2000) 48 | for _ in 1 ... 1000 { 49 | x2 += "hi" 50 | } 51 | } 52 | } 53 | 54 | public let suites = [ 55 | addStringBenchmarks, 56 | ] 57 | 58 | Benchmark.main(suites) 59 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/ArrayInterpolatorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArrayInterpolatorTests.swift 3 | // 4 | 5 | #if canImport(CoreGraphics) 6 | 7 | @testable import SwiftVizScale 8 | import XCTest 9 | 10 | final class ArrayInterpolatorTests: XCTestCase { 11 | func testSweepInterpolateIntoSteps() throws { 12 | for count in 2 ... 10 { 13 | for tValue in 0 ... 10 { 14 | let (index, intermediateTValue) = IndexedColorInterpolator.interpolateIntoSteps(Double(tValue) / 10, count) 15 | XCTAssertTrue(index >= 0) 16 | XCTAssertTrue(index < count - 1) 17 | XCTAssertTrue((0.0 ... 1.0).contains(intermediateTValue)) 18 | } 19 | } 20 | } 21 | 22 | func testHexSequence() throws { 23 | let colors = CGColor.fromHexSequence("010101FFFFFF") 24 | XCTAssertEqual(colors.count, 2) 25 | XCTAssertEqual(colors[0].toHex(), "010101") 26 | XCTAssertEqual(colors[1].toHex(), "FFFFFF") 27 | } 28 | 29 | func testHexSequenceWithBrokenSequence() throws { 30 | let colors = CGColor.fromHexSequence("010101FFFFFFABCD") 31 | XCTAssertEqual(colors.count, 2) 32 | XCTAssertEqual(colors[0].toHex(), "010101") 33 | XCTAssertEqual(colors[1].toHex(), "FFFFFF") 34 | } 35 | 36 | func testHexSequenceWithInvalidSequence() throws { 37 | let colors = CGColor.fromHexSequence("010101FFFFFFgoodbye") 38 | XCTAssertEqual(colors.count, 2) 39 | XCTAssertEqual(colors[0].toHex(), "010101") 40 | XCTAssertEqual(colors[1].toHex(), "FFFFFF") 41 | } 42 | 43 | func testFiveStepInterpolationValues() throws { 44 | // Five colors added means there'll be four breaks: 45 | // 0, 0.25, 0.5, 0.75, and 1.0 46 | let expectedTValueResults = [ 47 | 0.0: (0, 0.0), 48 | 0.1: (0, 0.4), 49 | 0.2: (0, 0.8), 50 | 0.3: (1, 0.2), 51 | 0.4: (1, 0.6), 52 | 0.5: (2, 0.0), 53 | 0.6: (2, 0.4), 54 | 0.7: (2, 0.8), 55 | 0.8: (3, 0.2), 56 | 0.9: (3, 0.6), 57 | 1.0: (3, 1.0), 58 | ] 59 | for (tValue, resultSet) in expectedTValueResults { 60 | let (index, intermediateTValue) = IndexedColorInterpolator.interpolateIntoSteps(tValue, 5) 61 | // print("index: \(index) t: \(intermediateTValue)") 62 | XCTAssertEqual(index, resultSet.0) 63 | XCTAssertEqual(intermediateTValue, resultSet.1, accuracy: 0.001) 64 | } 65 | } 66 | } 67 | #endif 68 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/DiscreteScaleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DiscreteScaleTests.swift 3 | // 4 | 5 | @testable import SwiftVizScale 6 | import XCTest 7 | 8 | class DiscreteScaleTests: XCTestCase { 9 | func testEmptyScale() throws { 10 | let scale = BandScale() 11 | let ticks = scale.ticks(rangeLower: 0, rangeHigher: 10) 12 | XCTAssertEqual(ticks.count, 0) 13 | } 14 | 15 | func testTicksOnPointScaleWithDomain() throws { 16 | let scale = PointScale(["1", "2", "3"]) 17 | let ticks = scale.ticks(rangeLower: 0, rangeHigher: 10) 18 | XCTAssertEqual(ticks.count, 3) 19 | } 20 | 21 | func testTicksOnBandScaleWithDomain() throws { 22 | let scale = BandScale(["1", "2", "3"]) 23 | let ticks = scale.ticks(rangeLower: 0, rangeHigher: 10) 24 | XCTAssertEqual(ticks.count, 3) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/ExternalPackageTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExternalPackageTests.swift 3 | // 4 | 5 | import Foundation 6 | import SwiftVizScale 7 | import XCTest 8 | 9 | final class PackagingTests: XCTestCase { 10 | func testManualTicks() { 11 | let scale = ContinuousScale(lower: 0.0, higher: 10.0, transform: .none) 12 | // verifies the method is visible externally - else this won't compile 13 | let ticks = scale.ticksFromValues([2.0], from: 0.0, to: 10.0) 14 | XCTAssertEqual(ticks.count, 1) 15 | } 16 | 17 | func testManualTicksOutsideRangeNone() { 18 | let scale = ContinuousScale(lower: 0.0, higher: 10.0, transform: .none) 19 | let ticks = scale.ticksFromValues([2.0, 4.0, 8.0, 16.0], from: 0.0, to: 10.0) 20 | XCTAssertEqual(ticks.count, 3) 21 | } 22 | 23 | func testManualTicksOutsideRangeClamped() { 24 | let scale = ContinuousScale(lower: 0.0, higher: 10.0, transform: .clamp) 25 | let ticks = scale.ticksFromValues([2.0, 4.0, 8.0, 16.0], from: 0.0, to: 10.0) 26 | XCTAssertEqual(ticks.count, 3) 27 | } 28 | 29 | func testManualTicksOutsideRangeDropped() { 30 | let scale = ContinuousScale(lower: 0.0, higher: 10.0, transform: .drop) 31 | let ticks = scale.ticksFromValues([2.0, 4.0, 8.0, 16.0], from: 0.0, to: 10.0) 32 | XCTAssertEqual(ticks.count, 3) 33 | } 34 | 35 | func testScaleTransform() { 36 | let scale = ContinuousScale(lower: 0.0, higher: 10.0, transform: .none) 37 | // default isClamped is false - no clamping 38 | let inputs = [11.0, 1.0, 7.0] 39 | XCTAssertEqual(inputs.map { scale.transformAgainstDomain($0) }, inputs) 40 | 41 | let cScale = ContinuousScale(lower: 5.0, higher: 10.0, transform: .clamp) 42 | XCTAssertEqual(inputs.map { cScale.transformAgainstDomain($0) }, [10.0, 5.0, 7.0]) 43 | 44 | let dScale = ContinuousScale(lower: 5.0, higher: 10.0, transform: .drop) 45 | XCTAssertEqual(inputs.map { dScale.transformAgainstDomain($0) }, [nil, nil, 7.0]) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/Histogram/RandomAccessCollectionStatTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RandomAccessCollectionStatTests.swift 3 | // 4 | 5 | import SwiftVizScale 6 | import XCTest 7 | 8 | final class RandomAccessCollectionStatTests: XCTestCase { 9 | let listIntOutliers: [Int] = [3, 6, 2, 2, 65, 7, 5, 2, 21, 5, 7, 8] 10 | let listDoubleOutliers: [Double] = [3, 6, 2, 2, 65, 7, 5, 2, 21, 5, 7, 8] 11 | 12 | let listIntClose: [Int] = [3, 6, 2, 2, 7, 5, 2, 5, 7, 8, 4, 2, 5, 4, 3, 6] 13 | let listDoubleClose: [Double] = [3, 6, 2, 2, 7, 5, 2, 5, 7, 8, 4, 2, 5, 4, 3, 6] 14 | 15 | func testIntSums() throws { 16 | XCTAssertEqual(listIntOutliers.sum, 133) 17 | } 18 | 19 | func testDoubleSums() throws { 20 | XCTAssertEqual(listDoubleOutliers.sum, 133) 21 | } 22 | 23 | func testIntSumSquared() throws { 24 | XCTAssertEqual(listIntOutliers.sumSquared, 4935) 25 | } 26 | 27 | func testDoubleSumSquared() throws { 28 | XCTAssertEqual(listDoubleOutliers.sumSquared, 4935) 29 | } 30 | 31 | func testEmptyIntAverage() throws { 32 | let x: [Int] = [] 33 | XCTAssertEqual(x.avg, 0) 34 | } 35 | 36 | func testEmptyDoubleAverage() throws { 37 | let x: [Double] = [] 38 | XCTAssertEqual(x.avg, 0) 39 | } 40 | 41 | func testIntAverage() throws { 42 | XCTAssertEqual(listIntOutliers.avg, 11.083, accuracy: 0.001) 43 | XCTAssertEqual(listIntClose.avg, 4.4375, accuracy: 0.001) 44 | } 45 | 46 | func testDoubleAverage() throws { 47 | XCTAssertEqual(listDoubleOutliers.avg, 11.083, accuracy: 0.001) 48 | XCTAssertEqual(listDoubleClose.avg, 4.4375, accuracy: 0.001) 49 | } 50 | 51 | func testEmptyIntStdDev() throws { 52 | let x: [Int] = [] 53 | XCTAssertNil(x.stdDev) 54 | } 55 | 56 | func testEmptyDoubleStdDev() throws { 57 | let x: [Double] = [] 58 | XCTAssertNil(x.stdDev) 59 | } 60 | 61 | func testIntStdDev() throws { 62 | XCTAssertNotNil(listIntOutliers.stdDev) 63 | XCTAssertEqual(listIntOutliers.stdDev!, 17.7377, accuracy: 0.001) 64 | XCTAssertEqual(listIntClose.stdDev!, 1.9989, accuracy: 0.001) 65 | } 66 | 67 | func testDoubleStdDev() throws { 68 | XCTAssertNotNil(listDoubleOutliers.stdDev) 69 | XCTAssertEqual(listDoubleOutliers.stdDev!, 17.7377, accuracy: 0.001) 70 | XCTAssertEqual(listDoubleClose.stdDev!, 1.9989, accuracy: 0.001) 71 | } 72 | 73 | func testCollectionPairs() throws { 74 | let x = [1, 2, 3, 6, 10] 75 | let paired = Array(x.pairs()) 76 | XCTAssertEqual(paired.count, 4) 77 | XCTAssertEqual(paired[0].0, 1) 78 | XCTAssertEqual(paired[0].1, 2) 79 | 80 | XCTAssertEqual(paired[1].0, 2) 81 | XCTAssertEqual(paired[1].1, 3) 82 | 83 | XCTAssertEqual(paired[2].0, 3) 84 | XCTAssertEqual(paired[2].1, 6) 85 | 86 | XCTAssertEqual(paired[3].0, 6) 87 | XCTAssertEqual(paired[3].1, 10) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/InterpolateTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InterpolateTests.swift 3 | // 4 | 5 | @testable import SwiftVizScale 6 | import XCTest 7 | 8 | final class InterpolateTests: XCTestCase { 9 | func testInterpolateMid() { 10 | let resultValue = interpolate(0.5, lower: 100.0, higher: 200.0) 11 | XCTAssertEqual(resultValue, 150.0, accuracy: 0.1) 12 | } 13 | 14 | func testInterpolateBelow() { 15 | let resultValue = interpolate(-0.5, lower: 100.0, higher: 200.0) 16 | XCTAssertEqual(resultValue, 50.0, accuracy: 0.1) 17 | } 18 | 19 | func testInterpolateLower() { 20 | let resultValue = interpolate(0.0, lower: 100.0, higher: 200.0) 21 | XCTAssertEqual(resultValue, 100.0, accuracy: 0.1) 22 | } 23 | 24 | func testInterpolateUpper() { 25 | let resultValue = interpolate(1.0, lower: 100.0, higher: 200.0) 26 | XCTAssertEqual(resultValue, 200.0, accuracy: 0.1) 27 | } 28 | 29 | func testInterpolateAbove() { 30 | let resultValue = interpolate(1.5, lower: 100.0, higher: 200.0) 31 | XCTAssertEqual(resultValue, 250.0, accuracy: 0.1) 32 | } 33 | 34 | func testInterpolateNearZero() { 35 | let resultValue = normalize(0.001, lower: 0.0, higher: 100.0) 36 | 37 | XCTAssertFalse(resultValue.isNaN) 38 | XCTAssertEqual(resultValue, 0.0, accuracy: 0.01) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/LCHTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LCHTests.swift 3 | // 4 | 5 | #if canImport(CoreGraphics) 6 | 7 | @testable import SwiftVizScale 8 | import XCTest 9 | 10 | final class LCHTests: XCTestCase { 11 | @MainActor 12 | func testLCHWhiteInterpolation() throws { 13 | // There's not really much to be able to pin down in terms of color space tests, but 14 | // for the LCH color space, and interpolation between white and black shouldn't ever 15 | // adjust the chroma or hue while it does it's thing, so we'll check that as a general 16 | // benchmark. 17 | let black = CGColor(srgbRed: 0, green: 0, blue: 0, alpha: 1) 18 | let white = CGColor(srgbRed: 1, green: 1, blue: 1, alpha: 1) 19 | 20 | for step in 0 ... 99 { 21 | let interpolatedColor = LCH.interpolate(black, white, t: CGFloat(step) / 100.0) 22 | let components = LCH.components(from: interpolatedColor) 23 | // This has notably looser bounds on "0" on iOS while testing w/ Github Actions simulator 24 | XCTAssertEqual(components[1], 0.0, accuracy: 0.1) 25 | // Hue doesn't apparently stay at 0 while testing w/ Github Actions simulator (Xcode 13.2.1) 26 | // XCTAssertEqual(components[2], 0.0, accuracy: 0.001) 27 | XCTAssertEqual(components[3], 1.0, accuracy: 0.001) 28 | } 29 | } 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/NormalizeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NormalizeTests.swift 3 | // 4 | 5 | @testable import SwiftVizScale 6 | import XCTest 7 | 8 | final class NormalizeTests: XCTestCase { 9 | func testNormalizeMid() { 10 | let resultValue = normalize(150.0, lower: 100.0, higher: 200.0) 11 | XCTAssertFalse(resultValue.isNaN) 12 | XCTAssertEqual(resultValue, 0.5, accuracy: 0.01) 13 | } 14 | 15 | func testNormalizeLower() { 16 | let resultValue = normalize(100.0, lower: 100.0, higher: 200.0) 17 | 18 | XCTAssertFalse(resultValue.isNaN) 19 | XCTAssertEqual(resultValue, 0.0, accuracy: 0.01) 20 | } 21 | 22 | func testNormalizeNearZero() { 23 | let resultValue = normalize(0.1, lower: 0.0, higher: 100.0) 24 | 25 | XCTAssertFalse(resultValue.isNaN) 26 | XCTAssertEqual(resultValue, 0.0, accuracy: 0.01) 27 | } 28 | 29 | func testNormalizeUpper() { 30 | let resultValue = normalize(199.9, lower: 100.0, higher: 200.0) 31 | XCTAssertFalse(resultValue.isNaN) 32 | XCTAssertEqual(resultValue, 1.0, accuracy: 0.01) 33 | } 34 | 35 | func testNormalizeUpperLimit() { 36 | let resultValue = normalize(200.0, lower: 100.0, higher: 200.0) 37 | XCTAssertFalse(resultValue.isNaN) 38 | XCTAssertEqual(resultValue, 1.0, accuracy: 0.01) 39 | } 40 | 41 | func testNormalizeAbove() { 42 | let resultValue = normalize(201.0, lower: 100.0, higher: 200.0) 43 | XCTAssertEqual(resultValue, 1.01, accuracy: 0.0001) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/PowerScaleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PowerScaleTests.swift 3 | // 4 | 5 | @testable import SwiftVizScale 6 | import XCTest 7 | 8 | class PowerScaleTests: XCTestCase { 9 | func testPowerScale_scale_identity() throws { 10 | let pow = ContinuousScale(lower: 0, higher: 100, type: .power(1)) 11 | guard let result = pow.scale(2, from: 0, to: 100) else { 12 | XCTFail() 13 | return 14 | } 15 | XCTAssertEqual(result, 2.0, accuracy: 0.001) 16 | } 17 | 18 | func testPowerScale_scale_square() throws { 19 | let pow = ContinuousScale(lower: 0, higher: 10, type: .power(2)) 20 | guard let result = pow.scale(2, from: 0, to: 100) else { 21 | XCTFail() 22 | return 23 | } 24 | XCTAssertEqual(result, 4.0, accuracy: 0.001) 25 | } 26 | 27 | func testPowerScale_invert_identity() throws { 28 | let pow = ContinuousScale(lower: 0, higher: 100, type: .power(1)) 29 | guard let result = pow.invert(5, from: 0, to: 100) else { 30 | XCTFail() 31 | return 32 | } 33 | XCTAssertEqual(result, 5, accuracy: 0.001) 34 | } 35 | 36 | func testPowerScale_invert_square() throws { 37 | let pow = ContinuousScale(lower: 0, higher: 10, type: .power(2)) 38 | guard let result = pow.invert(16, from: 0, to: 100) else { 39 | XCTFail() 40 | return 41 | } 42 | XCTAssertEqual(result, 4, accuracy: 0.001) 43 | } 44 | 45 | func testReversedRangeModifiers() { 46 | var scale = ContinuousScale(0 ... 100, type: .power(1)).range(0 ... 100) 47 | XCTAssertEqual(scale.reversed, false) 48 | scale = ContinuousScale(lower: 0, higher: 100, reversed: true, rangeLower: 0, rangeHigher: 100) 49 | XCTAssertEqual(scale.reversed, true) 50 | scale = scale.range(0 ... 40) 51 | XCTAssertEqual(scale.reversed, true) 52 | scale = scale.range(reversed: false, 0 ... 40) 53 | XCTAssertEqual(scale.reversed, false) 54 | } 55 | 56 | func testReversedCalculations() { 57 | let scale = ContinuousScale(lower: 0, higher: 100, type: .power(1), reversed: true, rangeLower: 0, rangeHigher: 100) 58 | XCTAssertEqual(scale.scale(0), 100) 59 | XCTAssertEqual(scale.scale(100), 0) 60 | XCTAssertEqual(scale.scale(10), 90) 61 | // verify invert 62 | XCTAssertEqual(scale.invert(90)!, 10.0, accuracy: 0.001) 63 | 64 | let forward = scale.range(reversed: false, lower: 0, higher: 100) // log identity 65 | XCTAssertEqual(forward.scale(0), 0) 66 | XCTAssertEqual(forward.scale(100), 100) 67 | XCTAssertEqual(forward.scale(10)!, 10.0, accuracy: 0.001) 68 | // verify invert 69 | XCTAssertEqual(forward.invert(90)!, 90.0, accuracy: 0.001) 70 | } 71 | 72 | func testReversedTicks() { 73 | let reversed = ContinuousScale(lower: 0, higher: 100, type: .power(1), reversed: true, rangeLower: 0, rangeHigher: 100) 74 | let reverseTicks = reversed.ticks(rangeLower: 0, rangeHigher: 20) 75 | XCTAssertEqual(reverseTicks.count, 6) 76 | assertTick(reverseTicks[0], "0.0", 20) 77 | assertTick(reverseTicks[1], "20.0", 16) 78 | assertTick(reverseTicks[2], "40.0", 12) 79 | assertTick(reverseTicks[3], "60.0", 8) 80 | assertTick(reverseTicks[4], "80.0", 4) 81 | assertTick(reverseTicks[5], "100.0", 0) 82 | 83 | let forward = reversed.range(reversed: false, lower: 0, higher: 20) // identity 84 | let forwardTicks = forward.ticks(rangeLower: 0, rangeHigher: 20) 85 | XCTAssertEqual(forwardTicks.count, 6) 86 | assertTick(forwardTicks[0], "0.0", 0) 87 | assertTick(forwardTicks[1], "20.0", 4) 88 | assertTick(forwardTicks[2], "40.0", 8) 89 | assertTick(forwardTicks[3], "60.0", 12) 90 | assertTick(forwardTicks[4], "80.0", 16) 91 | assertTick(forwardTicks[5], "100.0", 20) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/RadialScaleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RadialScaleTests.swift 3 | // 4 | 5 | @testable import SwiftVizScale 6 | import XCTest 7 | 8 | class RadialScaleTests: XCTestCase { 9 | func testRadialScale() { 10 | let myScale = ContinuousScale(lower: 0.0, higher: 10.0, type: .radial) 11 | XCTAssertEqual(myScale.transformType, .none) 12 | XCTAssertEqual(myScale.scaleType, .radial) 13 | XCTAssertEqual(myScale.desiredTicks, 10) 14 | 15 | let testRange = CGFloat(0) ... CGFloat(10.0) 16 | let reconfiguredScale = myScale.range(testRange) 17 | 18 | XCTAssertEqual(4, reconfiguredScale.scale(2)) 19 | XCTAssertEqual(2, reconfiguredScale.invert(4)) 20 | } 21 | 22 | func testRadialScaleRangeInitializer() { 23 | let myScale = ContinuousScale(0.0 ... 10.0, type: .radial, rangeLower: CGFloat(0), rangeHigher: CGFloat(10)) 24 | XCTAssertEqual(myScale.transformType, .none) 25 | XCTAssertEqual(myScale.scaleType, .radial) 26 | XCTAssertEqual(myScale.desiredTicks, 10) 27 | 28 | XCTAssertEqual(myScale.rangeLower, 0) 29 | XCTAssertEqual(myScale.rangeHigher, 10) 30 | } 31 | 32 | func testRadialScaleCompleteInitializer() { 33 | let myScale = ContinuousScale(lower: 0, higher: 100, type: .radial, transform: .clamp, desiredTicks: 5, rangeLower: 0, rangeHigher: 50) 34 | XCTAssertEqual(myScale.transformType, .clamp) 35 | XCTAssertEqual(myScale.scaleType, .radial) 36 | XCTAssertEqual(myScale.desiredTicks, 5) 37 | 38 | XCTAssertEqual(myScale.rangeLower, 0) 39 | XCTAssertEqual(myScale.rangeHigher, 50) 40 | } 41 | 42 | func testReversedCalculations() { 43 | let scale = ContinuousScale(lower: 0, higher: 100, type: .radial, reversed: true, rangeLower: 0, rangeHigher: 100) 44 | XCTAssertEqual(scale.scale(0), 10000) 45 | XCTAssertEqual(scale.scale(100), 0) 46 | XCTAssertEqual(scale.scale(10), 8100) 47 | // verify invert 48 | XCTAssertEqual(scale.invert(8100)!, 10.0, accuracy: 0.001) 49 | 50 | let forward = scale.range(reversed: false, lower: 0, higher: 100) // log identity 51 | XCTAssertEqual(forward.scale(0), 0) 52 | XCTAssertEqual(forward.scale(100), 10000) 53 | XCTAssertEqual(forward.scale(10)!, 100.0, accuracy: 0.001) 54 | // verify invert 55 | XCTAssertEqual(forward.invert(100)!, 10.0, accuracy: 0.001) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/ScaleAssertions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScaleAssertions.swift 3 | // 4 | 5 | import SwiftVizScale 6 | import XCTest 7 | 8 | func assertTick(_ tick: Tick, _ label: String, _ location: CGFloat, file: StaticString = #file, line: UInt = #line) { 9 | XCTAssertEqual(tick.rangeLocation, location, accuracy: 0.001, file: file, line: line) 10 | XCTAssertEqual(tick.label, label, file: file, line: line) 11 | } 12 | 13 | func assertBand(_ band: Band?, _ label: String, low: CGFloat, high: CGFloat, file: StaticString = #file, line: UInt = #line) { 14 | XCTAssertNotNil(band, file: file, line: line) 15 | guard let band else { 16 | return 17 | } 18 | XCTAssertEqual(band.value, label, file: file, line: line) 19 | XCTAssertEqual(band.lower, low, file: file, line: line) 20 | XCTAssertEqual(band.higher, high, file: file, line: line) 21 | } 22 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/ScaleFactoryTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScaleFactoryTests.swift 3 | // 4 | 5 | import SwiftVizScale 6 | import XCTest 7 | 8 | class ScaleFactoryTests: XCTestCase { 9 | func testIntScaleFactoryMethods() throws { 10 | let low = 6 11 | let high = 124 12 | let scale1 = ContinuousScale(lower: low, higher: high) 13 | let scale2 = ContinuousScale(low ... high) 14 | let scale3 = ContinuousScale(high) 15 | 16 | XCTAssertEqual(scale1.domainLower, scale2.domainLower) 17 | XCTAssertEqual(scale1.domainLower, 6) 18 | XCTAssertEqual(scale3.domainLower, 0) 19 | } 20 | 21 | func testDoubleScaleFactoryMethods() throws { 22 | let low: Double = 6 23 | let high: Double = 124 24 | 25 | let scale1 = ContinuousScale(lower: low, higher: high) 26 | let scale2 = ContinuousScale(low ... high) 27 | let scale3 = ContinuousScale(high) 28 | 29 | XCTAssertEqual(scale1.domainLower, scale2.domainLower) 30 | XCTAssertEqual(scale1.domainLower, 6) 31 | XCTAssertEqual(scale3.domainLower, 0) 32 | } 33 | 34 | func testScaleConvenienceMethod() throws { 35 | let lin = ContinuousScale(lower: 0, higher: 100.0) 36 | guard let result = lin.scale(5.0, to: 10.0) else { 37 | XCTFail() 38 | return 39 | } 40 | XCTAssertEqual(result, 0.5, accuracy: 0.001) 41 | } 42 | 43 | func testInvertConvenienceMethod() throws { 44 | let lin = ContinuousScale(lower: 0, higher: 100.0) 45 | guard let result = lin.invert(5.0, to: 10.0) else { 46 | XCTFail() 47 | return 48 | } 49 | XCTAssertEqual(result, 50, accuracy: 0.001) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/SwiftVizScaleTests/ScaleTemplateTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScaleTemplateTests.swift 3 | // 4 | 5 | import Foundation 6 | @testable import SwiftVizScale 7 | import XCTest 8 | 9 | class ScaleTemplateTests: XCTestCase { 10 | func testDefaultInitializers() throws { 11 | let linear = ContinuousScale() 12 | XCTAssertFalse(linear.fullyConfigured()) 13 | 14 | let log = ContinuousScale().scaleType(.log) 15 | XCTAssertFalse(log.fullyConfigured()) 16 | 17 | let power = ContinuousScale().scaleType(.power(1)) 18 | XCTAssertFalse(power.fullyConfigured()) 19 | } 20 | 21 | func testFullyConfiguratedInitializers() throws { 22 | let linear = ContinuousScale(lower: 0, higher: 1) 23 | XCTAssertFalse(linear.fullyConfigured()) 24 | 25 | let log = ContinuousScale(lower: 1, higher: 10).scaleType(.log) 26 | XCTAssertFalse(log.fullyConfigured()) 27 | 28 | let power = ContinuousScale(lower: 0, higher: 1).scaleType(.power(1)) 29 | XCTAssertFalse(power.fullyConfigured()) 30 | } 31 | 32 | func testRefineScaleTemplate() throws { 33 | let linear = ContinuousScale().range(reversed: false, lower: 0, higher: 1) 34 | XCTAssertTrue(linear.fullyConfigured()) 35 | 36 | let log = ContinuousScale().range(lower: 1, higher: 10).scaleType(.log) 37 | XCTAssertTrue(log.fullyConfigured()) 38 | 39 | let power = ContinuousScale().range(lower: 0, higher: 1).scaleType(.power(1)) 40 | XCTAssertTrue(power.fullyConfigured()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /docbuild.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Make sure you've rebased over the current HEAD branch:" 4 | echo "git rebase -i origin/main docs" 5 | 6 | set -e # exit on a non-zero return code from a command 7 | #set -x # print a trace of commands as they execute 8 | 9 | # borrowed filepath from 10 | # https://github.com/apple/swift-markdown/blob/main/bin/update-gh-pages-documentation-site 11 | 12 | filepath() { 13 | [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" 14 | } 15 | 16 | ROOT_DIR="$(dirname $(filepath $0))" 17 | #echo "filepath is $(filepath $0)" 18 | #echo "ROOT_DIR is ${ROOT_DIR}" 19 | # 20 | #rm -rf .build 21 | #mkdir -p .build/symbol-graphs 22 | # 23 | #$(xcrun --find swift) build --target SwiftVizScale \ 24 | # -Xswiftc -emit-symbol-graph \ 25 | # -Xswiftc -emit-symbol-graph-dir -Xswiftc .build/symbol-graphs 26 | # 27 | 28 | # Enables deterministic output 29 | # - useful when you're committing the results to host on github pages 30 | export DOCC_JSON_PRETTYPRINT=YES 31 | 32 | #$(xcrun --find docc) convert Sources/SwiftVizScale/Documentation.docc \ 33 | # --output-path ./docs \ 34 | # --fallback-display-name SwiftVizScale \ 35 | # --fallback-bundle-identifier com.github.swiftviz.SwiftVizScale \ 36 | # --fallback-bundle-version 0.1.9 \ 37 | # --additional-symbol-graph-dir .build/symbol-graphs \ 38 | # --emit-digest \ 39 | # --transform-for-static-hosting \ 40 | # --hosting-base-path 'Scale' 41 | 42 | # Add the following as a dependency into your Package.swift 43 | # 44 | # // Swift-DocC Plugin - swift 5.6 ONLY (GitHhub Actions on 1/29/2022 only supports to 5.5) 45 | # dependencies: [ 46 | # .package(url: "https://github.com/apple/swift-docc-plugin", branch: "main"), 47 | # ], 48 | # run: 49 | # $(xcrun --find swift) package resolve 50 | # $(xcrun --find swift) build 51 | 52 | 53 | # Swift package plugin for hosted content: 54 | # 55 | $(xcrun --find swift) package \ 56 | --allow-writing-to-directory ./docs \ 57 | generate-documentation \ 58 | --fallback-bundle-identifier com.github.swiftviz.SwiftVizScale \ 59 | --target SwiftVizScale \ 60 | --output-path ./docs \ 61 | --emit-digest \ 62 | --disable-indexing \ 63 | --transform-for-static-hosting \ 64 | --hosting-base-path 'Scale' \ 65 | --source-service github \ 66 | --source-service-base-url https://github.com/swiftviz/scale/blob/main \ 67 | --checkout-path ${ROOT_DIR} 68 | 69 | # Generate a list of all the identifiers to assist in DocC curation 70 | # 71 | 72 | cat docs/linkable-entities.json | jq '.[].referenceURL' -r > all_identifiers.txt 73 | sort all_identifiers.txt \ 74 | | sed -e 's/doc:\/\/com\.github\.swiftviz\.SwiftVizScale\/documentation\///g' \ 75 | | sed -e 's/^/- ``/g' \ 76 | | sed -e 's/$/``/g' > all_symbols.txt 77 | 78 | echo "Page will be available at https://swiftviz.github.io/Scale/documentation/swiftvizscale/" 79 | -------------------------------------------------------------------------------- /docreport.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e # exit on a non-zero return code from a command 4 | set -x # print a trace of commands as they execute 5 | 6 | rm -rf .build .scale-graphs 7 | mkdir -p .scale-graphs 8 | 9 | $(xcrun --find swift) build --target SwiftVizScale \ 10 | -Xswiftc -emit-symbol-graph \ 11 | -Xswiftc -emit-symbol-graph-dir -Xswiftc .scale-graphs 12 | 13 | # remove the dependency symbol graphs, unsupported for processing together within DocC today (8Aug2022) 14 | rm -f .scale-graphs/Collections*.json .scale-graphs/DequeModule*.json .scale-graphs/OrderedCollections*.json 15 | # remove the symbol graph for the modules which are extended by SwiftVizScale 16 | rm -f .scale-graphs/SwiftVizScale@Swift.symbols.json 17 | 18 | $(xcrun --find docc) convert Sources/SwiftVizScale/Documentation.docc \ 19 | --analyze \ 20 | --fallback-display-name SwiftVizScale \ 21 | --fallback-bundle-identifier com.github.swiftviz.SwiftVizScale \ 22 | --fallback-bundle-version 0.1.9 \ 23 | --additional-symbol-graph-dir .scale-graphs \ 24 | --experimental-documentation-coverage \ 25 | --level brief 26 | -------------------------------------------------------------------------------- /docs/css/documentation-topic~topic.fccbd76c.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */.generic-modal[data-v-f5b28690]{position:fixed;top:0;left:0;right:0;bottom:0;margin:0;z-index:11000;display:flex;align-items:center;justify-content:center;flex-wrap:wrap;background:none;overflow:auto}.modal-fullscreen[data-v-f5b28690]{align-items:stretch}.modal-fullscreen .container[data-v-f5b28690]{margin:0;flex:1;width:100%;height:100%;padding-top:env(safe-area-inset-top);padding-right:env(safe-area-inset-right);padding-bottom:env(safe-area-inset-bottom);padding-left:env(safe-area-inset-left)}.modal-standard[data-v-f5b28690]{padding:20px}.modal-standard .container[data-v-f5b28690]{padding:60px;border-radius:var(--border-radius,4px)}@media screen{[data-color-scheme=dark] .modal-standard .container[data-v-f5b28690]{background:#1d1d1f}}@media screen and (prefers-color-scheme:dark){[data-color-scheme=auto] .modal-standard .container[data-v-f5b28690]{background:#1d1d1f}}@media only screen and (max-width:735px){.modal-standard[data-v-f5b28690]{padding:0;align-items:stretch}.modal-standard .container[data-v-f5b28690]{margin:20px 0 0;padding:50px 30px;flex:1;width:100%;border-bottom-left-radius:0;border-bottom-right-radius:0}}.backdrop[data-v-f5b28690]{overflow:auto;background:rgba(0,0,0,.4);-webkit-overflow-scrolling:touch;width:100%;height:100%;position:fixed}.container[data-v-f5b28690]{margin-left:auto;margin-right:auto;width:980px;background:var(--colors-generic-modal-background,var(--color-generic-modal-background));z-index:1;position:relative;overflow:auto;max-width:100%}@media only screen and (max-width:1250px){.container[data-v-f5b28690]{width:692px}}@media only screen and (max-width:735px){.container[data-v-f5b28690]{width:87.5%}}.close[data-v-f5b28690]{position:absolute;z-index:9999;top:22px;left:22px;width:30px;height:30px;color:#666;cursor:pointer;background:none;border:0;display:flex;align-items:center}.close .close-icon[data-v-f5b28690]{fill:currentColor;width:100%;height:100%}.theme-dark .container[data-v-f5b28690]{background:#000}.theme-dark .container .close[data-v-f5b28690]{color:#b0b0b0}.theme-code .container[data-v-f5b28690]{background-color:var(--background,var(--color-code-background))} -------------------------------------------------------------------------------- /docs/data/documentation/swiftvizscale/snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "hierarchy" : { 3 | "paths" : [ 4 | [ 5 | "doc:\/\/com.github.swiftviz.SwiftVizScale\/documentation\/SwiftVizScale" 6 | ] 7 | ] 8 | }, 9 | "identifier" : { 10 | "interfaceLanguage" : "swift", 11 | "url" : "doc:\/\/com.github.swiftviz.SwiftVizScale\/documentation\/SwiftVizScale\/Snippets" 12 | }, 13 | "kind" : "article", 14 | "metadata" : { 15 | "modules" : [ 16 | { 17 | "name" : "SwiftVizScale" 18 | } 19 | ], 20 | "role" : "article", 21 | "roleHeading" : "Article", 22 | "title" : "Snippets" 23 | }, 24 | "primaryContentSections" : [ 25 | { 26 | "content" : [ 27 | { 28 | "anchor" : "Example", 29 | "level" : 2, 30 | "text" : "Example", 31 | "type" : "heading" 32 | }, 33 | { 34 | "code" : [ 35 | "import Foundation", 36 | "import SwiftVizScale", 37 | "", 38 | "func doSomething() {", 39 | " let linear = ContinuousScale(0.0 ... 50.0)", 40 | " let scaledValue = linear.scale(3, from: 0, to: 100)", 41 | " print(String(describing: scaledValue))", 42 | "}", 43 | "", 44 | "doSomething()" 45 | ], 46 | "syntax" : "swift", 47 | "type" : "codeListing" 48 | } 49 | ], 50 | "kind" : "content" 51 | } 52 | ], 53 | "schemaVersion" : { 54 | "major" : 0, 55 | "minor" : 3, 56 | "patch" : 0 57 | }, 58 | "sections" : [ 59 | 60 | ], 61 | "variants" : [ 62 | { 63 | "paths" : [ 64 | "\/documentation\/swiftvizscale\/snippets" 65 | ], 66 | "traits" : [ 67 | { 68 | "interfaceLanguage" : "swift" 69 | } 70 | ] 71 | } 72 | ] 73 | , 74 | "references": { 75 | "doc://com.github.swiftviz.SwiftVizScale/documentation/SwiftVizScale": { 76 | "abstract" : [ 77 | { 78 | "text" : "A collection of components to provide structures that support data visualization.", 79 | "type" : "text" 80 | } 81 | ], 82 | "identifier" : "doc:\/\/com.github.swiftviz.SwiftVizScale\/documentation\/SwiftVizScale", 83 | "kind" : "symbol", 84 | "role" : "collection", 85 | "title" : "SwiftVizScale", 86 | "type" : "topic", 87 | "url" : "\/documentation\/swiftvizscale" 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /docs/developer-og-twitter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/developer-og-twitter.jpg -------------------------------------------------------------------------------- /docs/developer-og.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/developer-og.jpg -------------------------------------------------------------------------------- /docs/diagnostics.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ] -------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/band/higher/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/band/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/band/lower/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/band/middle/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/band/value/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/bandscale/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/colorscheme/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/lch/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/scale/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/snippets/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/documentation/swiftvizscale/tick/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/favicon.ico -------------------------------------------------------------------------------- /docs/favicon.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/images/Blues@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Blues@2x.png -------------------------------------------------------------------------------- /docs/images/BrBG@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/BrBG@2x.png -------------------------------------------------------------------------------- /docs/images/BuGn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/BuGn@2x.png -------------------------------------------------------------------------------- /docs/images/BuPu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/BuPu@2x.png -------------------------------------------------------------------------------- /docs/images/Cividis@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Cividis@2x.png -------------------------------------------------------------------------------- /docs/images/GnBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/GnBu@2x.png -------------------------------------------------------------------------------- /docs/images/Grays@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Grays@2x.png -------------------------------------------------------------------------------- /docs/images/Greens@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Greens@2x.png -------------------------------------------------------------------------------- /docs/images/Inferno@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Inferno@2x.png -------------------------------------------------------------------------------- /docs/images/LAB_vs_LCH@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/LAB_vs_LCH@2x.png -------------------------------------------------------------------------------- /docs/images/Magma@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Magma@2x.png -------------------------------------------------------------------------------- /docs/images/OrRd@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/OrRd@2x.png -------------------------------------------------------------------------------- /docs/images/Oranges@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Oranges@2x.png -------------------------------------------------------------------------------- /docs/images/PiYG@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/PiYG@2x.png -------------------------------------------------------------------------------- /docs/images/Plasma@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Plasma@2x.png -------------------------------------------------------------------------------- /docs/images/PrGN@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/PrGN@2x.png -------------------------------------------------------------------------------- /docs/images/PuBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/PuBu@2x.png -------------------------------------------------------------------------------- /docs/images/PuBuGn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/PuBuGn@2x.png -------------------------------------------------------------------------------- /docs/images/PuOr@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/PuOr@2x.png -------------------------------------------------------------------------------- /docs/images/PuRd@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/PuRd@2x.png -------------------------------------------------------------------------------- /docs/images/Purples@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Purples@2x.png -------------------------------------------------------------------------------- /docs/images/RdBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/RdBu@2x.png -------------------------------------------------------------------------------- /docs/images/RdGy@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/RdGy@2x.png -------------------------------------------------------------------------------- /docs/images/RdPu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/RdPu@2x.png -------------------------------------------------------------------------------- /docs/images/RdYlBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/RdYlBu@2x.png -------------------------------------------------------------------------------- /docs/images/RdYlGn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/RdYlGn@2x.png -------------------------------------------------------------------------------- /docs/images/Reds@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Reds@2x.png -------------------------------------------------------------------------------- /docs/images/Sinebow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Sinebow@2x.png -------------------------------------------------------------------------------- /docs/images/Spectral@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Spectral@2x.png -------------------------------------------------------------------------------- /docs/images/Turbo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Turbo@2x.png -------------------------------------------------------------------------------- /docs/images/Viridis@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/Viridis@2x.png -------------------------------------------------------------------------------- /docs/images/YlGn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/YlGn@2x.png -------------------------------------------------------------------------------- /docs/images/YlGnBu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/YlGnBu@2x.png -------------------------------------------------------------------------------- /docs/images/YlOrBr@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/YlOrBr@2x.png -------------------------------------------------------------------------------- /docs/images/YlOrRd@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/images/YlOrRd@2x.png -------------------------------------------------------------------------------- /docs/img/added-icon.d6f7e47d.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/img/deprecated-icon.015b4f17.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/img/modified-icon.f496e73d.svg: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /docs/img/no-image@2x.df2a0a50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swiftviz/Scale/6ce5a969597393cf3dc3f1444a58972da6f3761e/docs/img/no-image@2x.df2a0a50.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | Documentation
-------------------------------------------------------------------------------- /docs/js/highlight-js-bash.1b52852f.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-bash"],{f0f8:function(e,s){function t(e){const s=e.regex,t={},n={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]};Object.assign(t,{className:"variable",variants:[{begin:s.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},n]});const a={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},c={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,t,a]};a.contains.push(c);const o={className:"",begin:/\\"/},r={className:"string",begin:/'/,end:/'/},l={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]},p=["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"],d=e.SHEBANG({binary:`(${p.join("|")})`,relevance:10}),h={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0},m=["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"],u=["true","false"],b={match:/(\/[a-z._-]+)+/},g=["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset"],f=["alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias"],w=["autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp"],k=["chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"];return{name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z._-]+\b/,keyword:m,literal:u,built_in:[...g,...f,"set","shopt",...w,...k]},contains:[d,e.SHEBANG(),h,l,e.HASH_COMMENT_MODE,i,b,c,o,r,t]}}e.exports=t}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-custom-markdown.7cffc4b3.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-custom-markdown","highlight-js-markdown"],{"04b0":function(n,e){function a(n){const e=n.regex,a={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},i={begin:"^[-\\*]{3,}",end:"$"},s={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},t={className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},c={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},d=/[A-Za-z][A-Za-z0-9+.-]*/,l={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:e.concat(/\[.+?\]\(/,d,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},g={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},o={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};g.contains.push(o),o.contains.push(g);let r=[a,l];g.contains=g.contains.concat(r),o.contains=o.contains.concat(r),r=r.concat(g,o);const b={className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:r},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:r}]}]},u={className:"quote",begin:"^>\\s+",contains:r,end:"$"};return{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[b,a,t,g,o,u,s,i,l,c]}}n.exports=a},"84cb":function(n,e,a){"use strict";a.r(e);var i=a("04b0"),s=a.n(i);const t={begin:"",returnBegin:!0,contains:[{className:"link",begin:"doc:",end:">",excludeEnd:!0}]},c={className:"link",begin:/`{2}(?!`)/,end:/`{2}(?!`)/,excludeBegin:!0,excludeEnd:!0},d={begin:"^>\\s+[Note:|Tip:|Important:|Experiment:|Warning:]",end:"$",returnBegin:!0,contains:[{className:"quote",begin:"^>",end:"\\s+"},{className:"type",begin:"Note|Tip|Important|Experiment|Warning",end:":"},{className:"quote",begin:".*",end:"$",endsParent:!0}]},l={begin:"@",end:"[{\\)\\s]",returnBegin:!0,contains:[{className:"title",begin:"@",end:"[\\s+(]",excludeEnd:!0},{begin:":",end:"[,\\)\n\t]",excludeBegin:!0,keywords:{literal:"true false null undefined"},contains:[{className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",endsWithParent:!0,excludeEnd:!0},{className:"string",variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}],endsParent:!0},{className:"link",begin:"http|https",endsWithParent:!0,excludeEnd:!0}]}]};e["default"]=function(n){const e=s()(n),a=e.contains.find(({className:n})=>"code"===n);a.variants=a.variants.filter(({begin:n})=>!n.includes("( {4}|\\t)"));const i=[...e.contains.filter(({className:n})=>"code"!==n),a];return{...e,contains:[c,t,d,l,...i]}}}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-diff.62d66733.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-diff"],{"48b8":function(e,n){function a(e){const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)},{className:"comment",variants:[{begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,end:/$/}]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-http.163e45b6.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-http"],{c01d:function(e,n){function a(e){const n=e.regex,a="HTTP/(2|1\\.[01])",s=/[A-Za-z][A-Za-z0-9-]*/,t={className:"attribute",begin:n.concat("^",s,"(?=\\:\\s)"),starts:{contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$",relevance:0}}]}},i=[t,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{begin:"^(?="+a+" \\d{3})",end:/$/,contains:[{className:"meta",begin:a},{className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/,contains:i}},{begin:"(?=^[A-Z]+ (.*?) "+a+"$)",end:/$/,contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{className:"meta",begin:a},{className:"keyword",begin:"[A-Z]+"}],starts:{end:/\b\B/,illegal:/\S/,contains:i}},e.inherit(t,{relevance:0})]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-java.8326d9d8.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-java"],{"332f":function(e,a){var n="[0-9](_*[0-9])*",s=`\\.(${n})`,i="[0-9a-fA-F](_*[0-9a-fA-F])*",t={className:"number",variants:[{begin:`(\\b(${n})((${s})|\\.)?|(${s}))[eE][+-]?(${n})[fFdD]?\\b`},{begin:`\\b(${n})((${s})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${s})[fFdD]?\\b`},{begin:`\\b(${n})[fFdD]\\b`},{begin:`\\b0[xX]((${i})\\.?|(${i})?\\.(${i}))[pP][+-]?(${n})[fFdD]?\\b`},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${i})[lL]?\\b`},{begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}],relevance:0};function r(e,a,n){return-1===n?"":e.replace(a,s=>r(e,a,n-1))}function c(e){e.regex;const a="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",n=a+r("(?:<"+a+"~~~(?:\\s*,\\s*"+a+"~~~)*>)?",/~~~/g,2),s=["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do"],i=["super","this"],c=["false","true","null"],l=["char","boolean","long","float","int","byte","short","double"],o={keyword:s,literal:c,type:l,built_in:i},b={className:"meta",begin:"@"+a,contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},_={className:"params",begin:/\(/,end:/\)/,keywords:o,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0};return{name:"Java",aliases:["jsp"],keywords:o,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{begin:/import java\.[a-z]+\./,keywords:"import",relevance:2},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/,className:"string",contains:[e.BACKSLASH_ESCAPE]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,a],className:{1:"keyword",3:"title.class"}},{begin:[a,/\s+/,a,/\s+/,/=/],className:{1:"type",3:"variable",5:"operator"}},{begin:[/record/,/\s+/,a],className:{1:"keyword",3:"title.class"},contains:[_,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"new throw return else",relevance:0},{begin:["(?:"+n+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{2:"title.function"},keywords:o,contains:[{className:"params",begin:/\(/,end:/\)/,keywords:o,relevance:0,contains:[b,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,t,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},t,b]}}e.exports=c}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-json.471128d2.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-json"],{"5ad2":function(n,e){function a(n){const e={className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},a={match:/[{}[\],:]/,className:"punctuation",relevance:0},s={beginKeywords:["true","false","null"].join(" ")};return{name:"JSON",contains:[e,a,n.QUOTE_STRING_MODE,s,n.C_NUMBER_MODE,n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],illegal:"\\S"}}n.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-llvm.6100b125.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-llvm"],{"7c30":function(e,n){function a(e){const n=e.regex,a=/([-a-zA-Z$._][\w$.-]*)/,t={className:"type",begin:/\bi\d+(?=\s|\b)/},i={className:"operator",relevance:0,begin:/=/},c={className:"punctuation",relevance:0,begin:/,/},l={className:"number",variants:[{begin:/0[xX][a-fA-F0-9]+/},{begin:/-?\d+(?:[.]\d+)?(?:[eE][-+]?\d+(?:[.]\d+)?)?/}],relevance:0},r={className:"symbol",variants:[{begin:/^\s*[a-z]+:/}],relevance:0},s={className:"variable",variants:[{begin:n.concat(/%/,a)},{begin:/%\d+/},{begin:/#\d+/}]},o={className:"title",variants:[{begin:n.concat(/@/,a)},{begin:/@\d+/},{begin:n.concat(/!/,a)},{begin:n.concat(/!\d+/,a)},{begin:/!\d+/}]};return{name:"LLVM IR",keywords:"begin end true false declare define global constant private linker_private internal available_externally linkonce linkonce_odr weak weak_odr appending dllimport dllexport common default hidden protected extern_weak external thread_local zeroinitializer undef null to tail target triple datalayout volatile nuw nsw nnan ninf nsz arcp fast exact inbounds align addrspace section alias module asm sideeffect gc dbg linker_private_weak attributes blockaddress initialexec localdynamic localexec prefix unnamed_addr ccc fastcc coldcc x86_stdcallcc x86_fastcallcc arm_apcscc arm_aapcscc arm_aapcs_vfpcc ptx_device ptx_kernel intel_ocl_bicc msp430_intrcc spir_func spir_kernel x86_64_sysvcc x86_64_win64cc x86_thiscallcc cc c signext zeroext inreg sret nounwind noreturn noalias nocapture byval nest readnone readonly inlinehint noinline alwaysinline optsize ssp sspreq noredzone noimplicitfloat naked builtin cold nobuiltin noduplicate nonlazybind optnone returns_twice sanitize_address sanitize_memory sanitize_thread sspstrong uwtable returned type opaque eq ne slt sgt sle sge ult ugt ule uge oeq one olt ogt ole oge ord uno ueq une x acq_rel acquire alignstack atomic catch cleanup filter inteldialect max min monotonic nand personality release seq_cst singlethread umax umin unordered xchg add fadd sub fsub mul fmul udiv sdiv fdiv urem srem frem shl lshr ashr and or xor icmp fcmp phi call trunc zext sext fptrunc fpext uitofp sitofp fptoui fptosi inttoptr ptrtoint bitcast addrspacecast select va_arg ret br switch invoke unwind unreachable indirectbr landingpad resume malloc alloca free load store getelementptr extractelement insertelement shufflevector getresult extractvalue insertvalue atomicrmw cmpxchg fence argmemonly double",contains:[t,e.COMMENT(/;\s*$/,null,{relevance:0}),e.COMMENT(/;/,/$/),e.QUOTE_STRING_MODE,{className:"string",variants:[{begin:/"/,end:/[^\\]"/}]},o,c,i,s,r,l]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-markdown.90077643.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-markdown"],{"04b0":function(n,e){function a(n){const e=n.regex,a={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},i={begin:"^[-\\*]{3,}",end:"$"},s={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},c={className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},t={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},g=/[A-Za-z][A-Za-z0-9+.-]*/,d={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:e.concat(/\[.+?\]\(/,g,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},l={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},o={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};l.contains.push(o),o.contains.push(l);let b=[a,d];l.contains=l.contains.concat(b),o.contains=o.contains.concat(b),b=b.concat(l,o);const r={className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:b},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:b}]}]},m={className:"quote",begin:"^>\\s+",contains:b,end:"$"};return{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[r,a,c,l,o,m,s,i,d,t]}}n.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-objectivec.bcdf5156.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-objectivec"],{"9bf2":function(e,n){function _(e){const n={className:"built_in",begin:"\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+"},_=/[a-zA-Z@][a-zA-Z0-9_]*/,i=["int","float","while","char","export","sizeof","typedef","const","struct","for","union","unsigned","long","volatile","static","bool","mutable","if","do","return","goto","void","enum","else","break","extern","asm","case","short","default","double","register","explicit","signed","typename","this","switch","continue","wchar_t","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","super","unichar","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"],t=["false","true","FALSE","TRUE","nil","YES","NO","NULL"],a=["BOOL","dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"],o={$pattern:_,keyword:i,literal:t,built_in:a},s={$pattern:_,keyword:["@interface","@class","@protocol","@implementation"]};return{name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"],keywords:o,illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+s.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:s,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}e.exports=_}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-python.c214ed92.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-python"],{9510:function(e,n){function a(e){const n=e.regex,a=/[\p{XID_Start}_]\p{XID_Continue}*/u,i=["and","as","assert","async","await","break","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],s=["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"],t=["__debug__","Ellipsis","False","None","NotImplemented","True"],r=["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"],l={$pattern:/[A-Za-z]\w+|__\w+__/,keyword:i,built_in:s,literal:t,type:r},o={className:"meta",begin:/^(>>>|\.\.\.) /},b={className:"subst",begin:/\{/,end:/\}/,keywords:l,illegal:/#/},c={begin:/\{\{/,relevance:0},d={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,o],relevance:10},{begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,o],relevance:10},{begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,o,c,b]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,o,c,b]},{begin:/([uU]|[rR])'/,end:/'/,relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/,end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,c,b]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,c,b]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},p="[0-9](_?[0-9])*",g=`(\\b(${p}))?\\.(${p})|\\b(${p})\\.`,m={className:"number",relevance:0,variants:[{begin:`(\\b(${p})|(${g}))[eE][+-]?(${p})[jJ]?\\b`},{begin:`(${g})[jJ]?`},{begin:"\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?\\b"},{begin:"\\b0[bB](_?[01])+[lL]?\\b"},{begin:"\\b0[oO](_?[0-7])+[lL]?\\b"},{begin:"\\b0[xX](_?[0-9a-fA-F])+[lL]?\\b"},{begin:`\\b(${p})[jJ]\\b`}]},_={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:l,contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},u={className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:l,contains:["self",o,m,d,e.HASH_COMMENT_MODE]}]};return b.contains=[d,m,o],{name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:l,illegal:/(<\/|->|\?)|=>/,contains:[o,m,{begin:/\bself\b/},{beginKeywords:"if",relevance:0},d,_,e.HASH_COMMENT_MODE,{match:[/def/,/\s+/,a],scope:{1:"keyword",3:"title.function"},contains:[u]},{variants:[{match:[/class/,/\s+/,a,/\s*/,/\(\s*/,a,/\s*\)/]},{match:[/class/,/\s+/,a]}],scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[m,u,d]}]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-ruby.f889d392.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-ruby"],{"82cb":function(e,n){function a(e){const n=e.regex,a="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",i={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor __FILE__",built_in:"proc lambda",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},b={begin:"#<",end:">"},c=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],r={className:"subst",begin:/#\{/,end:/\}/,keywords:i},d={className:"string",contains:[e.BACKSLASH_ESCAPE,r],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)),contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,r]})]}]},t="[1-9](_?[0-9])*|0",o="[0-9](_?[0-9])*",g={className:"number",relevance:0,variants:[{begin:`\\b(${t})(\\.(${o}))?([eE][+-]?(${o})|r)?i?\\b`},{begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{begin:"\\b0(_?[0-7])+r?i?\\b"}]},l={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:i},_=[d,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE,relevance:0}]}].concat(c)},{className:"function",begin:n.concat(/def\s+/,n.lookahead(a+"\\s*(\\(|;|$)")),relevance:0,keywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:a}),l].concat(c)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[d,{begin:a}],relevance:0},g,{className:"variable",begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{className:"params",begin:/\|/,end:/\|/,relevance:0,keywords:i},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,r],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(b,c),relevance:0}].concat(b,c);r.contains=_,l.contains=_;const w="[>?]>",E="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>",N=[{begin:/^\s*=>/,starts:{end:"$",contains:_}},{className:"meta",begin:"^("+w+"|"+E+"|"+u+")(?=[ ])",starts:{end:"$",contains:_}}];return c.unshift(b),{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:i,illegal:/\/\*/,contains:[e.SHEBANG({binary:"ruby"})].concat(N).concat(c).concat(_)}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-shell.dd7f411f.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-shell"],{b65b:function(s,n){function e(s){return{name:"Shell Session",aliases:["console","shellsession"],contains:[{className:"meta",begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/,subLanguage:"bash"}}]}}s.exports=e}}]); -------------------------------------------------------------------------------- /docs/js/highlight-js-xml.9c3688c7.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * This source file is part of the Swift.org open source project 3 | * 4 | * Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | * Licensed under Apache License v2.0 with Runtime Library Exception 6 | * 7 | * See https://swift.org/LICENSE.txt for license information 8 | * See https://swift.org/CONTRIBUTORS.txt for Swift project authors 9 | */ 10 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["highlight-js-xml"],{"8dcb":function(e,n){function a(e){const n=e.regex,a=n.concat(/[A-Z_]/,n.optional(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),s=/[A-Za-z0-9._:-]+/,t={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/,contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},c=e.inherit(i,{begin:/\(/,end:/\)/}),l=e.inherit(e.APOS_STRING_MODE,{className:"string"}),r=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),g={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,r,l,c,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[i,c,r,l]}]}]},e.COMMENT(//,{relevance:10}),{begin://,relevance:10},t,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[g],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[g],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:n.concat(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:a,relevance:0,starts:g}]},{className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(a,/>/))),contains:[{className:"name",begin:a,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}}e.exports=a}}]); -------------------------------------------------------------------------------- /docs/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundleDisplayName" : "SwiftVizScale", 3 | "bundleIdentifier" : "com.github.swiftviz.SwiftVizScale", 4 | "schemaVersion" : { 5 | "major" : 0, 6 | "minor" : 1, 7 | "patch" : 0 8 | } 9 | } -------------------------------------------------------------------------------- /preview.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | $(xcrun --find swift) package --disable-sandbox \ 6 | preview-documentation --target SwiftVizScale 7 | -------------------------------------------------------------------------------- /utils/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/config/registries.json 8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 9 | .netrc 10 | -------------------------------------------------------------------------------- /utils/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.6 2 | 3 | import PackageDescription 4 | 5 | // This executable is in its own package because including a CLI executable package 6 | // into the Scale library caused Xcode to have a freak out, and fail to present 7 | // SwiftUI previews for targets within that package. By moving it out and into it's 8 | // own thing, Xcode's failing resolution mechanisms seem to be worked around. 9 | 10 | let package = Package( 11 | name: "GenerateDocImages", 12 | platforms: [ 13 | .macOS(.v10_15), 14 | ], 15 | dependencies: [ 16 | .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"), 17 | .package(url: "https://github.com/apple/swift-system", from: "0.0.3"), 18 | // .package(url: "https://github.com/swiftviz/scale", branch: "main"), 19 | .package(name: "scale", path: "../"), 20 | ], 21 | targets: [ 22 | .executableTarget( 23 | name: "GenerateDocImages", 24 | dependencies: [ 25 | .product(name: "ScaleVisualTests", package: "scale"), 26 | .product(name: "ArgumentParser", package: "swift-argument-parser"), 27 | .product(name: "SystemPackage", package: "swift-system"), 28 | ] 29 | ), 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /utils/README.md: -------------------------------------------------------------------------------- 1 | # GenDocImages 2 | 3 | A utility CLI to generate images in support of the SwiftVizScale library. 4 | It generates PNG images in the local directory, which you can then move into Scale's documentation resources directory. 5 | 6 | Usage: 7 | 8 | cd utils 9 | swift run GenerateDocImages 10 | mv *.png ../Sources/SwiftVizScale/Documentation.docc/Resources/ 11 | -------------------------------------------------------------------------------- /utils/Sources/GenerateDocImages/GeneratedDocImagesCommand.swift: -------------------------------------------------------------------------------- 1 | import ArgumentParser 2 | import SwiftUI 3 | import SwiftVizScale 4 | import SystemPackage 5 | import VisualTests 6 | 7 | @main 8 | @available(macOS 12.0, *) 9 | struct GeneratedDocImagesCommand: ParsableCommand { 10 | @MainActor 11 | func run() throws { 12 | let schemes: [String: any ColorInterpolator] = [ 13 | "BrBG": ColorScheme.Diverging.BrBG, 14 | "PrGN": ColorScheme.Diverging.PrGN, 15 | "PiYG": ColorScheme.Diverging.PiYG, 16 | "PuOr": ColorScheme.Diverging.PuOr, 17 | "RdBu": ColorScheme.Diverging.RdBu, 18 | "RdGy": ColorScheme.Diverging.RdGy, 19 | "RdYlBu": ColorScheme.Diverging.RdYlBu, 20 | "RdYlGn": ColorScheme.Diverging.RdYlGn, 21 | "Spectral": ColorScheme.Diverging.Spectral, 22 | "BuGn": ColorScheme.SequentialMultiHue.BuGn, 23 | "BuPu": ColorScheme.SequentialMultiHue.BuPu, 24 | "GnBu": ColorScheme.SequentialMultiHue.GnBu, 25 | "OrRd": ColorScheme.SequentialMultiHue.OrRd, 26 | "PuBu": ColorScheme.SequentialMultiHue.PuBu, 27 | "PuBuGn": ColorScheme.SequentialMultiHue.PuBuGn, 28 | "PuRd": ColorScheme.SequentialMultiHue.PuRd, 29 | "RdPu": ColorScheme.SequentialMultiHue.RdPu, 30 | "YlGn": ColorScheme.SequentialMultiHue.YlGn, 31 | "YlGnBu": ColorScheme.SequentialMultiHue.YlGnBu, 32 | "YlOrBr": ColorScheme.SequentialMultiHue.YlOrBr, 33 | "YlOrRd": ColorScheme.SequentialMultiHue.YlOrRd, 34 | "Viridis": ColorScheme.SequentialMultiHue.Viridis, 35 | "Magma": ColorScheme.SequentialMultiHue.Magma, 36 | "Inferno": ColorScheme.SequentialMultiHue.Inferno, 37 | "Plasma": ColorScheme.SequentialMultiHue.Plasma, 38 | "Cividis": ColorScheme.SequentialMultiHue.Cividis, 39 | "Turbo": ColorScheme.SequentialMultiHue.Turbo, 40 | "Oranges": ColorScheme.SequentialSingleHue.Oranges, 41 | "Purples": ColorScheme.SequentialSingleHue.Purples, 42 | "Grays": ColorScheme.SequentialSingleHue.Grays, 43 | "Blues": ColorScheme.SequentialSingleHue.Blues, 44 | "Greens": ColorScheme.SequentialSingleHue.Greens, 45 | "Reds": ColorScheme.SequentialSingleHue.Reds, 46 | "Sinebow": ColorScheme.Cyclical.Sinebow, 47 | ] 48 | 49 | for (name, interpolator) in schemes { 50 | print("Creating color swatch for \(name)") 51 | 52 | let view = ColorInterpolatorView(steps: 128, interpolator: interpolator) 53 | .frame(width: 400, height: 40) 54 | let image = view.snapshot()!.cgImage(forProposedRect: nil, context: nil, hints: nil)! 55 | let newRepresentation = NSBitmapImageRep(cgImage: image) 56 | 57 | let path = FilePath("\(name)@2x.png") 58 | let fd = try FileDescriptor.open(path, .writeOnly, 59 | options: [.append, .create], 60 | permissions: .ownerReadWrite) 61 | try fd.closeAfter { 62 | if let pngData = newRepresentation.representation(using: .png, properties: [:]) { 63 | _ = try fd.writeAll(pngData) 64 | } 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /utils/Sources/GenerateDocImages/SwiftUI+snapshot.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftUI+snapshot.swift 3 | // 4 | 5 | import SwiftUI 6 | 7 | @available(watchOS 6.0, *) 8 | extension View { 9 | #if os(macOS) 10 | func snapshot() -> NSImage? { 11 | let controller = NSHostingController(rootView: self) 12 | let targetSize = controller.view.intrinsicContentSize 13 | let contentRect = NSRect(origin: .zero, size: targetSize) 14 | 15 | let window = NSWindow( 16 | contentRect: contentRect, 17 | styleMask: [.borderless], 18 | backing: .buffered, 19 | defer: false 20 | ) 21 | window.contentView = controller.view 22 | 23 | guard 24 | let bitmapRep = controller.view.bitmapImageRepForCachingDisplay(in: contentRect) 25 | else { return nil } 26 | 27 | controller.view.cacheDisplay(in: contentRect, to: bitmapRep) 28 | let image = NSImage(size: bitmapRep.size) 29 | image.addRepresentation(bitmapRep) 30 | return image 31 | } 32 | #endif 33 | 34 | #if os(iOS) 35 | func snapshot() -> UIImage { 36 | let controller = UIHostingController(rootView: self) 37 | let view = controller.view 38 | 39 | let targetSize = controller.view.intrinsicContentSize 40 | view?.bounds = CGRect(origin: .zero, size: targetSize) 41 | view?.backgroundColor = .clear 42 | 43 | let renderer = UIGraphicsImageRenderer(size: targetSize) 44 | 45 | return renderer.image { _ in 46 | view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true) 47 | } 48 | } 49 | #endif 50 | } 51 | --------------------------------------------------------------------------------