src/Microsoft.ML.DotNet.Interactive.Extensions/DecisionTreeDataFormatting.cs
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.IO; using System.Linq; using System.Text; using HtmlAgilityPack; using System.Text.Json; namespace Microsoft.ML.DotNet.Interactive { public static class DecisionTreeDataFormatting { private static readonly JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true }; internal static string GenerateTreeView(DecisionTreeData tree) { var newHtmlDocument = new HtmlDocument(); var renderingId = $"a{Guid.NewGuid()}"; newHtmlDocument.DocumentNode.ChildNodes.Add(HtmlNode.CreateNode($"<svg id=\"{renderingId}\"></svg>")); newHtmlDocument.DocumentNode.ChildNodes.Add(GetRenderingScript()); newHtmlDocument.DocumentNode.ChildNodes.Add(GetScriptNodeWithRequire(renderingId, tree)); return newHtmlDocument.DocumentNode.WriteContentTo(); } private static HtmlNode GetRenderingScript() { var newScript = new StringBuilder(); newScript.AppendLine("<script type=\"text/javascript\">"); var assembly = typeof(DecisionTreeDataFormatting).Assembly; var resourceName = assembly.GetManifestResourceNames().First(n => n.EndsWith("RegressionTree.js")); var resourceStream = assembly.GetManifestResourceStream(resourceName); using (var reader = new StreamReader(resourceStream, Encoding.UTF8)) { newScript.AppendLine(reader.ReadToEnd()); } newScript.AppendLine("</script>"); return HtmlNode.CreateNode(newScript.ToString()); } private static HtmlNode GetScriptNodeWithRequire(string renderingId, DecisionTreeData tree) { var newScript = new StringBuilder(); newScript.AppendLine("<script type=\"text/javascript\">"); newScript.AppendLine(@" var dotnet_regressiontree_renderTree = function() { var mlNetRequire = requirejs.config({context:'microsoft.ml-1.3.1',paths:{d3:'https://d3js.org/d3.v5.min'}}); mlNetRequire(['d3'], function(d3) {"); newScript.AppendLine(); newScript.Append($"var treeData = {GenerateData(tree)};"); newScript.AppendLine(); newScript.Append($@"dnRegressionTree.render(d3.select(""#{renderingId}""), treeData, d3);"); newScript.AppendLine(); newScript.AppendLine(@"}); }; if ((typeof(requirejs) !== typeof(Function)) || (typeof(requirejs.config) !== typeof(Function))) { var script = document.createElement(""script""); script.setAttribute(""src"", ""https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js""); script.onload = function(){ dotnet_regressiontree_renderTree(); }; document.getElementsByTagName(""head"")[0].appendChild(script); } else { dotnet_regressiontree_renderTree(); }"); newScript.AppendLine("</script>"); return HtmlNode.CreateNode(newScript.ToString()); } private static string GenerateData(DecisionTreeData tree) { return JsonSerializer.Serialize(tree.Root, options: JsonSerializerOptions); } } } |