I've started working with Plotly.NET which is written in F# and has a C# adapter. The API between C# & F# seems a bit inconsistent. What I'm trying to accomplish as given as an example in F# in the Plotly.NET documentation.
Value dependent cell coloring: https://plotly.net/simple-charts/table.html
Here is the code as written in F#.
let table3 =
let header2 = [ "Identifier"; "T0"; "T1"; "T2"; "T3" ]
let rowvalues =
[ [ 10001.; 0.2; 2.0; 4.0; 5.0 ]
[ 10002.; 2.1; 2.0; 1.8; 2.1 ]
[ 10003.; 4.5; 3.0; 2.0; 2.5 ]
[ 10004.; 0.0; 0.1; 0.3; 0.2 ]
[ 10005.; 1.0; 1.6; 1.8; 2.2 ]
[ 10006.; 1.0; 0.8; 1.5; 0.7 ]
[ 10007.; 2.0; 2.0; 2.1; 1.9 ] ]
|> Seq.sortBy (fun x -> x.[1])
//map color from value to hex representation
let mapColor min max value =
let proportion = (255. * (value - min) / (max - min)) |> int
Color.fromRGB 255 (255 - proportion) proportion
//Assign a color to every cell seperately. Matrix must be transposed for correct orientation.
let cellcolor =
rowvalues
|> Seq.map (fun row ->
row
|> Seq.mapi (fun index value ->
if index = 0 then
Color.fromString "white"
else
mapColor 0. 5. value))
|> Seq.transpose
|> Seq.map Color.fromColors
|> Color.fromColors
Chart.Table(headerValues = header2, cellsValues = rowvalues, CellsFillColor = cellcolor)
I've tried to reproduce this in C# a few times. There are Namespace issues with Plotly.NET. If you are using the Plotly.NET.CSharp Nuget Package, you'll find you need to explicitly reference anything in the Plotly.NET namespace, as there are many conflicts.
Plotly.NET.TraceDomain.initTable() is one way of creating a table, and the other is through the .CSharp namespace. Here is some working code that will create a Plotly Table through the CSharp namespace which is higher level code.
public class PlotlyTablePlotter
{
public static void CreateTable(IEnumerable<IEnumerable<string>> headerData, IEnumerable<IEnumerable<string>> rowData)
{
var transposedHeader = Transpose(headerData);
var header = TableCells.init<IEnumerable<string>, string>(
Align: FSharpOption<Plotly.NET.StyleParam.HorizontalAlign>.Some(Plotly.NET.StyleParam.HorizontalAlign.Center),
Font: FSharpOption<Plotly.NET.Font>.Some(Plotly.NET.Font.init(Size: 14)),
Values: FSharpOption<IEnumerable<IEnumerable<string>>>.Some(transposedHeader)
);
var transposedRows = Transpose(rowData);
var rows = TableCells.init<IEnumerable<string>, string>(
Fill: FSharpOption<Plotly.NET.TraceObjects.TableFill>.Some(TableFill.init(Color : Plotly.NET.Color.fromString("red"))),
Values: FSharpOption<IEnumerable<IEnumerable<string>>>.Some(transposedRows)
);
var table = Plotly.NET.CSharp.Chart.Table(
header,
rows,
Name: "Test"
);
table.Show();
}
/// <summary>
/// Plotly is column major.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private static IEnumerable<IEnumerable<string>> Transpose(IEnumerable<IEnumerable<string>> data)
{
var columns = new List<IEnumerable<string>>();
for (int i = 0; i < data.First().Count(); i++)
{
var column = new List<string>();
foreach (var row in data)
{
column.Add(row.ElementAt(i));
}
columns.Add(column);
}
return columns;
}
}
What I can't do through this interface is set a cells fill color per cell. The C# call to init a row provides the method parameter Fill:
Fill: FSharpOption<Plotly.NET.TraceObjects.TableFill>.Some(TableFill.init(Color : Plotly.NET.Color.fromString("red"))),
This fills the entire table with the same background color. I've looked at Table.style() function that's provided in the CSharp namepace, and I can't figure out how to work that to give what I want either.
I'd appreciate seeing how to do the above demo in C# if possible. And if not possible, I'd like that confirmation.
There are multiple ways to solve this issue. Just for context, i currently do not work on the CSharp API because i want to auto-generate these bindings based on the F# library eventually, as keeping it in sync with the core F# API manually is a huge pain. When that is done, there should be no need to reference anything else in C#.
First, this might be solvable just via using the Color abstraction correctly. I cannot get your example to work in my notebook, but in this line:
try creating a color colection via
Color.fromColors
. You can learn more about color abstractions here: https://plotly.net/general/working-with-colors.htmlThat being said, Plotly.NET is designed in such a way that there are always fallback mechanisms in lower level APIs when the high level abstractions are not sufficient. In this case, there would be the following options: