{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[this doc on github](https://github.com/dotnet/interactive/tree/main/samples/notebooks/csharp/Docs)\n", "\n", "# Formatting Outputs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## HTML Formatting\n", "\n", "When you return a value or a display a value using a .NET kernel, the default formatting behavior normally uses HTML to try to provide some useful information about the object. \n", "\n", "### Enumerables \n", "\n", "If the object is an array or other type implementing `IEnumerable` and the values within it are simple values such as `string` or `int` values, the output looks like this:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "
[ hello, world ]
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
[ 1, 2, 3, 4, 5 ]
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "new [] {\"hello\", \"world\"}.Display();\n", "\n", "Enumerable.Range(1, 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Objects with properties\n", "\n", "The default formatting behavior for other types of objects is to produce an expandable table showing their properties and the values of those properties." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "
Submission#3+Person
FirstName
Mitch
LastName
Buchannon
Age
42
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "class Person \n", "{\n", " public string FirstName { get; set; }\n", " public string LastName { get; set; }\n", " public int Age { get; set; } \n", "}\n", "\n", "new Person { FirstName = \"Mitch\", LastName = \"Buchannon\", Age = 42}.Display();" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "
indexvalue
0
Submission#3+Person
FirstName
Mitch
LastName
Buchannon
Age
42
1
Submission#3+Person
FirstName
Hobie 
LastName
Buchannon
Age
23
2
Submission#3+Person
FirstName
Summer
LastName
Quinn
Age
25
3
Submission#3+Person
FirstName
C.J.
LastName
Parker
Age
23
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "var groupOfPeople = new [] \n", "{\n", " new Person { FirstName = \"Mitch\", LastName = \"Buchannon\", Age = 42 },\n", " new Person { FirstName = \"Hobie \", LastName = \"Buchannon\", Age = 23 },\n", " new Person { FirstName = \"Summer\", LastName = \"Quinn\", Age = 25 },\n", " new Person { FirstName = \"C.J.\", LastName = \"Parker\", Age = 23 },\n", "};\n", "\n", "groupOfPeople.Display();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, you can use the `DisplayTable` method, which provides a layoutw that uses the properties as column headers." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/csv": [ "FirstName,LastName,Age\r\n", "Mitch,Buchannon,42\r\n", "\"Hobie \",Buchannon,23\r\n", "Summer,Quinn,25\r\n", "C.J.,Parker,23\r\n" ], "text/html": [ "
FirstNameLastNameAge
MitchBuchannon
42
Hobie Buchannon
23
SummerQuinn
25
C.J.Parker
23
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "groupOfPeople.DisplayTable();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dictionaries\n", "\n", "Similarly to the behavior for `IEnumerable` objects, you'll see tree output for dictionaries, but for each value in the dictionary, the key is provided rather than the index within the collection." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "
keyvalue
zero
0
one
1
two
2
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "var dictionary = new Dictionary\n", "{\n", " [\"zero\"] = 0,\n", " [\"one\"] = 1,\n", " [\"two\"] = 2\n", "};\n", "dictionary" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "
keyvalue
Mitch
Submission#3+Person
FirstName
Mitch
LastName
Buchannon
Age
42
Hobie 
Submission#3+Person
FirstName
Hobie 
LastName
Buchannon
Age
23
Summer
Submission#3+Person
FirstName
Summer
LastName
Quinn
Age
25
C.J.
Submission#3+Person
FirstName
C.J.
LastName
Parker
Age
23
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "groupOfPeople.ToDictionary(p => $\"{p.FirstName}\").Display();\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's try something a bit more complex. Let's look at a graph of objects. \n", "\n", "We'll redefine the `Person` class to allow a reference to a collection of other `Person` instances." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "
indexvalue
0
Submission#8+Person
FirstName
Mitch
LastName
Buchannon
Age
42
Friends
indexvalue
0
Submission#8+Person
FirstName
Hobie 
LastName
Buchannon
Age
23
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstName
Summer
LastName
Quinn
Age
25
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstName
C.J.
LastName
Parker
Age
23
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstName
Hobie 
LastName
Buchannon
Age
23
Friends
indexvalue
0
Submission#8+Person
FirstName
Mitch
LastName
Buchannon
Age
42
Friends
indexvalue
0
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstName
Summer
LastName
Quinn
Age
25
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstName
C.J.
LastName
Parker
Age
23
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstName
Summer
LastName
Quinn
Age
25
Friends
indexvalue
0
Submission#8+Person
FirstName
Mitch
LastName
Buchannon
Age
42
Friends
indexvalue
0
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstName
Hobie 
LastName
Buchannon
Age
23
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstName
C.J.
LastName
Parker
Age
23
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
3
Submission#8+Person
FirstName
C.J.
LastName
Parker
Age
23
Friends
indexvalue
0
Submission#8+Person
FirstName
Mitch
LastName
Buchannon
Age
42
Friends
indexvalue
0
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstName
Hobie 
LastName
Buchannon
Age
23
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameSummer
LastNameQuinn
Age25
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstName
Summer
LastName
Quinn
Age
25
Friends
indexvalue
0
Submission#8+Person
FirstNameMitch
LastNameBuchannon
Age42
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
1
Submission#8+Person
FirstNameHobie
LastNameBuchannon
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
2
Submission#8+Person
FirstNameC.J.
LastNameParker
Age23
Friends[ Submission#8+Person, Submission#8+Person, Submission#8+Person ]
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "class Person \n", "{\n", " public string FirstName { get; set; }\n", " public string LastName { get; set; }\n", " public int Age { get; set; } \n", " public List Friends { get; } = new List();\n", "}\n", "\n", "\n", "var mitch = new Person { FirstName = \"Mitch\", LastName = \"Buchannon\", Age = 42 };\n", "var hobie = new Person { FirstName = \"Hobie \", LastName = \"Buchannon\", Age = 23 };\n", "var summer = new Person { FirstName = \"Summer\", LastName = \"Quinn\", Age = 25 };\n", "var cj = new Person { FirstName = \"C.J.\", LastName = \"Parker\", Age = 23 };\n", "\n", "mitch.Friends.AddRange(new [] { hobie, summer, cj });\n", "hobie.Friends.AddRange(new [] { mitch, summer, cj });\n", "summer.Friends.AddRange(new [] { mitch, hobie, cj });\n", "cj.Friends.AddRange(new [] { mitch, hobie, summer });\n", "\n", "var groupOfPeople = new List { mitch, hobie, summer, cj };\n", "\n", "groupOfPeople.Display();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Customization\n", "\n", "## Registering plain text formatters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's clean up the output above by customizing the formatter for the `Person.Friends` property, which is creating a lot of noise. \n", "\n", "The way to do this is to use the `Formatter` API. This API lets you customize the formatting for a specific type. For example:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "
indexvalue
0person
1person
2person
3person
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "using Microsoft.DotNet.Interactive.Formatting;\n", "\n", "Formatter.Register((person, writer) => {\n", " writer.Write(\"person\");\n", "}, mimeType: \"text/html\");\n", "\n", "groupOfPeople" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With that in mind, we can make it even more concise by registering a good formatter for `Person`:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "
indexvalue
0Mitch
1Hobie
2Summer
3C.J.
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "Formatter.ResetToDefault();\n", "\n", "Formatter.Register((person, writer) => {\n", " writer.Write(person.FirstName);\n", "}, mimeType: \"text/html\");\n", "\n", "groupOfPeople" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Registering HTML formatters\n", "\n", "To replace the default HTML table view, you can register a formatter for the `\"text/html\"` mime type. Let's do that, and write some HTML using PocketView." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "dotnet_interactive": { "language": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [ { "data": { "text/html": [ "Mitch (42 years old and has 3 friends)
Hobie (23 years old and has 3 friends)
Summer (25 years old and has 3 friends)
C.J. (23 years old and has 3 friends)
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "using static Microsoft.DotNet.Interactive.Formatting.PocketViewTags;\n", " \n", "Formatter.ResetToDefault();\n", "Formatter.Register>((people, writer) => \n", "{\n", " foreach (var person in people)\n", " {\n", " writer.Write(\n", " span(\n", " b(person.FirstName), \n", " \" \",\n", " i($\"({person.Age} years old and has {person.Friends.Count} friends)\"),\n", " br));\n", " }\n", "}, mimeType: \"text/html\");\n", "\n", "groupOfPeople" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "**_See also_**\n", "* [Displaying output](Displaying%20output.ipynb)\n", "* [HTML](HTML.ipynb)" ] } ], "metadata": { "kernelspec": { "display_name": ".NET (C#)", "language": "C#", "name": ".net-csharp" }, "language_info": { "file_extension": ".cs", "mimetype": "text/x-csharp", "name": "C#", "pygments_lexer": "csharp", "version": "8.0" } }, "nbformat": 4, "nbformat_minor": 4 }