Skip to content

Commit 3e8b54e

Browse files
committed
Ansi colors
1 parent 61f88b6 commit 3e8b54e

File tree

6 files changed

+277
-12
lines changed

6 files changed

+277
-12
lines changed

AsciiChart.Sharp.TestApp/Program.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,20 @@ static void Main()
3939

4040
Console.WriteLine();
4141
Console.WriteLine(AsciiChart.Plot(
42-
Enumerable.Range(0, 6)
43-
.Select(i => Enumerable.Range(-40, 81).Select(x => Math.Abs(x) > 40 - i ? double.NaN : Math.Sqrt((40 - i) * (40 - i) - x * x) / 2))
44-
.ToList(),
45-
new Options { AxisLabelFormat = "0" }));
42+
Enumerable.Range(0, 6).Select(i => Enumerable.Range(-40, 81).Select(x => Math.Abs(x) > 40 - i ? double.NaN : Math.Sqrt((40 - i) * (40 - i) - x * x) / 2)),
43+
new Options
44+
{
45+
AxisLabelFormat = "0",
46+
SeriesColors = new[]
47+
{
48+
AnsiColor.Red,
49+
AnsiColor.Orange,
50+
AnsiColor.Yellow,
51+
AnsiColor.Green,
52+
AnsiColor.Blue,
53+
AnsiColor.Purple,
54+
}
55+
}));
4656
}
4757
}
4858
}

AsciiChart.Sharp.Tests/Tests.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,11 @@ public void TestPlot(double[] series, Options opts, string expected)
210210
0.30 ┤ ╭╴
211211
0.20 ┤╭╯
212212
0.10 ┼╯"
213-
}
213+
},
214+
new object[]
215+
{
216+
new[] { double.NaN, 1 }, new Options { AxisColor = AnsiColor.Green, LabelColor = AnsiColor.Red }, "\x1b[91m 1.00\x1b[0m \x1b[32m┤\x1b[0m╶ "
217+
},
214218
};
215219

216220
[Test]
@@ -240,9 +244,24 @@ public void TestPlotMulti(double[][] series, Options opts, string expected)
240244
new object[]
241245
{
242246
new[] { new double[] { 0, 0, 0 }, new[] { double.NaN, 0, 0 }, new[] { double.NaN, double.NaN, 0 } }, null, " 0.00 ┼╶╶ "
247+
},
248+
new object[]
249+
{
250+
new[] { new double[] { 0, 0 }, new[] { double.NaN, 0 } }, new Options { SeriesColors = new[] { AnsiColor.Red } }, " 0.00 \x1b[91m┼\x1b[0m╶ "
251+
},
252+
new object[]
253+
{
254+
new[] { new double[] { 0, 0 }, new[] { double.NaN, 0 } }, new Options { SeriesColors = new[] { AnsiColor.Default, AnsiColor.Red } }, " 0.00 ┼\x1b[91m╶\x1b[0m "
255+
},
256+
new object[]
257+
{
258+
new[] { new[] { double.NaN, 0, 2 }, new double[] { 0, 2 } }, new Options { SeriesColors = new[] { AnsiColor.Red, AnsiColor.Red } }, @"
259+
2.00 ┤\x1b[91m╭╭\x1b[0m
260+
1.00 ┤\x1b[91m││\x1b[0m
261+
0.00 \x1b[91m┼╯╯\x1b[0m"
243262
}
244263
};
245264

246-
static string Normalize(string text) => _normalize.Replace(text.Trim('\r', '\n') + Environment.NewLine, Environment.NewLine);
265+
static string Normalize(string text) => _normalize.Replace(text.Trim('\r', '\n') + Environment.NewLine, Environment.NewLine).Replace(@"\x1b", "\x1b");
247266
}
248267
}

AsciiChart.Sharp/AsciiChart.Sharp.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
<PropertyGroup>
44
<TargetFramework>netstandard1.0</TargetFramework>
5+
<PackageVersion>1.0.2</PackageVersion>
6+
<AssemblyVersion>1.0.2</AssemblyVersion>
7+
<FileVersion>1.0.0</FileVersion>
58
</PropertyGroup>
69

710
</Project>

AsciiChart.Sharp/AsciiChart.cs

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Text;
45

56
namespace AsciiChart.Sharp
67
{
@@ -37,17 +38,22 @@ public static string Plot(IEnumerable<IEnumerable<double>> data, Options options
3738
var width = dataList.Max(s => s.Count()) + columnIndexOfFirstDataPoint;
3839

3940
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();
4042

4143
var yAxisLabels = GetYAxisLabels(max, range, rows, options);
42-
ApplyYAxisLabels(resultArray, yAxisLabels, columnIndexOfFirstDataPoint);
44+
ApplyYAxisLabels(resultArray, colorArray, yAxisLabels, columnIndexOfFirstDataPoint, options);
4345

46+
var i = 0;
4447
foreach (var series in dataList)
4548
{
49+
var color = options.SeriesColors?.Length > i ? options.SeriesColors[i++] : AnsiColor.Default;
50+
4651
var seriesList = series.ToList();
4752
var rowIndex0 = Math.Round(seriesList[0] * ratio, MidpointRounding.AwayFromZero) - min2;
4853
if (!double.IsNaN(rowIndex0))
4954
{
5055
resultArray[(int)(rows - rowIndex0)][columnIndexOfFirstDataPoint - 1] = "┼";
56+
colorArray[(int)(rows - rowIndex0)][columnIndexOfFirstDataPoint - 1] = color;
5157
}
5258

5359
for (var x = 0; x < seriesList.Count - 1; x++)
@@ -82,11 +88,25 @@ public static string Plot(IEnumerable<IEnumerable<double>> data, Options options
8288
}
8389
}
8490

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+
85105
rowIndex0 = rowIndex1;
86106
}
87107
}
88108

89-
return ToString(resultArray);
109+
return ToString(resultArray, colorArray);
90110
}
91111

92112
static string[][] CreateAndFill2dArray(double rows, int width, string fill)
@@ -130,19 +150,70 @@ static IEnumerable<double> GetYAxisTicks(double max, double range, double rows)
130150
return yTicks;
131151
}
132152

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)
134154
{
135155
for (var i = 0; i < yAxisLabels.Count; i++)
136156
{
137157
resultArray[i][0] = yAxisLabels[i].Label;
158+
colorArray[i][0] = options.LabelColor;
138159
resultArray[i][columnIndexOfFirstDataPoint - 1] = "┤";
160+
colorArray[i][columnIndexOfFirstDataPoint - 1] = options.AxisColor;
139161
}
140162
}
141163

142-
static string ToString(IReadOnlyList<string[]> resultArray)
164+
static string ToString(IReadOnlyList<string[]> resultArray, IReadOnlyList<AnsiColor[]> colorArray)
143165
{
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");
146217
}
147218

148219
class AxisLabel

AsciiChart.Sharp/Color.cs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
namespace AsciiChart.Sharp
2+
{
3+
public enum AnsiColor : byte
4+
{
5+
Default = 0,
6+
AliceBlue = 255,
7+
AntiqueWhite = 255,
8+
Aqua = 14,
9+
Aquamarine = 122,
10+
Azure = 15,
11+
Beige = 230,
12+
Bisque = 224,
13+
Black = 188, // dummy value
14+
BlanchedAlmond = 230,
15+
Blue = 12,
16+
BlueViolet = 92,
17+
Brown = 88,
18+
BurlyWood = 180,
19+
CadetBlue = 73,
20+
Chartreuse = 118,
21+
Chocolate = 166,
22+
Coral = 209,
23+
CornflowerBlue = 68,
24+
Cornsilk = 230,
25+
Crimson = 161,
26+
Cyan = 14,
27+
DarkBlue = 18,
28+
DarkCyan = 30,
29+
DarkGoldenrod = 136,
30+
DarkGray = 248,
31+
DarkGreen = 22,
32+
DarkKhaki = 143,
33+
DarkMagenta = 90,
34+
DarkOliveGreen = 59,
35+
DarkOrange = 208,
36+
DarkOrchid = 134,
37+
DarkRed = 88,
38+
DarkSalmon = 173,
39+
DarkSeaGreen = 108,
40+
DarkSlateBlue = 60,
41+
DarkSlateGray = 238,
42+
DarkTurquoise = 44,
43+
DarkViolet = 92,
44+
DeepPink = 198,
45+
DeepSkyBlue = 39,
46+
DimGray = 242,
47+
DodgerBlue = 33,
48+
Firebrick = 124,
49+
FloralWhite = 15,
50+
ForestGreen = 28,
51+
Fuchsia = 13,
52+
Gainsboro = 253,
53+
GhostWhite = 15,
54+
Gold = 220,
55+
Goldenrod = 178,
56+
Gray = 8,
57+
Green = 2,
58+
GreenYellow = 155,
59+
Honeydew = 15,
60+
HotPink = 205,
61+
IndianRed = 167,
62+
Indigo = 54,
63+
Ivory = 15,
64+
Khaki = 222,
65+
Lavender = 254,
66+
LavenderBlush = 255,
67+
LawnGreen = 118,
68+
LemonChiffon = 230,
69+
LightBlue = 152,
70+
LightCoral = 210,
71+
LightCyan = 195,
72+
LightGoldenrodYellow = 230,
73+
LightGray = 252,
74+
LightGreen = 120,
75+
LightPink = 217,
76+
LightSalmon = 216,
77+
LightSeaGreen = 37,
78+
LightSkyBlue = 117,
79+
LightSlateGray = 103,
80+
LightSteelBlue = 152,
81+
LightYellow = 230,
82+
Lime = 10,
83+
LimeGreen = 77,
84+
Linen = 255,
85+
Magenta = 13,
86+
Maroon = 1,
87+
MediumAquamarine = 79,
88+
MediumBlue = 20,
89+
MediumOrchid = 134,
90+
MediumPurple = 98,
91+
MediumSeaGreen = 72,
92+
MediumSlateBlue = 99,
93+
MediumSpringGreen = 48,
94+
MediumTurquoise = 80,
95+
MediumVioletRed = 162,
96+
MidnightBlue = 17,
97+
MintCream = 15,
98+
MistyRose = 224,
99+
Moccasin = 223,
100+
NavajoWhite = 223,
101+
Navy = 4,
102+
OldLace = 230,
103+
Olive = 3,
104+
OliveDrab = 64,
105+
Orange = 214,
106+
OrangeRed = 202,
107+
Orchid = 170,
108+
PaleGoldenrod = 223,
109+
PaleGreen = 120,
110+
PaleTurquoise = 159,
111+
PaleVioletRed = 168,
112+
PapayaWhip = 230,
113+
PeachPuff = 223,
114+
Peru = 173,
115+
Pink = 218,
116+
Plum = 182,
117+
PowderBlue = 152,
118+
Purple = 5,
119+
Red = 9,
120+
RosyBrown = 138,
121+
RoyalBlue = 63,
122+
SaddleBrown = 94,
123+
Salmon = 210,
124+
SandyBrown = 215,
125+
SeaGreen = 29,
126+
SeaShell = 15,
127+
Sienna = 131,
128+
Silver = 7,
129+
SkyBlue = 117,
130+
SlateBlue = 62,
131+
SlateGray = 66,
132+
Snow = 15,
133+
SpringGreen = 48,
134+
SteelBlue = 67,
135+
Tan = 180,
136+
Teal = 6,
137+
Thistle = 182,
138+
Tomato = 203,
139+
Turquoise = 80,
140+
Violet = 213,
141+
Wheat = 223,
142+
White = 15,
143+
WhiteSmoke = 255,
144+
Yellow = 11,
145+
YellowGreen = 149,
146+
}
147+
}

AsciiChart.Sharp/Options.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,20 @@ public int AxisLabelRightMargin
5353
/// The axis label format.
5454
/// </summary>
5555
public string AxisLabelFormat { get; set; } = "0.00";
56+
57+
/// <summary>
58+
/// The axis color.
59+
/// </summary>
60+
public AnsiColor AxisColor { get; set; }
61+
62+
/// <summary>
63+
/// The axis label color.
64+
/// </summary>
65+
public AnsiColor LabelColor { get; set; }
66+
67+
/// <summary>
68+
/// The color of each series.
69+
/// </summary>
70+
public AnsiColor[] SeriesColors { get; set; }
5671
}
5772
}

0 commit comments

Comments
 (0)