|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Linq; |
| 4 | +using System.Text; |
4 | 5 |
|
5 | 6 | namespace AsciiChart.Sharp |
6 | 7 | { |
@@ -37,17 +38,22 @@ public static string Plot(IEnumerable<IEnumerable<double>> data, Options options |
37 | 38 | var width = dataList.Max(s => s.Count()) + columnIndexOfFirstDataPoint; |
38 | 39 |
|
39 | 40 | var resultArray = CreateAndFill2dArray(rows, width, options.Fill.ToString()); |
| 41 | + var colorArray = Enumerable.Repeat(Enumerable.Repeat(AnsiColor.Default, width), (int)rows + 1).Select(row => row.ToArray()).ToArray(); |
40 | 42 |
|
41 | 43 | var yAxisLabels = GetYAxisLabels(max, range, rows, options); |
42 | | - ApplyYAxisLabels(resultArray, yAxisLabels, columnIndexOfFirstDataPoint); |
| 44 | + ApplyYAxisLabels(resultArray, colorArray, yAxisLabels, columnIndexOfFirstDataPoint, options); |
43 | 45 |
|
| 46 | + var i = 0; |
44 | 47 | foreach (var series in dataList) |
45 | 48 | { |
| 49 | + var color = options.SeriesColors?.Length > i ? options.SeriesColors[i++] : AnsiColor.Default; |
| 50 | + |
46 | 51 | var seriesList = series.ToList(); |
47 | 52 | var rowIndex0 = Math.Round(seriesList[0] * ratio, MidpointRounding.AwayFromZero) - min2; |
48 | 53 | if (!double.IsNaN(rowIndex0)) |
49 | 54 | { |
50 | 55 | resultArray[(int)(rows - rowIndex0)][columnIndexOfFirstDataPoint - 1] = "┼"; |
| 56 | + colorArray[(int)(rows - rowIndex0)][columnIndexOfFirstDataPoint - 1] = color; |
51 | 57 | } |
52 | 58 |
|
53 | 59 | for (var x = 0; x < seriesList.Count - 1; x++) |
@@ -82,11 +88,25 @@ public static string Plot(IEnumerable<IEnumerable<double>> data, Options options |
82 | 88 | } |
83 | 89 | } |
84 | 90 |
|
| 91 | + var lower = double.IsNaN(rowIndex0) ? rowIndex1 : rowIndex0; |
| 92 | + var upper = double.IsNaN(rowIndex1) ? rowIndex0 : rowIndex1; |
| 93 | + if (lower > upper) |
| 94 | + { |
| 95 | + var tmp = lower; |
| 96 | + lower = upper; |
| 97 | + upper = tmp; |
| 98 | + } |
| 99 | + |
| 100 | + for (var y = lower; y <= upper; y++) |
| 101 | + { |
| 102 | + colorArray[(int)(rows - y)][x + columnIndexOfFirstDataPoint] = color; |
| 103 | + } |
| 104 | + |
85 | 105 | rowIndex0 = rowIndex1; |
86 | 106 | } |
87 | 107 | } |
88 | 108 |
|
89 | | - return ToString(resultArray); |
| 109 | + return ToString(resultArray, colorArray); |
90 | 110 | } |
91 | 111 |
|
92 | 112 | static string[][] CreateAndFill2dArray(double rows, int width, string fill) |
@@ -130,19 +150,70 @@ static IEnumerable<double> GetYAxisTicks(double max, double range, double rows) |
130 | 150 | return yTicks; |
131 | 151 | } |
132 | 152 |
|
133 | | - static void ApplyYAxisLabels(IReadOnlyList<string[]> resultArray, IReadOnlyList<AxisLabel> yAxisLabels, int columnIndexOfFirstDataPoint) |
| 153 | + static void ApplyYAxisLabels(IReadOnlyList<string[]> resultArray, IReadOnlyList<AnsiColor[]> colorArray, IReadOnlyList<AxisLabel> yAxisLabels, int columnIndexOfFirstDataPoint, Options options) |
134 | 154 | { |
135 | 155 | for (var i = 0; i < yAxisLabels.Count; i++) |
136 | 156 | { |
137 | 157 | resultArray[i][0] = yAxisLabels[i].Label; |
| 158 | + colorArray[i][0] = options.LabelColor; |
138 | 159 | resultArray[i][columnIndexOfFirstDataPoint - 1] = "┤"; |
| 160 | + colorArray[i][columnIndexOfFirstDataPoint - 1] = options.AxisColor; |
139 | 161 | } |
140 | 162 | } |
141 | 163 |
|
142 | | - static string ToString(IReadOnlyList<string[]> resultArray) |
| 164 | + static string ToString(IReadOnlyList<string[]> resultArray, IReadOnlyList<AnsiColor[]> colorArray) |
143 | 165 | { |
144 | | - var rowStrings = resultArray.Select(row => string.Join("", row)); |
145 | | - return string.Join(Environment.NewLine, rowStrings); |
| 166 | + var builder = new StringBuilder(); |
| 167 | + for (var y = 0; y < resultArray.Count; y++) |
| 168 | + { |
| 169 | + var prev = AnsiColor.Default; |
| 170 | + for (var x = 0; x < resultArray[y].Length; x++) |
| 171 | + { |
| 172 | + var color = colorArray[y][x]; |
| 173 | + if (color != prev) |
| 174 | + { |
| 175 | + builder.Append(ColorString(color)); |
| 176 | + prev = color; |
| 177 | + } |
| 178 | + |
| 179 | + builder.Append(resultArray[y][x]); |
| 180 | + } |
| 181 | + |
| 182 | + if (y < resultArray.Count - 1) |
| 183 | + { |
| 184 | + builder.Append(Environment.NewLine); |
| 185 | + } |
| 186 | + } |
| 187 | + |
| 188 | + return builder.ToString(); |
| 189 | + } |
| 190 | + |
| 191 | + static string ColorString(AnsiColor color) |
| 192 | + { |
| 193 | + if (color == AnsiColor.Default) |
| 194 | + { |
| 195 | + return "\x1b[0m"; |
| 196 | + } |
| 197 | + |
| 198 | + if (color == AnsiColor.Black) |
| 199 | + { |
| 200 | + color = AnsiColor.Default; |
| 201 | + } |
| 202 | + |
| 203 | + if (color <= AnsiColor.Silver) |
| 204 | + { |
| 205 | + // 3-bit color |
| 206 | + return $"\x1b[{30 + (byte)color}m"; |
| 207 | + } |
| 208 | + |
| 209 | + if (color <= AnsiColor.White) |
| 210 | + { |
| 211 | + // 4-bit color |
| 212 | + return ($"\x1b[{82 + (byte)color}m"); |
| 213 | + } |
| 214 | + |
| 215 | + // 8-bit color |
| 216 | + return ($"\x1b[38;5;{(byte)color}m"); |
146 | 217 | } |
147 | 218 |
|
148 | 219 | class AxisLabel |
|
0 commit comments