package render import "math" // Temperature bands. The two ends are IMGW's own warning criteria, so a red // temperature means the met office would issue a warning about it rather than // that it looked hot to whoever wrote this: // // Tmin <= -15 silny mroz, stopien 1 -> bright blue // Tmax >= 30 upal, stopien 1 -> red // Tmax > 35 the higher heat level -> bright red // // The splits between (0, 10, 20) are round numbers, not thresholds from any // source; they only subdivide the range nobody warns about. var tempBands = []struct { below float64 code string }{ {0, Blue}, {10, Cyan}, {20, Green}, {30, Yellow}, } // Deg rounds to whole degrees. Rounding through int conversion avoids "-0", // which is arithmetically fine and visually wrong. func Deg(t float64) int { return int(math.Round(t)) } // TempStyle is the ANSI code for a temperature in Celsius. // // The warning edges are written out rather than folded into tempBands so they // match IMGW's criteria exactly, inclusive and exclusive included. // // The value is rounded first, so the colour always matches the number printed // beside it: otherwise -14.6 prints as "-15" in a different colour than a true // -15 and looks like a rendering bug. func TempStyle(celsius float64) string { t := float64(Deg(celsius)) switch { case t <= -15: return BrightBlue case t > 35: return BrightRed case t >= 30: return Red } for _, b := range tempBands { if t < b.below { return b.code } } return Yellow } // Pollen bands in grains/m3, from Polish clinical sources. Each entry is an // upper bound (exclusive) and a band key; a nil bound means "everything above". // // grass -- alergen.info.pl symptom table: 20 = first nasal symptoms in 25% // of sufferers, 50 = symptoms in all tested, 65 = intensified in // over 75%, 120 = dyspnoea after 30 minutes of exposure. // birch -- mp.pl: 80 provokes symptoms in over 95% of allergics. // mugwort -- mp.pl: over 70 counts as high, intensified symptoms. // // Birch and mugwort have a single published anchor each, so they get a two-way // split rather than four bands: their "low" is weaker evidence than grass's. // Alder, olive and ragweed have no Polish threshold that could be sourced and // are deliberately left unbanded rather than banded on a guess. var pollenBands = map[string][]struct { below float64 band string }{ "grass": {{20, "low"}, {50, "medium"}, {65, "high"}, {math.Inf(1), "very high"}}, "birch": {{80, "low"}, {math.Inf(1), "high"}}, "mugwort": {{70, "low"}, {math.Inf(1), "high"}}, } // PollenBand is the qualitative level for a count, or "" where no threshold // exists for that species. func PollenBand(species string, value float64) string { if value < 1 { return "none" } bands, ok := pollenBands[species] if !ok { return "" } for _, b := range bands { if value < b.below { return b.band } } return "" }