Description:
Add logarithmic scale.
Imperfect but does mostly work so I think it's worth merging this work from the past few weeks.
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
@@ -52,12 +52,12 | |||||
|
52 | private static Dictionary<LogLevel, (ConsoleColor, ConsoleColor)> mappings = new Dictionary<LogLevel, (ConsoleColor, ConsoleColor)> |
|
52 | private static Dictionary<LogLevel, (ConsoleColor, ConsoleColor)> mappings = new Dictionary<LogLevel, (ConsoleColor, ConsoleColor)> |
|
53 | { |
|
53 | { |
|
54 | {LogLevel.Critical, (ConsoleColor.White, ConsoleColor.Red)}, |
|
54 | {LogLevel.Critical, (ConsoleColor.White, ConsoleColor.Red)}, |
|
55 |
{LogLevel.Error, (ConsoleColor. |
|
55 | {LogLevel.Error, (ConsoleColor.Black, ConsoleColor.Red)}, |
|
56 |
{LogLevel.Warning, (ConsoleColor. |
|
56 | {LogLevel.Warning, (ConsoleColor.Black, ConsoleColor.Yellow)}, |
|
57 |
{LogLevel.Success, (ConsoleColor. |
|
57 | {LogLevel.Success, (ConsoleColor.White, ConsoleColor.Green)}, |
|
58 |
{LogLevel.Info, (ConsoleColor. |
|
58 | {LogLevel.Info, (ConsoleColor.White, ConsoleColor.Blue)}, |
|
59 |
{LogLevel.Debug, (ConsoleColor. |
|
59 | {LogLevel.Debug, (ConsoleColor.Blue, ConsoleColor.Black)}, |
|
60 |
{LogLevel.Trace, (ConsoleColor. |
|
60 | {LogLevel.Trace, (ConsoleColor.Magenta, ConsoleColor.Black)}, |
|
61 | {LogLevel.Spy, (ConsoleColor.Black, ConsoleColor.White)}, |
|
61 | {LogLevel.Spy, (ConsoleColor.Black, ConsoleColor.White)}, |
|
62 |
|
62 | ||
|
63 | }; |
|
63 | }; |
@@ -27,6 +27,7 | |||||
|
27 | public static bool show_upkeep = false; |
|
27 | public static bool show_upkeep = false; |
|
28 |
|
28 | ||
|
29 | public static bool always_show_zero = false; |
|
29 | public static bool always_show_zero = false; |
|
|
30 | public static bool logarithmic = false; | ||
|
30 |
|
31 | ||
|
31 | private static string[] money_series = {"Total Funds", |
|
32 | private static string[] money_series = {"Total Funds", |
|
32 | "Subsidies", "Upkeep", "Contracts", "Cashflow", "Misc"}; |
|
33 | "Subsidies", "Upkeep", "Contracts", "Cashflow", "Misc"}; |
@@ -103,6 +104,38 | |||||
|
103 | } |
|
104 | } |
|
104 | } |
|
105 | } |
|
105 |
|
106 | ||
|
|
107 | public static void DrawLogrithmicLabels(ImFontPtr font, ImDrawListPtr draw_list, Num.Vector2 domain, Num.Vector2 range, bool vertical, int labels, Num.Vector2 starting_position) { | ||
|
|
108 | //We need to increment by one in order to cover the entire range. | ||
|
|
109 | //For example, if our range is 0 - 100, and we want 11 ticks, 100 / 10 gives us a spacing o 10 | ||
|
|
110 | //So our 11 labels become 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100. | ||
|
|
111 | var tick_spacing = (int)Math.Abs((range.Y - range.X) / (labels - 1)); | ||
|
|
112 | var tick_length = 5; | ||
|
|
113 | var tick_adjust = vertical ? new Num.Vector2(tick_length, 0) : new Num.Vector2(0, tick_length); | ||
|
|
114 | |||
|
|
115 | var tick_position = new Num.Vector2(0, range.Y); | ||
|
|
116 | var tick_absolute_position = Num.Vector2.Add(starting_position, tick_position); | ||
|
|
117 | |||
|
|
118 | for(int i = 0; i < labels; i++) { | ||
|
|
119 | var value = ScaleLogarithmic(range, domain, (int)(vertical ? tick_position.Y : tick_position.X)); | ||
|
|
120 | var label = String.Format("{0}", value); | ||
|
|
121 | var height_adjust = ImGui.CalcTextSize(label).Y / 2; | ||
|
|
122 | var adjusted_position = Num.Vector2.Add(tick_absolute_position, | ||
|
|
123 | new Num.Vector2(0, -height_adjust)); | ||
|
|
124 | |||
|
|
125 | draw_list.AddText(font, 11.0f, adjusted_position, (uint)ImGuiColor.BLACK, label); | ||
|
|
126 | //Logging.Info(String.Format("Drawing {0:} at {1} ({2})", label, tick_absolute_position, tick_position)); | ||
|
|
127 | |||
|
|
128 | if (vertical) { | ||
|
|
129 | tick_position = new Num.Vector2(0, range.Y + ((i + 1) * tick_spacing)); | ||
|
|
130 | } | ||
|
|
131 | else { | ||
|
|
132 | tick_position = new Num.Vector2(range.X + ((i + 1) * tick_spacing), 0); | ||
|
|
133 | } | ||
|
|
134 | |||
|
|
135 | tick_absolute_position = Num.Vector2.Add(starting_position, tick_position); | ||
|
|
136 | } | ||
|
|
137 | } | ||
|
|
138 | |||
|
106 | public static void DrawLine(ImDrawListPtr draw_list, Num.Vector2 c, Num.Vector2[] points, ImGuiColor col) { |
|
139 | public static void DrawLine(ImDrawListPtr draw_list, Num.Vector2 c, Num.Vector2[] points, ImGuiColor col) { |
|
107 | var p = Num.Vector2.Zero; |
|
140 | var p = Num.Vector2.Zero; |
|
108 |
|
141 | ||
@@ -125,6 +158,29 | |||||
|
125 | return (int) (((num - domain.X) / domain_span) * range_span + range.X); |
|
158 | return (int) (((num - domain.X) / domain_span) * range_span + range.X); |
|
126 | } |
|
159 | } |
|
127 |
|
160 | ||
|
|
161 | public static float Scale(Num.Vector2 domain, Num.Vector2 range, float num) { | ||
|
|
162 | //https://stats.stackexchange.com/a/281164 | ||
|
|
163 | |||
|
|
164 | if (!float.IsNaN(domain.Y - domain.X)) { | ||
|
|
165 | var domain_span = Math.Sign(domain.Y - domain.X) * Math.Max(1, Math.Abs(domain.Y - domain.X)); | ||
|
|
166 | var range_span = range.Y - range.X; | ||
|
|
167 | |||
|
|
168 | var start = range.X - domain.X; | ||
|
|
169 | |||
|
|
170 | return (((num - domain.X) / domain_span) * range_span + range.X); | ||
|
|
171 | } | ||
|
|
172 | else { | ||
|
|
173 | return float.NaN; | ||
|
|
174 | } | ||
|
|
175 | } | ||
|
|
176 | |||
|
|
177 | public static float ScaleLogarithmic(Num.Vector2 domain, Num.Vector2 range, float num) { | ||
|
|
178 | var scaled_domain = new Num.Vector2((float)MathUtils.SymmetricLog10(domain.X), (float)MathUtils.SymmetricLog10(domain.Y)); | ||
|
|
179 | float scaled_num = num == 0 ? 0.0f : (float)MathUtils.SymmetricLog10(num); | ||
|
|
180 | |||
|
|
181 | return Scale(scaled_domain, range, scaled_num); | ||
|
|
182 | } | ||
|
|
183 | |||
|
128 | public static Num.Vector2 adjust_domain(int domain_min, int domain_max) |
|
184 | public static Num.Vector2 adjust_domain(int domain_min, int domain_max) |
|
129 | { |
|
185 | { |
|
130 | if (domain_max == int.MinValue) { |
|
186 | if (domain_max == int.MinValue) { |
@@ -139,6 +195,8 | |||||
|
139 | var domain_max_rounded = Math.Ceiling(domain_max / 50.0) * 50; |
|
195 | var domain_max_rounded = Math.Ceiling(domain_max / 50.0) * 50; |
|
140 | var domain_min_rounded = Math.Floor(domain_min / 50.0) * 50; |
|
196 | var domain_min_rounded = Math.Floor(domain_min / 50.0) * 50; |
|
141 |
|
197 | ||
|
|
198 | Logging.Info("Standard rounding."); | ||
|
|
199 | |||
|
142 | //Throw out rounding if result is too close together: |
|
200 | //Throw out rounding if result is too close together: |
|
143 | if (domain_min_rounded != domain_max_rounded) { |
|
201 | if (domain_min_rounded != domain_max_rounded) { |
|
144 | return new Num.Vector2((float)domain_min_rounded, (float)domain_max_rounded); |
|
202 | return new Num.Vector2((float)domain_min_rounded, (float)domain_max_rounded); |
@@ -147,11 +205,14 | |||||
|
147 | return new Num.Vector2(domain_min, domain_max); |
|
205 | return new Num.Vector2(domain_min, domain_max); |
|
148 | } |
|
206 | } |
|
149 |
|
207 | ||
|
|
208 | |||
|
150 | } |
|
209 | } |
|
151 | else { |
|
210 | else { |
|
152 | var lower = MathUtils.Clamp(domain_min, 0, 100); |
|
211 | var lower = MathUtils.Clamp(domain_min, 0, 100); |
|
153 | var upper = MathUtils.Clamp(domain_min, 10, 100); |
|
212 | var upper = MathUtils.Clamp(domain_min, 10, 100); |
|
154 |
|
213 | ||
|
|
214 | Logging.Info("Clamped rounding."); | ||
|
|
215 | |||
|
155 | return new Num.Vector2(domain_min-lower, domain_max+upper); |
|
216 | return new Num.Vector2(domain_min-lower, domain_max+upper); |
|
156 | } |
|
217 | } |
|
157 | } |
|
218 | } |
@@ -243,8 +304,8 | |||||
|
243 | var range = new Num.Vector2(200 - padding, 0 + padding); |
|
304 | var range = new Num.Vector2(200 - padding, 0 + padding); |
|
244 |
|
305 | ||
|
245 | //Zero |
|
306 | //Zero |
|
246 | var zero_point = Scale(domain, range, 0); |
|
307 | var zero_point = logarithmic ? ScaleLogarithmic(domain, range, 0) : Scale(domain, range, 0); |
|
247 | Logging.Spy(new {zero_point = zero_point}); |
|
308 | // Logging.Spy(new {zero_point = zero_point}); |
|
248 | draw_list.AddLine(Num.Vector2.Add(new Num.Vector2(padding, zero_point), c), |
|
309 | draw_list.AddLine(Num.Vector2.Add(new Num.Vector2(padding, zero_point), c), |
|
249 | Num.Vector2.Add(new Num.Vector2(350, zero_point), c), |
|
310 | Num.Vector2.Add(new Num.Vector2(350, zero_point), c), |
|
250 | (uint)ImGuiColor.LIGHTGREY, 1.0f); |
|
311 | (uint)ImGuiColor.LIGHTGREY, 1.0f); |
@@ -261,7 +322,7 | |||||
|
261 |
|
322 | ||
|
262 | if (data.Count() > 0 && show) |
|
323 | if (data.Count() > 0 && show) |
|
263 | { |
|
324 | { |
|
264 |
IEnumerable< |
|
325 | IEnumerable<float> data_array = data_sets[key].Select((p) => (logarithmic ? ScaleLogarithmic(domain, range, (float)p): Scale(domain, range, (float)p))); |
|
265 | var data_array2 = data_array.Select((p, i) => new Num.Vector2(Scale(x_domain, x_range, i), p)).ToArray(); |
|
326 | var data_array2 = data_array.Select((p, i) => new Num.Vector2(Scale(x_domain, x_range, i), p)).ToArray(); |
|
266 |
|
327 | ||
|
267 | DrawLine(draw_list, c, data_array2, color); |
|
328 | DrawLine(draw_list, c, data_array2, color); |
@@ -270,7 +331,12 | |||||
|
270 | } |
|
331 | } |
|
271 |
|
332 | ||
|
272 | DrawLinearAxis(draw_list, range /*new Num.Vector2(0, 200)*/, true, 11, Num.Vector2.Add(c, new Num.Vector2(padding, padding))); |
|
333 | DrawLinearAxis(draw_list, range /*new Num.Vector2(0, 200)*/, true, 11, Num.Vector2.Add(c, new Num.Vector2(padding, padding))); |
|
273 | DrawLinearLabels(font, draw_list, domain, range /*new Num.Vector2(0, 200)*/, true, 11, c); |
|
334 | if (logarithmic) { |
|
|
335 | DrawLogrithmicLabels(font, draw_list, domain, range, true, 11, c); | ||
|
|
336 | } | ||
|
|
337 | else { | ||
|
|
338 | DrawLinearLabels(font, draw_list, domain, range, true, 11, c); | ||
|
|
339 | } | ||
|
274 | DrawLinearAxis(draw_list, new Num.Vector2(0, 350), false, 12, Num.Vector2.Add(c, new Num.Vector2(padding, 200 - padding))); |
|
340 | DrawLinearAxis(draw_list, new Num.Vector2(0, 350), false, 12, Num.Vector2.Add(c, new Num.Vector2(padding, 200 - padding))); |
|
275 |
|
341 | ||
|
276 | ImGui.Dummy(new Num.Vector2(350, 200)); |
|
342 | ImGui.Dummy(new Num.Vector2(350, 200)); |
@@ -314,6 +380,12 | |||||
|
314 | ImGui.Text("Always show zero:"); |
|
380 | ImGui.Text("Always show zero:"); |
|
315 | ImGui.SameLine(); |
|
381 | ImGui.SameLine(); |
|
316 | ImGui.Checkbox("##AlwaysShowZero", ref always_show_zero); |
|
382 | ImGui.Checkbox("##AlwaysShowZero", ref always_show_zero); |
|
|
383 | #if DEBUG | ||
|
|
384 | ImGui.SameLine(); | ||
|
|
385 | ImGui.Text("Logarithmic: "); | ||
|
|
386 | ImGui.SameLine(); | ||
|
|
387 | ImGui.Checkbox("##Logarithmic", ref logarithmic); | ||
|
|
388 | #endif | ||
|
317 |
|
389 | ||
|
318 |
|
390 | ||
|
319 | #if DEBUG |
|
391 | #if DEBUG |
@@ -185,5 +185,13 | |||||
|
185 | throw new EmptyArrayException("Array must not be empty"); |
|
185 | throw new EmptyArrayException("Array must not be empty"); |
|
186 | } |
|
186 | } |
|
187 | } |
|
187 | } |
|
|
188 | |||
|
|
189 | public static float SymmetricLog10(float num) { | ||
|
|
190 | return num > 0.0f ? (float)Math.Log10(num) : -(float)Math.Log10(-num); | ||
|
|
191 | } | ||
|
|
192 | |||
|
|
193 | public static double SymmetricLog10(double num) { | ||
|
|
194 | return num > 0.0f ? Math.Log10(num) : -Math.Log10(-num); | ||
|
|
195 | } | ||
|
188 | } |
|
196 | } |
|
189 | } |
|
197 | } |
You need to be logged in to leave comments.
Login now