A.K.A. Rose Wheel
A SwiftUI data representation that combines pie charts and histograms to display layered data
The most common use case is a timeline, that would usually be represented as a histogram. This approach allows for a "category", "log based",... approach where today/last week/last month/last year is more clearly representd for visual comparison
It's a regular SwiftUI view and you can set it up by looking at the documentation
Back in the far far away time of 2014, a couple friends and I wanted to visualize a series of events. The idea was to provide an observer with a quick way to assess the frequency of these events as it compares to the rest of the year.
The main problem with regular histograms is that, while it allows for a quick overview of the rate of change in terms of values, doesn't provide with a simple way to grasp the timescales involved. You can of course use a logarithmic scale for the x-axis, or zoom in, or provide several graphs, but the kind of events we had in mind had an explosive nature: when it starts happening, it ramps up very quickly until you address the problem. But in order to fix it, you also needed to see if this was a regular occurence, what the general background level was, etc.
Think of sales, or traffic on your website: every time you push a new thing out, there's a noticeable spike, but a "problem" (in those example, inventory issues or DDoS) isn't just the ramping up, but the amount at which it becomes an issue.
My friend Peter and I hate pie charts. The are hard to read precisely, even if they give a good global overview of the relative importance of "things"
Histograms are also great at global overview, maybe even a glimpse at max/min/avg values, but they lack legibility.
So, Peter came up with this representation that tries to keep the ease of comparison of both charts: segmentation on the pie side (day/week/month/year), and amplitude on the histogram/spikes.
We called it the Rose Wheel, because it kind of looks like a flower.
And it made looking at incident graphs to decide "normalcy" easier. In his honor, I re-coded it in Swift, and here it is.
As usual with SPM packages, import it through Xcode's dependencies or in your package file:
let package = Package(
...
, dependencies: [
.package(url: "https://github.com/krugazor/SpikeWheelTimeline", from: "0.1.0"),
...
],
Then add it to your view hierarchy:
import SwiftUI
import SpikeWheelTimeline
struct RegularContentView: View {
@State var data = SpikedWheelData([SpikedWheelSliceData("1", size: 1, spikes:(-20...40).map({ Double($0) * Double.random(in: -1...1) }), scale: 0.75),
SpikedWheelSliceData("2", size: 1, spikes:(10...80).reversed().map({ Double($0) * Double.random(in: -1...1) }), offset: 10, scale: 1.1),
SpikedWheelSliceData("3", size: 2, spikes:(10...200).map({ Double($0) * Double.random(in: 0...1) }), offset: 20),
SpikedWheelSliceData("4", size: 0.25, spikes:[])
])
@State var showSpikes: Bool = true
@State var diameter: Double = 200
@State var invertSpikes: Bool = false
var body: some View {
var swg = SpikedWheelGraph(data: data, diameter: diameter, showSpikes: showSpikes)
VStack {
HStack {
Toggle("Show spikes", isOn: $showSpikes).onChange(of: showSpikes) {
showSpikes.toggle()
}
Toggle("Invert spikes", isOn: $invertSpikes).onChange(of: invertSpikes) {
invertSpikes.toggle()
let newData = SpikedWheelData(data.slices.map({ mslice in
SpikedWheelSliceData(mslice.label, size: mslice.size, spikes: mslice.spikes.map({ invertSpikes ? $0 * -1 : $0 }), offset: mslice.offset, scale: mslice.scale)
}))
data = newData
}
}
swg
}
}
- 0.1.0: Initial release