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

Replace Pluto notebooks with Quarto files #279

Draft
wants to merge 25 commits into
base: main
Choose a base branch
from
Draft

Replace Pluto notebooks with Quarto files #279

wants to merge 25 commits into from

Conversation

sethaxen
Copy link
Member

@sethaxen sethaxen commented Jul 5, 2023

Loosely follows https://forem.julialang.org/kellertuer/render-quarto-tutorials-in-documenterjl-with-github-actions-3fo.

This has the benefit that the markdown part of the examples is parsed using Documenter, so we can reference docstrings in the same docs build. It has the downside that Julia's markdown parses does not parse the HTML representation of InferenceData, which is probably a dealbreaker for this PR unless we can find a workaround.

@kellertuer
Copy link

Can you pin point me to the cell that provides the issue?

Variant 1: If possible one could write a show method that outputs markdown instead (or an additional show method for that)?

Variant 2, either in the corresponding code block or a new (hidden) one (you can hide quarto code blocks in rendering):

````{julia}
"```rawhtml\n$(show(...[yourshowcode]...)\n```"
````

this way the output of this quarto code block is a raw html block for documenter.

Though I would personally prefer something like variant 1 if possible.

@kellertuer
Copy link

I tried to look at this locally, but could not get it to work.

  1. I tried to instantiate the docs/ environment and that does not work directly, since it requires version 0.9 but only 0.8.2 Is registered. This I could solve by putting Arviz into development mode on the parent directory.

  2. using Arviz errors for me with

julia> using ArviZ
[ Info: Precompiling ArviZ [131c737c-5715-5e2e-ad31-c244f01c1dc7]
┌ Warning: ArviZ.jl only officially supports arviz version 0.13.0 or greater but found version 0.11.2.
└ @ ArviZ ~/Repositories/Julia/ArviZ.jl/src/setup.jl:15
ERROR: LoadError: KeyError: key :plot_ecdf not found
Stacktrace:
  [1] __getproperty
    @ ~/.julia/packages/PyCall/ilqDX/src/PyCall.jl:313 [inlined]
  [2] getproperty
    @ ~/.julia/packages/PyCall/ilqDX/src/PyCall.jl:318 [inlined]
  [3] forwarddoc(f::Symbol)
    @ ArviZ ~/Repositories/Julia/ArviZ.jl/src/utils.jl:58
  [4] var"@forwardplotfun"(__source__::LineNumberNode, __module__::Module, f::Any, forward_docs::Any)
    @ ArviZ ~/Repositories/Julia/ArviZ.jl/src/utils.jl:120
  [5] var"@forwardplotfun"(__source__::LineNumberNode, __module__::Module, f::Any)
    @ ArviZ ~/Repositories/Julia/ArviZ.jl/src/utils.jl:119
  [6] include(mod::Module, _path::String)
    @ Base ./Base.jl:457
  [7] include(x::String)
    @ ArviZ ~/Repositories/Julia/ArviZ.jl/src/ArviZ.jl:2
  [8] top-level scope
    @ ~/Repositories/Julia/ArviZ.jl/src/ArviZ.jl:151
  [9] include
    @ ./Base.jl:457 [inlined]
 [10] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing)
    @ Base ./loading.jl:2045
 [11] top-level scope
    @ stdin:3
in expression starting at /Users/ronnber/Repositories/Julia/ArviZ.jl/src/plots.jl:7
in expression starting at /Users/ronnber/Repositories/Julia/ArviZ.jl/src/plots.jl:7
in expression starting at /Users/ronnber/Repositories/Julia/ArviZ.jl/src/ArviZ.jl:2
in expression starting at stdin:3
ERROR: Failed to precompile ArviZ [131c737c-5715-5e2e-ad31-c244f01c1dc7] to "/Users/ronnber/.julia/compiled/v1.9/ArviZ/jl_DLhZ3B".
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool)
   @ Base ./loading.jl:2296
 [3] compilecache
   @ ./loading.jl:2163 [inlined]
 [4] _require(pkg::Base.PkgId, env::String)
   @ Base ./loading.jl:1805
 [5] _require_prelocked(uuidkey::Base.PkgId, env::String)
   @ Base ./loading.jl:1660
 [6] macro expansion
   @ ./loading.jl:1648 [inlined]
 [7] macro expansion
   @ ./lock.jl:267 [inlined]
 [8] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611

I am not sure how to resolve this, since I am not sure where this messages – it seems to be even 2? – come from. So I can no say much more than my generic posts from before.

@sethaxen
Copy link
Member Author

sethaxen commented Jul 6, 2023

Thanks for looking at this!

Can you pin point me to the cell that provides the issue?

This is the cell in quarto:

```{julia}
idata_turing_post = from_mcmcchains(
turing_chns;
coords=(; school=schools),
dims=NamedTuple(k => (:school,) for k in (:y, :σ, :θ)),
library="Turing",
)
```
. The InferenceData object has an HTML show method defined here: https://github.com/arviz-devs/InferenceObjects.jl/blob/12c402d7e06cf8fe404f418ffc958c8c9c20ac89/src/inference_data.jl#L192-L203

Variant 1: If possible one could write a show method that outputs markdown instead (or an additional show method for that)?

The desired HTML result uses interactive dropdown elements (using the HTML <details> tag), which are not available in markdown. I tried the following:

struct RawOutput
    content
    type::String
end

function Base.show(io::IO, ::MIME"text/markdown", o::RawOutput)
    print(io, "````@raw $(o.type)")
    show(io, "text/$(o.type)", o.content)
    println(io)
    println(io, "````")
    return nothing
end

RawOutput(idata_turing_post, "html")

but quarto ends up escaping the backticks, so Documenter can't recognize this as a valid @raw block. Here's the markdown Quarto renders this to:

\`\`\`\`@raw html

InferenceData
<details>
<summary>
posterior
</summary>
<pre><code>Dataset with dimensions: 
  Dim{:draw},
  Dim{:chain},
  Dim{:school} Categorical{String} String[Choate, Deerfield, …, St. Paul's, Mt. Hermon] Unordered
and 3 layers:
  :μ Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :τ Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :θ Float64 dims: Dim{:draw}, Dim{:chain}, Dim{:school} (1000×4×8)
&#10;with metadata Dict{String, Any} with 2 entries:
  "created_at" => "2023-07-06T10:52:22.591"
  "inference_library" => "Turing"</code></pre>
</details>
<details>
<summary>
sample_stats
</summary>
<pre><code>Dataset with dimensions: Dim{:draw}, Dim{:chain}
and 12 layers:
  :energy           Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :n_steps          Int64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :diverging        Bool dims: Dim{:draw}, Dim{:chain} (1000×4)
  :max_energy_error Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :energy_error     Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :is_accept        Bool dims: Dim{:draw}, Dim{:chain} (1000×4)
  :log_density      Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :tree_depth       Int64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :step_size        Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :acceptance_rate  Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :lp               Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
  :step_size_nom    Float64 dims: Dim{:draw}, Dim{:chain} (1000×4)
&#10;with metadata Dict{String, Any} with 2 entries:
  "created_at" => "2023-07-06T10:52:22.59"
  "inference_library" => "Turing"</code></pre>
</details>

\`\`\`\`

An awful hack would be to post-process all Quarto-rendered markdown files in make.jl to replace the escaped backticks with real ones. But at that point, it might be more straightforward to just not use RawOutput and instead parse the markdown files to find HTML and wrap it in a @raw block.

1. I tried to instantiate the `docs/` environment and that does not work directly, since it requires version 0.9 but only 0.8.2 Is registered. This I could solve by putting Arviz into development mode on the parent directory.

Yes, this is necessary when building docs for unregistered breaking releases.

2. `using Arviz` errors for me with

Looks like you've installed ArviZ before, so your Conda.jl environment has an outdated version of the Python package installed. You'll need to update ArviZ. If using Conda for Python deps installations, do

using Conda
Conda.add("arviz>=0.13.0"; channel="conda-forge")

(this all used to happen with interactive messages at load time, but since v1.9 seems to happen during precompilation, where interactivity is not possible, so it just errors)

@kellertuer
Copy link

So I have now fought with Conda for a while and I just give up, I can vary the error message quite a bit, but it never installs arviz, some dependencies might be wrong? I mean, my usual experiences with Python are: I have more python versions installed than I have ever run python (no, I reduced that to just one again by now) and that what ever I follow in python installation ideas is the same as bash: It works exactly on the machine of the person that wrote the tutorial. But usually not on mine.

You could try wrapping the raw html in a (even longer back-ticked) raw common mark block as

```{=commonmark}
....
```

We already do that for @ref links with spaces since quarto otherwise escapes those to %20 as well, see https://github.com/JuliaManifolds/Manifolds.jl/blob/e714d9d97e274ba8dd27d51095696064206054d4/tutorials/getstarted.qmd#L164
we just have not yet used it for whole books. The = tells quarto also to leave the block as is.

Concerning the show method – this is not a real markdown, since it is a raw-html-markdown-encapsulation, but I am not sure to what to translate the outer div or the inner details tag, the pre-code combination is of course just a backticks block.

@kellertuer
Copy link

My idea for a markdown (ignoring basically the summary and details tags) would be something like

function Base.show(io::IO, mime::MIME"text/markdown", data::InferenceData)
    print(io, "\n\nInferenceData\n\n")
    for (name, group) in pairs(groups(data))
        print(io, mime, """
        
        $name
        ```
        $(sprint(show, "text/plain", group))
        ```
        """))
    end
    return print(io, "\n\n")
end

@sethaxen
Copy link
Member Author

sethaxen commented Jul 6, 2023

I tried different ways of using {=commonmark} with no success.

My idea for a markdown (ignoring basically the summary and details tags) would be something like

For me this would not be acceptable. Most of the time one doesn't need or want to inspect the contents of an InferenceData. But sometimes it is quite convenient to do so interactively. Showing all contents could easily fill several screens, and at that point, it's better to have no custom show method at all.

I think I'll try my bad solution of post-processing the MD files, and if that doesn't work abandon using Quarto until Documenter (Julia?) has better support for CommonMark.

@kellertuer
Copy link

Hm, that is not a common mark problem but a problem that markdown does not have any notation to fold something (which I suppose the details tag does?)., but then sure, modifying the html output and wrap it in @raw html (sorry my notation was wrongg previously for documenter), but also wrap said raw html Block in a =commonmark block should do the job.

If the code is a bit ugly you can hide this display code and only show the output (and omit the output of the current cell).

It seems that if you are that dependent on html output, maybe some other method that does more HTML-like output is preferable here.

@kellertuer
Copy link

Oh, nice fix :)
A bit hardcoded for the div but nice.

@sethaxen
Copy link
Member Author

sethaxen commented Jul 6, 2023

A bit hardcoded for the div but nice.

Yeah it's a little more general than what we need (it handles nested divs, but we don't nest them), but I wrote it this way to point others to the solution. Basically, it assumes

  1. all HTML reprs are wrapped in a <div> (good practice anyways)
  2. if all opened <div>s are closed on a line, a new one is not opened on the same line.
  3. no non-HTML content comes before or after the HTML content on the same line

The nice thing about handling it this way is that the quarto file as a standalone still will render correctly.

docs/make.jl Outdated Show resolved Hide resolved
Comment on lines +40 to +42
```{julia}
df = DataFrame(idata.posterior)
```
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Successfully merging this pull request may close these issues.

2 participants