@@ -73,8 +73,15 @@ extension Heatmap: HasGraphLayout, Plot {
7373 width: size. width / Float( results. columns) ,
7474 height: size. height / Float( results. rows)
7575 )
76- results. itemSize. width. round ( . down)
77- results. itemSize. height. round ( . down)
76+ // If we have at enough space to give each element a pixel,
77+ // round the items down to integer dimensions to remove aliasing
78+ // in the rendered image.
79+ if results. itemSize. width > 1 {
80+ results. itemSize. width = max ( results. itemSize. width. rounded ( . down) , 1 )
81+ }
82+ if results. itemSize. height > 1 {
83+ results. itemSize. height = max ( results. itemSize. height. rounded ( . down) , 1 )
84+ }
7885 // Calculate markers.
7986 markers. xMarkers = ( 0 ..< results. columns) . map {
8087 ( Float ( $0) + 0.5 ) * results. itemSize. width
@@ -154,18 +161,18 @@ extension Heatmap
154161
155162// Collection construction shorthand.
156163
157- extension Sequence where Element: Sequence {
164+ extension SequencePlots where Base . Element: Sequence {
158165
159166 /// Returns a heatmap of values from this 2-dimensional sequence.
160167 /// - parameters:
161168 /// - interpolator: A function or `KeyPath` which maps values to a continuum between 0 and 1.
162169 /// - returns: A heatmap plot of the sequence's inner items.
163- public func heatmap( interpolator: Interpolator < Element . Element > ) -> Heatmap < Self > {
164- return Heatmap ( values: self , interpolator: interpolator)
170+ public func heatmap( interpolator: Interpolator < Base . Element . Element > ) -> Heatmap < Base > {
171+ return Heatmap ( values: base , interpolator: interpolator)
165172 }
166173}
167174
168- extension Collection {
175+ extension SequencePlots where Base : Collection {
169176
170177 /// Returns a heatmap of this collection's values, generated by slicing rows with the given width.
171178 /// - parameters:
@@ -174,51 +181,53 @@ extension Collection {
174181 /// - returns: A heatmap plot of the collection's values.
175182 /// - complexity: O(n). Consider though, that rendering a heatmap or copying to a `RamdomAccessCollection`
176183 /// is also at least O(n), and this does not copy the data.
177- public func heatmap( width: Int , interpolator: Interpolator < Element > ) -> Heatmap < [ SubSequence ] > {
184+ public func heatmap( width: Int , interpolator: Interpolator < Base . Element > ) -> Heatmap < [ Base . SubSequence ] > {
178185 precondition ( width > 0 , " Cannot build a histogram with zero or negative width " )
179- var rows = [ SubSequence] ( )
180- var rowStart = startIndex
181- while rowStart != endIndex {
182- guard let rowEnd = index ( rowStart, offsetBy: width, limitedBy: endIndex) else {
183- rows. append ( self [ rowStart..< endIndex] )
186+ var rows = [ Base . SubSequence] ( )
187+ var rowStart = base . startIndex
188+ while rowStart != base . endIndex {
189+ guard let rowEnd = base . index ( rowStart, offsetBy: width, limitedBy: base . endIndex) else {
190+ rows. append ( base [ rowStart..< base . endIndex] )
184191 break
185192 }
186- rows. append ( self [ rowStart..< rowEnd] )
193+ rows. append ( base [ rowStart..< rowEnd] )
187194 rowStart = rowEnd
188195 }
189- return rows. heatmap ( interpolator: interpolator)
196+ return rows. plots . heatmap ( interpolator: interpolator)
190197 }
191198}
192199
193- extension RandomAccessCollection {
200+ extension SequencePlots where Base : RandomAccessCollection {
194201
195202 /// Returns a heatmap of this collection's values, generated by slicing rows with the given width.
196203 /// - parameters:
197204 /// - width: The width of the heatmap to generate. Must be greater than 0.
198205 /// - interpolator: A function or `KeyPath` which maps values to a continuum between 0 and 1.
199206 /// - returns: A heatmap plot of the collection's values.
200- public func heatmap( width: Int , interpolator: Interpolator < Element > ) -> Heatmap < [ SubSequence ] > {
207+ public func heatmap( width: Int , interpolator: Interpolator < Base . Element > ) -> Heatmap < [ Base . SubSequence ] > {
201208 precondition ( width > 0 , " Cannot build a histogram with zero or negative width " )
202- let height = Int ( ( Float ( count) / Float( width) ) . rounded ( . up) )
209+ let height = Int ( ( Float ( base . count) / Float( width) ) . rounded ( . up) )
203210 return ( 0 ..< height)
204- . map { _sliceForRow ( $0, width: width) }
205- . heatmap ( interpolator: interpolator)
211+ . map { base . _sliceForRow ( $0, width: width) }
212+ . plots . heatmap ( interpolator: interpolator)
206213 }
207214
208215 /// Returns a heatmap of this collection's values, generated by the data in to `height` rows.
209216 /// - parameters:
210217 /// - height: The height of the heatmap to generate. Must be greater than 0.
211218 /// - interpolator: A function or `KeyPath` which maps values to a continuum between 0 and 1.
212219 /// - returns: A heatmap plot of the collection's values.
213- public func heatmap( height: Int , interpolator: Interpolator < Element > ) -> Heatmap < [ SubSequence ] > {
220+ public func heatmap( height: Int , interpolator: Interpolator < Base . Element > ) -> Heatmap < [ Base . SubSequence ] > {
214221 precondition ( height > 0 , " Cannot build a histogram with zero or negative height " )
215- let width = Int ( ( Float ( count) / Float( height) ) . rounded ( . up) )
222+ let width = Int ( ( Float ( base . count) / Float( height) ) . rounded ( . up) )
216223 return ( 0 ..< height)
217- . map { _sliceForRow ( $0, width: width) }
218- . heatmap ( interpolator: interpolator)
224+ . map { base . _sliceForRow ( $0, width: width) }
225+ . plots . heatmap ( interpolator: interpolator)
219226 }
220-
221- private func _sliceForRow( _ row: Int , width: Int ) -> SubSequence {
227+ }
228+
229+ extension RandomAccessCollection {
230+ fileprivate func _sliceForRow( _ row: Int , width: Int ) -> SubSequence {
222231 guard let start = index ( startIndex, offsetBy: row * width, limitedBy: endIndex) else {
223232 return self [ startIndex..< startIndex]
224233 }
0 commit comments