Logo Deedle

Deedle.DotNetInteractive — .NET Interactive Notebook Formatting

The Deedle.DotNetInteractive package registers HTML formatters for Deedle frames and series in .NET Interactive notebooks — including Polyglot Notebooks (VS Code) and Jupyter via the .NET kernel.

Install it alongside Deedle in a notebook cell:

#r "nuget: Deedle"
#r "nuget: Deedle.DotNetInteractive"

Once loaded, any Frame<_,_> or Series<_,_> displayed in a notebook cell is automatically rendered as a styled HTML table instead of plain text.

Example output

Below is a frame as it would appear in a notebook. When using Deedle.DotNetInteractive, display output includes column types, dimensions, and missing-value counts.

let prices =
    frame [ "Open"  => Series.ofValues [ 100.0; 102.5; 101.0; 103.0 ]
            "Close" => Series.ofValues [ 101.5; 101.0; 103.5; 104.0 ]
            "Vol"   => Series.ofValues [ 12000; 15000; 11000; 14000 ] ]
val prices: Frame<int,string> =
  
     Open  Close Vol   
0 -> 100   101.5 12000 
1 -> 102.5 101   15000 
2 -> 101   103.5 11000 
3 -> 103   104   14000
let vols = Series.ofValues [ 12000; 15000; 11000; 14000 ]
val vols: Series<int,int> = 
0 -> 12000 
1 -> 15000 
2 -> 11000 
3 -> 14000

Configuring display options

The InteractiveConfig module lets you control how frames and series are rendered. All settings are mutable and take effect immediately for subsequent cell evaluations.

Frame display settings

Setting

Default

Description

InteractiveConfig.Frame.MaxRows

10

Maximum rows to display before truncating

InteractiveConfig.Frame.MaxCols

20

Maximum columns to display before truncating

InteractiveConfig.Frame.ShowColTypes

true

Show column type names in the header

InteractiveConfig.Frame.ShowInfo

true

Show the info footer (dimensions and/or missing counts)

InteractiveConfig.Frame.ShowDimensions

true

Show "N rows x M columns" in the footer

InteractiveConfig.Frame.ShowMissingValueCount

true

Show the count of missing values in the footer

Series display settings

Setting

Default

Description

InteractiveConfig.Series.MaxItems

10

Maximum items to display before truncating

InteractiveConfig.Series.ShowInfo

true

Show the info footer

InteractiveConfig.Series.ShowItemCount

true

Show total item count in the footer

InteractiveConfig.Series.ShowMissingValueCount

true

Show the count of missing values in the footer

Example: compact display

In a notebook cell you might write:

open Deedle.DotNetInteractive

InteractiveConfig.Frame.MaxRows <- 5
InteractiveConfig.Frame.MaxCols <- 4
InteractiveConfig.Frame.ShowColTypes <- false
InteractiveConfig.Frame.ShowMissingValueCount <- false

Resetting to defaults

Call InteractiveConfig.Reset() to restore all settings to their defaults:

InteractiveConfig.Reset()

How it works

Deedle.DotNetInteractive ships an extension.dib file that is loaded automatically by the .NET Interactive kernel. It registers two Formatter instances:

Both produce text/html output. The formatters call the InteractiveFormat method on the frame or series, which returns a string grid that is then wrapped in an HTML <table> with basic CSS styling.

Because registration happens via the standard .NET Interactive extension mechanism, no manual setup code is needed — just reference the NuGet package.

NuGet package information

Package

Description

Deedle

Core library

Deedle.DotNetInteractive

.NET Interactive HTML formatters for frames and series

namespace Deedle
val prices: Frame<int,string>
val frame: columns: ('a * #ISeries<'c>) seq -> Frame<'c,'a> (requires equality and equality)
<summary> A function for constructing data frame from a sequence of name - column pairs. This provides a nicer syntactic sugar for `Frame.ofColumns`. </summary>
<example> To create a simple frame with two columns, you can write: <code> frame [ "A" =&gt; series [ 1 =&gt; 30.0; 2 =&gt; 35.0 ] "B" =&gt; series [ 1 =&gt; 30.0; 3 =&gt; 40.0 ] ] </code></example>
<category>Frame construction</category>
Multiple items
module Series from Deedle
<summary> The `Series` module provides an F#-friendly API for working with data and time series. The API follows the usual design for collection-processing in F#, so the functions work well with the pipelining (<c>|&gt;</c>) operator. For example, given a series with ages, we can use `Series.filterValues` to filter outliers and then `Stats.mean` to calculate the mean: ages |&gt; Series.filterValues (fun v -&gt; v &gt; 0.0 &amp;&amp; v &lt; 120.0) |&gt; Stats.mean The module provides comprehensive set of functions for working with series. The same API is also exposed using C#-friendly extension methods. In C#, the above snippet could be written as: [lang=csharp] ages .Where(kvp =&gt; kvp.Value &gt; 0.0 &amp;&amp; kvp.Value &lt; 120.0) .Mean() For more information about similar frame-manipulation functions, see the `Frame` module. For more information about C#-friendly extensions, see `SeriesExtensions`. The functions in the `Series` module are grouped in a number of categories and documented below. Accessing series data and lookup -------------------------------- Functions in this category provide access to the values in the series. - The term _observation_ is used for a key value pair in the series. - When working with a sorted series, it is possible to perform lookup using keys that are not present in the series - you can specify to search for the previous or next available value using _lookup behavior_. - Functions such as `get` and `getAll` have their counterparts `lookup` and `lookupAll` that let you specify lookup behavior. - For most of the functions that may fail, there is a `try[Foo]` variant that returns `None` instead of failing. - Functions with a name ending with `At` perform lookup based on the absolute integer offset (and ignore the keys of the series) Series transformations ---------------------- Functions in this category perform standard transformations on series including projections, filtering, taking some sub-series of the series, aggregating values using scanning and so on. Projection and filtering functions generally skip over missing values, but there are variants `filterAll` and `mapAll` that let you handle missing values explicitly. Keys can be transformed using `mapKeys`. When you do not need to consider the keys, and only care about values, use `filterValues` and `mapValues` (which is also aliased as the `$` operator). Series supports standard set of folding functions including `reduce` and `fold` (to reduce series values into a single value) as well as the `scan[All]` function, which can be used to fold values of a series into a series of intermeidate folding results. The functions `take[Last]` and `skip[Last]` can be used to take a sub-series of the original source series by skipping a specified number of elements. Note that this does not require an ordered series and it ignores the index - for index-based lookup use slicing, such as `series.[lo .. hi]`, instead. Finally the `shift` function can be used to obtain a series with values shifted by the specified offset. This can be used e.g. to get previous value for each key using `Series.shift 1 ts`. The `diff` function calculates difference from previous value using `ts - (Series.shift offs ts)`. Processing series with exceptions --------------------------------- The functions in this group can be used to write computations over series that may fail. They use the type <c>tryval&lt;'T&gt;</c> which is defined as a discriminated union with two cases: Success containing a value, or Error containing an exception. The function `tryMap` lets you create <c>Series&lt;'K, tryval&lt;'T&gt;&gt;</c> by mapping over values of an original series. You can then extract values using `tryValues`, which throws `AggregateException` if there were any errors. Functions `tryErrors` and `trySuccesses` give series containing only errors and successes. You can fill failed values with a constant using `fillErrorsWith`. Hierarchical index operations ----------------------------- When the key of a series is tuple, the elements of the tuple can be treated as multiple levels of a index. For example <c>Series&lt;'K1 * 'K2, 'V&gt;</c> has two levels with keys of types <c>'K1</c> and <c>'K2</c> respectively. The functions in this cateogry provide a way for aggregating values in the series at one of the levels. For example, given a series `input` indexed by two-element tuple, you can calculate mean for different first-level values as follows: input |&gt; applyLevel fst Stats.mean Note that the `Stats` module provides helpers for typical statistical operations, so the above could be written just as `input |&gt; Stats.levelMean fst`. Grouping, windowing and chunking -------------------------------- This category includes functions that group data from a series in some way. Two key concepts here are _window_ and _chunk_. Window refers to (overlapping) sliding windows over the input series while chunk refers to non-overlapping blocks of the series. The boundary behavior can be specified using the `Boundary` flags. The value `Skip` means that boundaries (incomplete windows or chunks) should be skipped. The value `AtBeginning` and `AtEnding` can be used to define at which side should the boundary be returned (or skipped). For chunking, `AtBeginning ||| Skip` makes sense and it means that the incomplete chunk at the beginning should be skipped (aligning the last chunk with the end). The behavior may be specified in a number of ways (which is reflected in the name): - `dist` - using an absolute distance between the keys - `while` - using a condition on the first and last key - `size` - by specifying the absolute size of the window/chunk The functions ending with `Into` take a function to be applied to the window/chunk. The functions `window`, `windowInto` and `chunk`, `chunkInto` are simplified versions that take a size. There is also `pairwise` function for sliding window of size two. Missing values -------------- This group of functions provides a way of working with missing values in a series. The `dropMissing` function drops all keys for which there are no values in the series. The `withMissingFrom` function lets you copy missing values from another series. The remaining functions provide different mechanism for filling the missing values. * `fillMissingWith` fills missing values with a specified constant * `fillMissingUsing` calls a specified function for every missing value * `fillMissing` and variants propagates values from previous/later keys Sorting and index manipulation ------------------------------ A series that is sorted by keys allows a number of additional operations (such as lookup using the `Lookp.ExactOrSmaller` lookup behavior). However, it is also possible to sort series based on the values - although the functions for manipulation with series do not guarantee that the order will be preserved. To sort series by keys, use `sortByKey`. Other sorting functions let you sort the series using a specified comparer function (`sortWith`), using a projection function (`sortBy`) and using the default comparison (`sort`). In addition, you can also replace the keys of a series with other keys using `indexWith` or with integers using `indexOrdinally`. To pick and reorder series values using to match a list of keys use `realign`. Sampling, resampling and advanced lookup ---------------------------------------- Given a (typically) time series sampling or resampling makes it possible to get time series with representative values at lower or uniform frequency. We use the following terminology: - `lookup` and `sample` functions find values at specified key; if a key is not available, they can look for value associated with the nearest smaller or the nearest greater key. - `resample` function aggregate values values into chunks based on a specified collection of keys (e.g. explicitly provided times), or based on some relation between keys (e.g. date times having the same date). - `resampleUniform` is similar to resampling, but we specify keys by providing functions that generate a uniform sequence of keys (e.g. days), the operation also fills value for days that have no corresponding observations in the input sequence. Joining, merging and zipping ---------------------------- Given two series, there are two ways to combine the values. If the keys in the series are not overlapping (or you want to throw away values from one or the other series), then you can use `merge` or `mergeUsing`. To merge more than 2 series efficiently, use the `mergeAll` function, which has been optimized for large number of series. If you want to align two series, you can use the _zipping_ operation. This aligns two series based on their keys and gives you tuples of values. The default behavior (`zip`) uses outer join and exact matching. For ordered series, you can specify other forms of key lookups (e.g. find the greatest smaller key) using `zipAlign`. functions ending with `Into` are generally easier to use as they call a specified function to turn the tuple (of possibly missing values) into a new value. For more complicated behaviors, it is often convenient to use joins on frames instead of working with series. Create two frames with single columns and then use the join operation. The result will be a frame with two columns (which is easier to use than series of tuples). </summary>
<category>Frame and series operations</category>


--------------------
type Series = static member ofNullables: values: Nullable<'a> seq -> Series<int,'a> (requires default constructor and value type and 'a :> ValueType) static member ofObservations: observations: ('a * 'b) seq -> Series<'a,'b> (requires equality) static member ofOptionalObservations: observations: ('K * 'a option) seq -> Series<'K,'a> (requires equality) static member ofValues: values: 'a seq -> Series<int,'a>

--------------------
type Series<'K,'V (requires equality)> = interface ISeriesFormattable interface IFsiFormattable interface ISeries<'K> new: index: IIndex<'K> * vector: IVector<'V> * vectorBuilder: IVectorBuilder * indexBuilder: IIndexBuilder -> Series<'K,'V> + 3 overloads member After: lowerExclusive: 'K -> Series<'K,'V> member Aggregate: aggregation: Aggregation<'K> * keySelector: Func<DataSegment<Series<'K,'V>>,'TNewKey> * valueSelector: Func<DataSegment<Series<'K,'V>>,OptionalValue<'R>> -> Series<'TNewKey,'R> (requires equality) + 1 overload member AsyncMaterialize: unit -> Async<Series<'K,'V>> member Before: upperExclusive: 'K -> Series<'K,'V> member Between: lowerInclusive: 'K * upperInclusive: 'K -> Series<'K,'V> member Compare: another: Series<'K,'V> -> Series<'K,Diff<'V>> ...
<summary> The type <c>Series&lt;K, V&gt;</c> represents a data series consisting of values `V` indexed by keys `K`. The keys of a series may or may not be ordered </summary>
<category>Core frame and series types</category>


--------------------
new: pairs: System.Collections.Generic.KeyValuePair<'K,'V> seq -> Series<'K,'V>
new: keys: 'K seq * values: 'V seq -> Series<'K,'V>
new: keys: 'K array * values: 'V array -> Series<'K,'V>
new: index: Indices.IIndex<'K> * vector: IVector<'V> * vectorBuilder: Vectors.IVectorBuilder * indexBuilder: Indices.IIndexBuilder -> Series<'K,'V>
static member Series.ofValues: values: 'a seq -> Series<int,'a>
val vols: Series<int,int>
namespace Deedle.DotNetInteractive
module InteractiveConfig from Deedle.DotNetInteractive
module Frame from Deedle.DotNetInteractive.InteractiveConfig
val mutable MaxRows: int
val mutable MaxCols: int
val mutable ShowColTypes: bool
val mutable ShowMissingValueCount: bool
val Reset: unit -> unit

Type something to start searching.