{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[this doc on github](https://github.com/dotnet/interactive/tree/master/samples/notebooks/csharp/Docs)\n", "\n", "# Charts with XPlot\n", "Charts can be rendered using [Xplot.Plotly](https://fslab.org/XPlot/). \n", "We will cover some example on how to use XPlot in a notebook with the .NET Kernel.\n", "\n", "First, import the `XPlot.Plotly` namespace:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "#i \"nuget:https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json\" \r\n", "#i \"nuget:https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json\" \r\n", " \r\n", "#r \"nuget: XPlot.Plotly.Interactive, 4.0.2\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "using XPlot.Plotly;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The next cell sets up some helpers for data generation." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "var generator = new Random();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Rendering Scatter plots\n", "One of the most commonly used type of chart to explore data set. Use the type `Scatter`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "var openSeries = new Scatter\n", "{\n", " name = \"Open\",\n", " x = new[] {1, 2, 3, 4},\n", " y = new[] {10, 15, 13, 17}\n", "};\n", "\n", "var closeSeries = new Scatter\n", "{\n", " name = \"Close\",\n", " x = new[] { 2,3,4,5 },\n", " y = new[] { 16, 5, 11, 9 }\n", "};\n", "\n", "var chart = Chart.Plot(new[] {openSeries, closeSeries});\n", "chart.WithTitle(\"Open vs Close\");\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's change it to be markers style, so more like a scatter plot." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "openSeries.mode = \"markers\";\n", "closeSeries.mode = \"markers\";\n", "chart = Chart.Plot(new [] {openSeries, closeSeries});\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Scatter` can also produce polar charts by setting the radial property `r` and angular proeprty `t`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "openSeries = new Scatter\n", "{\n", " name = \"Open\",\n", " r = new[] {1, 2, 3, 4},\n", " t = new[] {45, 100, 150, 290}\n", "};\n", "\n", "closeSeries = new Scatter\n", "{\n", " name = \"Close\",\n", " r = new[] { 2,3,4,5 },\n", " t = new[] { 16, 45, 118, 90 }\n", "};\n", "\n", "chart = Chart.Plot(new[] {openSeries, closeSeries});\n", "chart.WithLayout(new Layout.Layout\n", " {\n", " orientation = -90\n", " });\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Large scatter plots and performance\n", "It is not uncommong to have scatter plots with a large dataset, it is a common scenario at the beginning of a data exploration process. Using the default `svg` based rendering will create performace issues as the dom will become very large.\n", "We can then use `web-gl` support to address the problem." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "#!time\n", "var series = new Scattergl[10];\n", "\n", "for(var i = 0; i < series.Length; i++){\n", " series[i] = new Scattergl\n", " {\n", " name = $\"Series {i}\",\n", " mode = \"markers\",\n", " x = Enumerable.Range(0,100000).Select(_ => generator.Next(-200, 200) * 1000 * generator.Next(-2000, 2000)),\n", " y = Enumerable.Range(0,100000).Select(_ => generator.Next(-200, 200) * 1000 * generator.Next(-2000, 2000))\n", " };\n", "}\n", "\n", "chart = Chart.Plot(series);\n", "chart.WithTitle(\"Large Dataset\");\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Can provide custom marker `colour`, `size` and `colorscale` to display even more information to the user." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "for(var i = 0; i < series.Length; i++){\n", " var sizes = Enumerable.Range(0,100).Select(_ => (generator.NextDouble() < 0.75) ? generator.Next(1, 5) : generator.Next(10, 15)).ToArray();\n", " var temperatures = sizes.Select(t => (t * 10) - 100);\n", " \n", " series[i].x = Enumerable.Range(0,100).Select(_ => generator.Next(-200, 200) * 1000 * generator.Next(-2000, 2000));\n", " series[i].y = Enumerable.Range(0,100).Select(_ => generator.Next(-200, 200) * 1000 * generator.Next(-2000, 2000));\n", " series[i].marker = new Marker{ \n", " size = sizes,\n", " color = temperatures,\n", " colorscale = \"hot\" \n", " };\n", "}\n", "\n", "chart = Chart.Plot(series);\n", "chart.WithTitle(\"Size and Colour\");\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Plotly pvoides some additional `color scales` to use." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "for(var i = 0; i < series.Length; i++) {\n", " series[i].marker.colorscale = \"Viridis\";\n", "}\n", "\n", "chart = Chart.Plot(series);\n", "chart.WithTitle(\"Viridis scale\");\n", "display(chart);\n", "\n", "for(var i = 0; i < series.Length; i++) {\n", " series[i].marker.colorscale = \"Hot\";\n", "}\n", "\n", "chart = Chart.Plot(series);\n", "chart.WithTitle(\"Hot scale\");\n", "display(chart);\n", "\n", "for(var i = 0; i < series.Length; i++) {\n", " series[i].marker.colorscale = \"Jet\";\n", "}\n", "\n", "chart = Chart.Plot(series);\n", "chart.WithTitle(\"Jet scale\");\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Rendering Histograms\n", "Let's have a look at using histograms, the next cell sets up some generators." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "var count = 20;\n", "var dates = Enumerable.Range(0, count).Select(i => DateTime.Now.AddMinutes(generator.Next(i, i + 30))).ToArray();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's define histogram traces:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "var openByTime = new Histogram\n", "{\n", " x = dates,\n", " y = Enumerable.Range(0, count).Select(_ => generator.Next(0,200)),\n", " name = \"Open\"\n", "};\n", "\n", "var closeByTime = new Histogram\n", "{\n", " x = dates,\n", " y = Enumerable.Range(0, count).Select(_ => generator.Next(0, 200)),\n", " name = \"Close\"\n", "};\n", "chart = Chart.Plot(new [] {openByTime, closeByTime});\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Histogram generator will automatically count the number of items per bin. \n", "\n", "Setting `histfunc` to `\"sum\"` we can now add up all the values contained in each bin.\n", "Note that we are creatng bin using the `x` data point and we are using bydefault autobinx" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "openByTime.histfunc = \"sum\";;\n", "closeByTime.histfunc = \"sum\";\n", "chart = Chart.Plot(new [] {openByTime, closeByTime});\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Area chart and Polar Area chart" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By populating hte property `fill` of a `Scatter` trace the chart will render as area chart.\n", "\n", "Here is set to `\"tozeroy\"` which will create a fill zone underneath the line reachin to the 0 of the y axis." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "openSeries = new Scatter\n", "{\n", " name = \"Open\",\n", " x = new[] {1, 2, 3, 4},\n", " y = new[] {10, 15, 13, 17},\n", " fill = \"tozeroy\",\n", " mode= \"lines\"\n", "};\n", "\n", "closeSeries = new Scatter\n", "{\n", " name = \"Close\",\n", " x = new[] {1, 2, 3, 4},\n", " y = new[] {3, 5, 11, 9},\n", " fill = \"tozeroy\",\n", " mode= \"lines\"\n", "};\n", "\n", "chart = Chart.Plot(new[] {openSeries, closeSeries});\n", "chart.WithTitle(\"Open vs Close\");\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With one `fill` set to `\"tonexty\"` the cahrt will fill the aread between traces." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "openSeries.fill = null;\n", "closeSeries.fill = \"tonexty\";\n", "\n", "chart = Chart.Plot(new[] {openSeries, closeSeries});\n", "chart.WithTitle(\"Open vs Close\");\n", "display(chart);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `Area` traces we can generate radial area chart. In this example we are using cardinal points to xpress angular values.\n", "The array `{\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"}` will be autoimatically translated to angular values." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [], "source": [ "var areaTrace1 =\n", " new Area\n", " {\n", " r = new[] {77.5, 72.5, 70.0, 45.0, 22.5, 42.5, 40.0, 62.5},\n", " t = new[] {\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"},\n", " name = \"11-14 m/s\",\n", " marker = new Marker\n", " {\n", " color = \"rgb(106,81,163)\"\n", " }\n", " };\n", "\n", "var areaTrace2 =\n", " new Area\n", " {\n", " r = new [] {57.49999999999999, 50.0, 45.0, 35.0, 20.0, 22.5, 37.5, 55.00000000000001},\n", " t = new [] {\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"},\n", " name = \"8-11 m/s\",\n", " marker = new Marker{\n", " color = \"rgb(158,154,200)\"\n", " }\n", " };\n", "\n", "var areaTrace3 =\n", " new Area\n", " {\n", " r = new [] {40.0, 30.0, 30.0, 35.0, 7.5, 7.5, 32.5, 40.0},\n", " t = new [] {\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"},\n", " name = \"5-8 m/s\",\n", " marker = new Marker{\n", " color = \"rgb(203,201,226)\"\n", " }\n", " };\n", "\n", "var areaTrace4 =\n", " new Area\n", " {\n", " r = new [] {20.0, 7.5, 15.0, 22.5, 2.5, 2.5, 12.5, 22.5},\n", " t = new [] {\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"},\n", " name = \"< 5 m/s\",\n", " marker = new Marker{\n", " color = \"rgb(242,240,247)\"\n", " }\n", " };\n", "\n", "var areaLayout = new Layout.Layout\n", "{\n", " title = \"Wind Speed Distribution in Laurel, NE\",\n", " font = new Font\n", " {\n", " size = 16\n", " },\n", " legend = new Legend\n", " {\n", " font = new Font\n", " {\n", " size = 16\n", " }\n", " },\n", " radialaxis = new Radialaxis\n", " {\n", " ticksuffix = \"%\"\n", "\n", " },\n", " orientation = 270\n", "};\n", "\n", "chart = Chart.Plot(new [] {areaTrace1, areaTrace2, areaTrace3, areaTrace4});\n", "chart.WithLayout(areaLayout);\n", "display(chart);" ] } ], "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 }