C#: Plot, Chart and ToRows

The namespace Mosaik.GraphDB.Plotting is imported in every C# notebook, so Plot, Chart and ToRows() need no using. In a Shell script or an endpoint, add using Mosaik.GraphDB.Plotting; to use ToRows(); a chart is only drawn by a notebook.

For guides with examples, see charts and tables and C# notebooks.

Plot

public static class Plot builds a Chart for each chart type. Rows are any IEnumerable<object>: anonymous types, records, dictionaries, or the result of ToRows(). Every method returns a Chart that can be refined before the cell ends.

Member Chart Channels set
Plot.Bar(rows, x, y, title = null) Bar Chart x, y
Plot.StackedBar(rows, x, y, color, title = null) Stacked Bar Chart x, y, color
Plot.Line(rows, x, y, title = null) Line Chart x, y
Plot.Area(rows, x, y, title = null) Area Chart x, y
Plot.Scatter(rows, x, y, title = null) Scatter Plot x, y
Plot.Pie(rows, category, value, title = null) Pie Chart color = category, size = value
Plot.Donut(rows, category, value, title = null) Donut Chart color = category, size = value
Plot.Histogram(rows, x, title = null) Histogram x
Plot.Heatmap(rows, x, y, color, title = null) Heatmap x, y, color
Plot.Of(chartType, rows) Any of the types in Plot.ChartTypes None; set them with Chart
Member Type Description
Plot.ChartTypes IReadOnlyList<string> The 39 chart type names Flint draws, as a spec names them.
Plot.MimeType string application/vnd.flint+json, the output type a chart travels as.

All field arguments are names of properties or keys in the rows. A null title leaves the chart untitled.

var sales = new[]
{
    new { Product = "Notebooks", Sales = 1840 },
    new { Product = "Pens", Sales = 2650 },
};

Plot.Bar(sales, x: "Product", y: "Sales", title: "Sales per product")

Plot.Of matches the type name without regard to case and writes it as Flint names it. A name that is not a chart type throws ArgumentException listing every valid name.

Chart

public sealed class Chart is a Flint spec being built. A cell that ends in a Chart draws it. A chart is created by Plot; it has no public constructor.

Member Description
Chart X(string field) The field on the x axis.
Chart Y(params string[] fields) The field, or fields, on the y axis. Several fields draw a series each.
Chart Color(string field) A series per value of the field.
Chart Size(string field) Sizes the marks by the field.
Chart Group(string field) Groups bars side by side.
Chart Encode(string channel, params string[] fields) Puts fields on any channel by name: x, y, color, size, shape, column, row, open, high, low, close and the rest of Flint's channels. A null or empty field leaves the channel as it was. One field is written as a string, several as an array.
Chart Title(string title) The title above the chart. Null leaves it unchanged.
Chart Semantic(string field, string semanticType) What a field means: Date, Amount, Percentage, Category, Country and the other Flint semantic types. Decides scale, format and colors. Fields without one are inferred from their values.
Chart Property(string name, object value) A property of the chart type, written under chartProperties: innerRadius, showPoints, stackMode, binCount, cornerRadius and others. The value is serialized as JSON.
string ToJson() The Flint spec: data.values, semantic_types (when any), and chart_spec with chartType, title, encodings and chartProperties.
override string ToString() What a notebook shows when it cannot draw: <Bar Chart: 3 rows, "Sales per product">.
const int MaxRows 50,000.

Every method that sets something returns the same Chart, so calls chain.

Rows

Each row is serialized with System.Text.Json and must be a JSON object, so an anonymous type, a record, a class with public properties or a dictionary with string keys all work. A row that is a bare value, such as a number or a string, throws ArgumentException. More than Chart.MaxRows rows throws ArgumentException asking you to aggregate first.

The spec

{
  "data": { "values": [ { "Product": "Notebooks", "Sales": 1840 }, { "Product": "Pens", "Sales": 2650 } ] },
  "chart_spec": {
    "chartType": "Bar Chart",
    "title": "Sales per product",
    "encodings": { "x": "Product", "y": "Sales" }
  }
}

This is the JSON a ```flint fence in a chat reply holds, so it can be pasted into one.

ToRows

public static class QueryRowExtensions adds two extension methods that turn a query, or nodes, into rows that Plot can chart.

Signature Description
List<Dictionary<string, object>> ToRows(this IQuery query, params string[] fields) The query's nodes as rows.
List<Dictionary<string, object>> ToRows(this IEnumerable<ReadOnlyNode> nodes, params string[] fields) A list of nodes as rows.
  • Columns. With no fields, the columns are UID, Type, then every field in the order it is first seen. With fields, only those columns, in that order. "Timestamp" can be named. A node without a field has null there, so every row has every column.
  • Values. Numbers (as long or double), strings, booleans and lists. A time or a UID is its text.
  • Hidden fields. A field the schema hides ([InternalNodeHidden]) is not included.
  • Never-returnable node types. Types that never leave the server, such as secrets and tokens, are dropped from a query, as Emit drops them. This applies to the query overload.
  • Limit. More than 100,000 nodes throws InvalidOperationException: "A table takes at most 100000 rows. Narrow the query first." The error is never silent; nothing is cut.
var rows = Q().StartAt("Ticket").ToRows("Status", "Priority");

The same conversion is available in Python as dataframe() and query_rows().