Giter Site home page Giter Site logo

plotly / dash.net Goto Github PK

View Code? Open in Web Editor NEW
67.0 15.0 14.0 3.68 MB

F# interface to Dash- the most downloaded framework for building ML & data science web apps

Home Page: https://plotly.github.io/Dash.NET

License: MIT License

Batchfile 0.01% Shell 0.01% F# 96.20% Dockerfile 0.06% CSS 0.01% C# 3.72%

dash.net's Introduction

Dash.NET is a .NET interface to Dash - the most downloaded framework for building ML & data science web apps - written in F#. Built on top of Plotly.NET, React and asp.netcore (via Giraffe), Dash.NET ties modern UI elements like dropdowns, sliders, and graphs directly to your analytical .NET code.

This library is under heavy development. Things might break. However, Dash.NET has a stable core and has already been used for non trivial applications (example1, example2). The current development goal is to implement all targets set in the beta roadmap, where you can also see a summary of the state of the project.

The documentation is WIP as well.

Installation

Get the latest preview package via nuget:

Use the dotnet new template:

dotnet new -i Dash.NET.Template::*

(watch out, this template might not use the latest Dash.NET package, take a look at the referenced version and update if needed )

Documentation

The landing page of our docs contains everything to get you started fast, check it out ๐Ÿ“– here

Development

Note: The release and prerelease build targets assume that there is a NUGET_KEY environment variable that contains a valid Nuget.org API key.

build

Check the build.fsx file to take a look at the build targets. Here are some examples:

# Windows

# Build only
./build.cmd

# Full release buildchain: build, test, pack, build the docs, push a git tag, publsih thze nuget package, release the docs
./build.cmd -t release

# The same for prerelease versions:
./build.cmd -t prerelease


# Linux/mac

# Build only
build.sh

# Full release buildchain: build, test, pack, build the docs, push a git tag, publsih thze nuget package, release the docs
build.sh -t release

# The same for prerelease versions:
build.sh -t prerelease

docs

The docs are contained in .fsx and .md files in the docs folder. To develop docs on a local server with hot reload, run the following in the root of the project:

# Windows
./build.cmd -t watchdocs

# Linux/mac
./build.sh -t watchdocs

release

Library license

The library is available under the MIT license.

dash.net's People

Contributors

ademar avatar jackparmer avatar jannesiera avatar kaashyapan avatar kmutagene avatar mr-m-coetzee avatar mrjuanblack avatar plt-joey avatar rpkyle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dash.net's Issues

Unify usage of html DSLs across the projects

Currently, 3 types of html DSLs are used:

  • Giraffe.ViewEngine
  • Feliz.Engine
  • Suave.Html

As Feliz.Engine is designed to be plucked in any kind of project, it should be used across all projects.

On the same note, Feliz.Engine should be used as nuget package instead of using the source code directly.

Consider computation expressions for callbacks

This can either exist in parallel to or instead of the currently used constructors.

so for

  Callback(
      Inputs = [
          ...
      ],
      Output = ...
      State = [...],
      HandlerFunction = ...
      )
  )

we could have

callback {
	inputs [...]
	state [...]
	output ...
	handlerFunction ...
}

with the benefit of keyword-style named parameters instead of constructor arguments

Running Dash.NET from scripts

With Giraffe - and therefore asp.netcore - Dash.NET has to be an application (at least to my knowledge we can not use these libraries in a scripting environment). It might be worth to investigate adding support for a lightweight server such as suave to enable Dash.NET apps from within a single script file

Roadmap and discussion for beta release

TL;DR - To-Do list for the beta release:

General:

  • improve type handling for invokeDynamic, also regarding function argument count (78439fb)
  • full support for
    • all core and html components
    • all html components (should be done by #15, but needs tests)
  • support for multi callbacks (callbacks with multiple outputs): #6

Backend:

  • Component registry
  • inject custom css and javascript sources: #5
  • Improve handling of the Callback type #10

Frontend:

  • Auto-generate components (semi-auto generation is in place)
  • PropTypes mapping for auto generate scripts (can be done via #8)
  • Inline CSS Style DSL

Nice to have:

  • full mapping of the dash config
  • Error handling
  • implement hot reload for improved dev experience
  • Server-side validation of objects (is there a JSON schema?)

17/06/2021 - Update

  • C# tests, templates, and samples

9/27/2020 - Roadmap and discussion for a Dash.NET beta release

Now that this project is through the proof-of-concept stage (you can check a deployed version of the POC app on heroku here and install a dotnet template for Dash.NET), it is time to open up the development process for external input and maybe/hopefully contributions. For this purpose, i want to summarize the state of the project and highlight issues to overcome for moving it forward. Most of this may be subject to change over time, and i may have missed critical issues, so please feel free to contribute to this issue.

General

Dash.NET is a port of the open source dash framework by plotly, the most downloaded framework for building ML & data science web apps. It should target .NET core only, therefore running on all platforms that support the .NET core environment.

Generally, a dash app hosts a single page react application, containing the DashRenderer and several endpoints that serve JSON which determine the app layout rendered and the callbacks processed by it.

  • Familiar look and feel

    When possible, naming/syntax/types should be as close to the original libraries as possible.

  • Language support

    Dash.NET is written in F#, but a general aim of the project to be easily usable from both F# and C#, just as Plotly.NET, as well as multiple styles of creating layouts (e.g. the fable react dsl way for F#, as well as providing classes with constructors for components to consume from C#)

  • Type safety

    A general problem that showed up pretty early in the design process of this library is that all versions of dash (python/r/julia) are designed for dynamically typed languages.

    This is solved by types inheriting from DynamicObject (this is a tried and tested - as long as correctly encapsuled - way to generate objects with dynamic types to serialize correct JSON in Plotly.NET), and an internal invokeDynamic function to handle callbacks (which are basically functions with arbitrary argument count). We are currently working on making this function more resilient against runtime errors (as both rely on reflection).

Backend:

Dash.Net's backend is built on Giraffe, which itself is built on ASP.NET Core.

  • Full Dash config mapping

    Not all config options for dash apps are currently usable from Dash.NET. All options can be found here

  • Server-side validation of objects

    Not sure if this is needed in a type safe environment, but all other dash versions do it.

  • Component registry

    serve javascript for components based on the referenced component libraries, e.g. only serve html component js when the library is opened or referenced in the project.

  • inject custom css and javascript sources

    Adding the option to add custom css and scripts in the header of the dash app

  • Error handling

    Implement a type model for dash specific errors, and handle them in a meaningful way (e.g. when a component is invalid, track the validation error and maybe only serve the valid components)

  • Hot reload

    Should be straight forward to implement like this

Frontend:

The front end in dash applications is rendered by the DashRenderer from serialized components provided by the _dash-layout endpoint. This is the reason why this is not a Fable based project.
A DSL for dash components and html components has been designed with both C# and F# in mind.

  • Auto generate scripts for components

    either as a python script or via a F# metaprogramming tool or generation script that can be called in the dash build pipeline. A really basic script for html component generation is already in place.

  • PropTypes mapping for auto generate scripts

    the prop types of react components, as well as everything that is of type object need mapping to F# types for component auto generation to work.

  • Inline CSS Style DSL

    A DSL for inline CSS styles must be in place for them to be usable. Seems like the DashRenderer expects these to be key value pairs, which should be possible to be generated analogously to the other types/classes via DynamicObject.

Make Callbacks easier to use and create

Using the Callback constructor is kinda tedious, especially for large functions. There are multiple reasons for this, for example the convoluted way of creating Dependency (via CallbackOutput.create or CallbackInput.create). Here are some steps that i identified to help with this:

  • Use multiple overloads, e.g. for callbacks that only take one input, one output, and multiple of both (66ba10d)
  • Add custom operators for dependency (CallbackOutput/Input) creation (a75eac6)
  • Add component property DSL for autocompletion of component properties when defining dependencies (#8)
  • Add a callback computation expression (#9)

Adapt Feliz style DSL for Dash components

While the core HTML components use the new Feliz-style DSL with Feliz.Engine, other Dash components still use the double list style Component.component [<props>] [<children>].

Unifying the feel of components would be awesome. We can most likely tackle this as #16 progresses.

Small fixes needed to tutorial part 2

I found some issues with the documentation that might be a stumbling block for a F# beginner. This might not be the right forum to contribute to docs, but I start here :)

Fixes can be seen here, tested with .Net 5 and 6
https://gist.github.com/magnushammar/50ca4adf881f8506ee43db80144e5b1e/revisions

Edit: Missed that fst and snd needed to swap place for the chart to render as shown.
https://gist.github.com/magnushammar/50ca4adf881f8506ee43db80144e5b1e#file-app-fsx-L25

Support multi callbacks

Callbacks should be a DU like this:

type Callback
| SingleCallback ...
| MultiCallback ...

this will make serialization harder but making multiple outputs possible is important.

  • the 'Output' property of the callback (which is basically its id) needs to be constructed from the multi output objects
  • this id should then automatically be used to register the callback, abstracting the argument away from the registerCallback function.

Use the same serialization configs for all backend implementations

Raising this issue now as #24 might be merged with the problem still existent.

Copying my comment from that PR:

I copied the code from the Dash.NET.Dev app into the suave script to check if callbacks are working. They do, but the dropdown component did not render. The problem lies here:

type DropdownOption =
{
Label:IConvertible
Value:IConvertible
Disabled:bool
Title:string
}
static member create label value disabled title = {Label=label; Value=value; Disabled=disabled; Title=title}

While these properties are uppercase in that record type, the dash renderer expect the Json properties to be lowercase:

image

This problem does not appear when using giraffe (which per default is also using Newtonsoft.Json, that's why I'm confused now). It is fixable by adding JsonPropertyAttributes to the record types, but i think it should be investigated why the json configs are different

Let's make sure to file an issue and use the exact same Json serializer options for both apps, or this will be a nightmare to maintain, especially if there might be more backend implementations in the future

Optional component record fields

Current component record implementations does not implement optional fields as optional.

  • This force long winded code.
  • Puts it on the user to specify a default value for optional fields.
  • Is inconsistent with implementations for Python, Julia, R and MATLAB (as far as I can tell).
  • Not clear from the code which fields are optional.

Current state

Taking DropdownOption as an example.

The fields are described as:

  • Label: string | number (required)
  • Value: string | number (required)
  • Disabled: boolean (optional)
  • Title: string (optional)

But is implemented as:

type DropdownOption = 
    {
        Label:IConvertible
        Value:IConvertible
        Disabled:bool    // Optional - but must provide a value
        Title:string    // Optional - but must provide a value
    }
    // Both optional arguments require a value
    static member create label value disabled title = {Label=label; Value=value; Disabled=disabled; Title=title}

Usage:

Dropdown.Attr.options [
    // Forced to provide a default value
    DropdownOption.create "Population" "pop" false "Population"
    DropdownOption.create "Life Expectancy" "lifeExp" false "Life Expectancy"
    DropdownOption.create "GDP per Capita" "gdpPercap" false "GDP per Capita"
]

Proposal

  1. Make optional fields optional.
type DropdownOption = 
    {
        Label: IConvertible
        Value: IConvertible
        Disabled: bool option    // Clearly optional
        Title: string option    // Clearly optional
    }
  1. create method making use of tuples with optional arguments (also allows overloading where curry does not).
static member create (label, value, ?disabled, ?title) = { Label=label; Value=value; Disabled=disabled; Title=title }

Usage:

Dropdown.Attr.options [
    DropdownOption.create ("Population", "pop")
    DropdownOption.create ("Life Expectancy", "lifeExp", title = "My Life Expectancy")
    DropdownOption.create ("GDP per Capita", "gdpPercap", true)
]

Example convert method:

static member convert this =
    box {|
        label = this.Label
        value = this.Value
        disabled = match this.Disabled with Some isDisabled -> box isDisabled | None -> null
        title = match this.Title with Some title -> box title | None -> null
    |}

Namespace refactoring

  • The HTML DSL is too verbose. Instead of Button.button users should be able to just use button (it is now Html.button)
  • Change Callback argument order to mirror python behaviour
  • use a single overloaded method for creating callbacks

Add DSL for Component Properties

Should be straightforward to implement a union case for the most used properties in callbacks, such as children or value. The rest can be captured by Custom:

type ComponentProperty =
| Children
| Value
| Custom of string

static member convert =
	//do the mapping to the correct string version here 

Giraffe 5 ?

Latest version of Giraffe. (v5) has breaking changes.
It supports minimum .net 5.

Most libraries in the dotnet world are going in this direction.

Do you want to consider dropping support for netstandard and going all in on .net 5 ?

Dash core component Javascript reference has disappeared

One of the javascript references has gone offline breaking all our applications and examples.

https://unpkg.com/[email protected]/dash_core_components/dash_core_components.min.js

Marius noted that the not minified version is still there.

https://unpkg.com/[email protected]/dash_core_components/dash_core_components.js

Shall we update this reference? Or go to the bottom of it why it was removed?

Or shall we start packing them with our components so that they do not rely in online resources and apps could actually be used offline ?

Use direct DynamicObj dependency in component generation

Currently, DynObj is used as transient dependency of Plotly.NET.

I added a direct dependency of the core project, which will be merged soon. This also means that component auto generation needs to

  • add a DynamicObj dependency to the component project file
  • open DynamicObj on top of the library file

I did this by hand now in #33, but those changes are overridden in the next auto generation cycle.

Unify object generation and serialization approaches

The overall strategy for creating objects to serialize and serve via the dash app endpoints should be the same everywhere:

  • When it is a object with no optional fields:

    -> Record type with [<JsonProperty>] attribute indicating the correct json property name

  • When it is an object with optional fields:

    -> class inheriting from DynamicObj using the init(and optionally style/applyMembers pattern, see #29)

  • When it is an enum:

    DU with the following static members: toString (which converts to the correct string for the js enum), and convert, which boxes the result of toString see for example here:

    type InputType =
    | Text
    | Number
    | Password
    | Email
    | Range
    | Search
    | Tel
    | Url
    | Hidden
    static member toString = function
    | Text -> "text"
    | Number -> "number"
    | Password -> "password"
    | Email -> "email"
    | Range -> "range"
    | Search -> "search"
    | Tel -> "tel"
    | Url -> "url"
    | Hidden -> "hidden"
    static member convert = InputType.toString >> box

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.