Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does GenericChart.toChartHTML work in version 4.0? #373

Closed
nhirschey opened this issue Mar 8, 2023 · 7 comments
Closed

Does GenericChart.toChartHTML work in version 4.0? #373

nhirschey opened this issue Mar 8, 2023 · 7 comments

Comments

@nhirschey
Copy link
Contributor

Description

I cannot get GenericChart.toChartHTML to render in fsdocs generated pages with Plotly.NET 4.0. I think it's because 4.0 is not producing the fsharpPlotlyRequire javascript in the output.

Repro steps

If I do this in a blank docs folder index.fsx I get a nice plot produced in the html

#r "nuget: Plotly.NET, 3.*"

open Plotly.NET

Chart.Line([1,2; 3, 4])
|> GenericChart.toChartHTML
(***include-it-raw***)

However, with 4.0 no chart gets displayed:
image

Comparing the html output vs. 3.0, I think 4.0 missing the fsharpPlotlyRequire ... code?

see that in 4.0 there is no fsharpPlotlyRequire code before the data declaration in the output:

#r "nuget: Plotly.NET, 4.*"

open Plotly.NET

Chart.Line([1,2; 3, 4])
|> GenericChart.toChartHTML
> val it: string =
  "<div><div id="0acfb4b0-43b3-421f-adaf-849ee352d955"><!-- Plotly chart will be drawn inside this DIV --></div><script type="text/javascript">var renderPlotly_0acfb4b043b3421fadaf849ee352d955 = function() {
    var data = [{"type":"scatter","mode":"lines","x":[1,3],"y":[2,4],"marker":{},"line":{}}]

There is an fsharpPlotlyRequire function in the 3.0 output:

#r "nuget: Plotly.NET, 3.*"

open Plotly.NET

Chart.Line([1,2; 3, 4])
|> GenericChart.toChartHTML
> val it: string =
  "<div id="5347e62f-9fc9-4c6e-88f1-c3d40ad1f5d8"><!-- Plotly chart will be drawn inside this DIV --></div>
<script type="text/javascript">

            var renderPlotly_5347e62f9fc94c6e88f1c3d40ad1f5d8 = function() {
            var fsharpPlotlyRequire = requirejs.config({context:'fsharp-plotly',paths:{plotly:'https://cdn.plot.ly/plotly-2.6.3.min'}}) || require;
            fsharpPlotlyRequire(['plotly'], function(Plotly) {

            var data = [{"type":"scatter","mode":"lines","x":[1,3],"y":[2,4],"marker":{},"line":{}}];

Related information

  • Operating system: Windows
  • fsdocs: tried 16.1.1 and 17.3.0
  • .NET Runtime, CoreCLR or Mono Version: dotnet --version = 7.0.100
@nhirschey
Copy link
Contributor Author

The cause seems to be that toChartHTML calls toChartHTMLNodes, and toChartHTMLNodes calls getPlotlyReference

displayOpts |> DisplayOptions.getPlotlyReference

getPlotlyReference uses PlotlyJSReference.NoReference as the default.

displayOpts |> DisplayOptions.tryGetPlotlyReference |> Option.defaultValue (PlotlyJSReference.NoReference)

I understand why you'd want that as the default given that you reference plotly explicitly in your _template.html for fsdocs. Was this an intentional global change for all users?

@kMutagene
Copy link
Collaborator

kMutagene commented Mar 9, 2023

Was this an intentional global change for all users?

Changing the way the html output is rendered in general was intentional, especially getting rid of the require code that spams the head tags of pages with references once you have more than one chart per page. The previous template used both cdn and require at once, which was unnecessary.

However, the default plotly reference should be always set to CDN here:

let mutable DefaultDisplayOptions =
DisplayOptions.init (
PlotlyJSReference = CDN $"https://cdn.plot.ly/plotly-{Globals.PLOTLYJS_VERSION}.min.js",
AdditionalHeadTags =
[
title [] [ str "Plotly.NET Datavisualization" ]
meta [ _charset "UTF-8" ]
meta
[
_name "description"
_content "A plotly.js graph generated with Plotly.NET"
]
link
[
_id "favicon"
_rel "shortcut icon"
_type "image/png"
_href $"data:image/png;base64,{Globals.LOGO_BASE64}"
]
]
)

Although that still will not fix your issue, as the cdn is referenced in the document head, which is only present in toEmbeddedHTML.

You can either use a global reference in the template header or change the global default DisplayOptions to use require again. For fsdocs, i'd recommend the former, as you load the reference only once across the page.

@kMutagene
Copy link
Collaborator

@nhirschey do the proposed methods work for you?

@nhirschey
Copy link
Contributor Author

nhirschey commented Mar 17, 2023

Hi @kMutagene, thanks for the context.

fsdocs, i'd recommend [global reference in the template header], as you load the reference only once across the page.

I prefer using the default fsdocs template when possible; creating a custom _template.html just to use Plotly.NET adds some friction.

  1. Is there a simpler way to add the CDN script reference to an fsdocs page than what I have below? If not, would it make sense to add something like DisplayOptions.getPlotlyReferenceCDNScriptString() so that adding Plotly.NET CDN to an fsdocs page becomes a simple one-liner?

    #r "nuget: Plotly.NET, 4.*"
    
    open Plotly.NET
    
    (***condition: prepare***)
    let (PlotlyJSReference.CDN cdn) = DisplayOptions.getPlotlyReference(DisplayOptions.initCDNOnly())
    $"<script src='{cdn}'></script>"
    (***include-it-raw***)
    
    Chart.Line([1,2; 3, 4; 5,6])
    |> GenericChart.toChartHTML
    (***include-it-raw***)
  2. I guess another simple alternative is to just use GenericChart.toEmbeddedHTML for at least the first chart on a page. Once toEmbeddHTML is called the page is referencing the CDN, so later toChartHTML will load correctly as far as I can tell from my testing.

Given option 2. using toEmbeddedHTML, it's probably not worth adding something like DisplayOptions.getPlotlyReferenceCDNScriptString().

@nhirschey
Copy link
Contributor Author

nhirschey commented Mar 17, 2023

I guess I'll close this, with the suggestions being either:

  1. To use GenericChart.toChartHTML with fsdocs, create a custom _template.html file that explicitly references the CDN.
  2. Or, use GenericChart.toEmbeddedHTML everywhere you used to use GenericChart.toChartHTML; it'll just work and be strictly better than v3.0 of Plotly.NET.
  3. Or, use GenericChart.toEmbeddedHTML for the first chart on a page, then GenericChart.toChartHTML for any subsequent charts on the same page. This will replicate the efficiency of using a custom _template.html file that has an explicit CDN reference.

@kMutagene
Copy link
Collaborator

I think we can try another solution:

One suggestion could be doing this in the first rendered document.

Plotly.NET.Defaults.DefaultDisplayOptions <-
Plotly.NET.DisplayOptions.init (PlotlyJSReference = Plotly.NET.PlotlyJSReference.NoReference)

Plotly.NET.Defaults.DefaultDisplayOptions <-
    Plotly.NET.DisplayOptions.init (PlotlyJSReference = Require "https://cdn.plot.ly/plotly-2.18.2.min.js")

(or this if you want to preserve the other defaults):

Plotly.NET.Defaults.DefaultDisplayOptions <-
    Plotly.NET.Defaults.DefaultDisplayOptions
    |> DisplayOptions.setPlotlyReference(Require "https://cdn.plot.ly/plotly-2.18.2.min.js")

Global defaults should persist across fsdocs files IIRC, otherwise you can do it in every file just to be safe, that's how i do it, but the other way around to make sure we use NoReference everywhere:

This will add the require part to the scripts, and is also how charts are rendered in Plotly.NET.IOnteractive.

image

@kMutagene kMutagene reopened this Mar 17, 2023
@nhirschey
Copy link
Contributor Author

Plotly.NET.Defaults.DefaultDisplayOptions <-
    Plotly.NET.Defaults.DefaultDisplayOptions
|> DisplayOptions.setPlotlyReference(Require "https://cdn.plot.ly/plotly-2.18.2.min.js")`

Ok, that's a good option too. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants