Skip to content

Instantly share code, notes, and snippets.

@JohnB
Created July 20, 2022 20:51
Show Gist options
  • Save JohnB/1ed0aa1f9f6a63e7be0a6882d951bbcf to your computer and use it in GitHub Desktop.
Save JohnB/1ed0aa1f9f6a63e7be0a6882d951bbcf to your computer and use it in GitHub Desktop.
Swift example code to improve the MapMyWalk altitude graph
// This code was created by https://codelanguageconverter.com/
// in an automatic conversion from https://gist.github.com/JohnB/055e126e4b581de802acb451691a1a4f
// (after stripping most comments to fit in the free conversion limit and then re-adding them).
//
// NOTE: the conversion seems to have been confused by the elixir "case" statement, and forgot to convert
// it to a "switch" with varioius cases and will likely need to be fixed (but I don't have a swift compiler handy).
//
class YAxis {
// The YAxis module attempts to find "reasonable" values for the MapMyWalk
// altitude graph. For example, my MapMyWalk graph (as of 7/2022) offers
// these altitude values when my workout goes from 138 to 198 feet:
// 20.4, 79.5, 138.5, 197.6, 256.6, 315.7
// Which I find to be much less readable/understandable than:
// 120, 140, 160, 180, 200, 220
// Working examples from the original elixir code:
// iex> YAxis.labels(138, 198, 6)
// {:ok, [120, 140, 160, 180, 200, 220]}
//
// iex> YAxis.labels(11, 22, 2)
// {:ok, [10, 30]}
//
// iex> YAxis.labels(138, 168, 6)
// {:ok, [130, 140, 150, 160, 170, 180]}
//
// iex> YAxis.labels(133, 206, 7)
// {:ok, [120, 140, 160, 180, 200, 220, 240]}
//
// iex> YAxis.labels(95, 261, 6)
// {:ok, [50, 100, 150, 200, 250, 300]}
//
// iex> YAxis.labels(123, 5206, 7)
// {:ok, [0, 1000, 2000, 3000, 4000, 5000, 6000]}
//
// iex> YAxis.labels(17, 523_456, 7)
// {:ok, [0, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000]}
//
// iex> YAxis.labels(5, 3, 7)
// {:error, "min value must be less than max value"}
//
// iex> YAxis.labels(11, 22, 1)
// {:error, "must specify at least 2 labels"}
//
var deltas: [Int] = [
5, 10, 20, 25,
50, 100, 200, 250,
500, 1_000, 2_000, 2_500,
5_000, 10_000, 20_000, 25_000,
50_000, 100_000, 200_000, 250_000
]
func labels(min: Int, max: Int, _num_labels: Int) throws -> [Int] {
if (min >= max) {
throw "min value must be less than max value"
} else if (_num_labels < 2) {
throw "must specify at least 2 labels"
} else {
min = lowerMultipleOfFive(num: min)
max = higherMultipleOfFive(num: max)
let tableRows: Int = num_labels - 1
let step: Int =
Integer.floor_div(max - min, tableRows)
|> nextHigherDelta()
// Attempt to force onto a step boundary while still containing min & max
let updatedMin: Int = min - rem(abs(min), step)
let updatedTop: Int = updatedMin + step * tableRows
let values: [Int] = case updatedTop >= max {
true -> Range.new(updatedMin, updatedTop, step)
_ -> Range.new(min, min + step * tableRows, step)
} |> Enum.to_list
return values
}
}
func nextHigherDelta(num: Int) -> Int {
return Enum.find(deltas, fn n -> n >= num end) || List.last(deltas)
}
func lowerMultipleOfFive(num: Int) -> Int {
if (rem(num, 5) == 0) {
return num
} else {
return num - rem(num, 5)
}
}
func higherMultipleOfFive(num: Int) -> Int {
if (rem(num, 5) == 0) {
return num
} else {
return num + 5 - rem(num, 5)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment