Plotting errors when building documentation using Plots.jl and Documenter.jl

Hi all, I’m attempting to add plots into my package documentation using Plots.jl and Documenter.jl. However, creating a simple plot such as the following produces an error as below.

Code in markdown file:

using Plots

plot(1:100)

Resulting error when I tried julia --project=docs/ docs/make.jl:

[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
[ Info: ExpandTemplates: expanding markdown templates.
connect: No error
GKS: can't connect to GKS socket application

ERROR: LoadError: ReadOnlyMemoryError()
Stacktrace:
  [1] setcharheight(height::Float64)
    @ GR ~\.julia\packages\GR\bVi3d\src\GR.jl:1630
  [2] gr_set_font(f::Plots.Font, s::Plots.Subplot{Plots.GRBackend}; halign::Symbol, valign::Symbol, color::ColorTypes.RGB{FixedPointNumbers.N0f8}, rotation::Float64)
    @ Plots ~\.julia\packages\Plots\Awg62\src\backends\gr.jl:391
  [3] gr_set_font(f::Plots.Font, s::Plots.Subplot{Plots.GRBackend})
    @ Plots ~\.julia\packages\Plots\Awg62\src\backends\gr.jl:390
  [4] _update_min_padding!(sp::Plots.Subplot{Plots.GRBackend})
    @ Plots ~\.julia\packages\Plots\Awg62\src\backends\gr.jl:758
  [5] iterate
    @ .\generator.jl:47 [inlined]
  [6] _collect(c::Matrix{RecipesBase.AbstractLayout}, itr::Base.Generator{Matrix{RecipesBase.AbstractLayout}, typeof(Plots._update_min_padding!)}, #unused#::Base.EltypeUnknown, isz::Base.HasShape{2})
    @ Base .\array.jl:691
  [7] collect_similar
    @ .\array.jl:606 [inlined]
  [8] map
    @ .\abstractarray.jl:2294 [inlined]
  [9] _update_min_padding!(layout::Plots.GridLayout)
    @ Plots ~\.julia\packages\Plots\Awg62\src\layouts.jl:282
 [10] prepare_output(plt::Plots.Plot{Plots.GRBackend})
    @ Plots ~\.julia\packages\Plots\Awg62\src\plot.jl:224
 [11] show
    @ ~\.julia\packages\Plots\Awg62\src\output.jl:214 [inlined]
 [12] __binrepr
    @ .\multimedia.jl:159 [inlined]
 [13] _textrepr
    @ .\multimedia.jl:151 [inlined]
 [14] stringmime(m::MIME{Symbol("text/html")}, x::Plots.Plot{Plots.GRBackend}; context::Nothing)
    @ Base64 C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\Base64\src\Base64.jl:43
 [15] stringmime(m::MIME{Symbol("text/html")}, x::Plots.Plot{Plots.GRBackend})
    @ Base64 C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\Base64\src\Base64.jl:43
 [16] display_dict(x::Plots.Plot{Plots.GRBackend})
    @ Documenter.Utilities ~\.julia\packages\Documenter\f5jts\src\Utilities\Utilities.jl:627
 [17] #invokelatest#2
    @ .\essentials.jl:708 [inlined]
 [18] invokelatest
    @ .\essentials.jl:706 [inlined]
 [19] runner(#unused#::Type{Documenter.Expanders.ExampleBlocks}, x::Markdown.Code, page::Documenter.Documents.Page, doc::Documenter.Documents.Document)
    @ Documenter.Expanders ~\.julia\packages\Documenter\f5jts\src\Expanders.jl:582
 [20] dispatch(::Type{Documenter.Expanders.ExpanderPipeline}, ::Markdown.Code, ::Vararg{Any, N} where N)
    @ Documenter.Utilities.Selectors ~\.julia\packages\Documenter\f5jts\src\Utilities\Selectors.jl:170
 [21] expand(doc::Documenter.Documents.Document)
    @ Documenter.Expanders ~\.julia\packages\Documenter\f5jts\src\Expanders.jl:42
 [22] runner(#unused#::Type{Documenter.Builder.ExpandTemplates}, doc::Documenter.Documents.Document)
    @ Documenter.Builder ~\.julia\packages\Documenter\f5jts\src\Builder.jl:227
 [23] dispatch(#unused#::Type{Documenter.Builder.DocumentPipeline}, x::Documenter.Documents.Document)
    @ Documenter.Utilities.Selectors ~\.julia\packages\Documenter\f5jts\src\Utilities\Selectors.jl:170
 [24] #2
    @ ~\.julia\packages\Documenter\f5jts\src\Documenter.jl:249 [inlined]
 [25] cd(f::Documenter.var"#2#3"{Documenter.Documents.Document}, dir::String)
    @ Base.Filesystem .\file.jl:95
 [26] #makedocs#1
    @ ~\.julia\packages\Documenter\f5jts\src\Documenter.jl:248 [inlined]
 [27] top-level scope
    @ ~\Documents\WaveletsExt\docs\make.jl:3
in expression starting at C:\Users\LZFun\Documents\WaveletsExt\docs\make.jl:3

Could anyone shed some light on what’s happening here? This was never a problem when I worked on documentation a couple of months ago. Was there a new update that perhaps messed things up, or that it requires some form of changes in my code?

Thanks in advance.

On headless systems you can set ENV["GKS_WSTYPE"]=100 before importing Plots or set the environment variable in your shell scripts. This should be done automatically if you are using an up-to-date GR version.

1 Like

Hi, thanks for your reply. I tried updating all my dependencies and it worked on my local Windows machine, but not on Github Actions. How do I set ENV["GKS_WSTYPE"]=100 on my Documenter.yml file?

I don’t know your Documenter.jl setup, but I suspect you’ll have to add ENV["GKS_WSTYPE"]=100 at the beginning of your make.jl script.

Adding that line did not work. It throws out this error:

ERROR: LoadError: SystemError: opening file "/tmp/jl_QfUIVp.svg": No such file or directory
Stacktrace:
  [1] systemerror(p::String, errno::Int32; extrainfo::Nothing)
    @ Base ./error.jl:168
  [2] #systemerror#62
    @ ./error.jl:167 [inlined]
  [3] systemerror
    @ ./error.jl:167 [inlined]
  [4] open(fname::String; lock::Bool, read::Nothing, write::Nothing, create::Nothing, truncate::Nothing, append::Nothing)
    @ Base ./iostream.jl:293
  [5] open
    @ ./iostream.jl:282 [inlined]
  [6] open(f::Base.var"#326#327"{String}, args::String; kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Base ./io.jl:328
  [7] open
    @ ./io.jl:328 [inlined]
  [8] read
    @ ./io.jl:434 [inlined]
  [9] _show(io::IOContext{IOBuffer}, #unused#::MIME{Symbol("image/svg+xml")}, plt::Plots.Plot{Plots.GRBackend})
    @ Plots ~/.julia/packages/Plots/Di0Qb/src/backends/gr.jl:2054
 [10] show(io::IOContext{IOBuffer}, m::MIME{Symbol("image/svg+xml")}, plt::Plots.Plot{Plots.GRBackend})
    @ Plots ~/.julia/packages/Plots/Di0Qb/src/output.jl:213
 [11] _show(io::IOContext{IOBuffer}, #unused#::MIME{Symbol("text/html")}, plt::Plots.Plot{Plots.GRBackend})
    @ Plots ~/.julia/packages/Plots/Di0Qb/src/output.jl:178
 [12] show(io::IOContext{IOBuffer}, m::MIME{Symbol("text/html")}, plt::Plots.Plot{Plots.GRBackend})
    @ Plots ~/.julia/packages/Plots/Di0Qb/src/output.jl:213
 [13] __binrepr
    @ ./multimedia.jl:161 [inlined]
 [14] _textrepr
    @ ./multimedia.jl:151 [inlined]
 [15] stringmime(m::MIME{Symbol("text/html")}, x::Plots.Plot{Plots.GRBackend}; context::Pair{Symbol, Bool})
    @ Base64 /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Base64/src/Base64.jl:43
 [16] display_dict(x::Plots.Plot{Plots.GRBackend}; context::Pair{Symbol, Bool})
    @ Documenter.Utilities ~/.julia/packages/Documenter/ruzxx/src/Utilities/Utilities.jl:666
 [17] invokelatest(f::Any, args::Any; kwargs::Base.Iterators.Pairs{Symbol, Pair{Symbol, Bool}, Tuple{Symbol}, NamedTuple{(:context,), Tuple{Pair{Symbol, Bool}}}})
    @ Base ./essentials.jl:710
 [18] runner(#unused#::Type{Documenter.Expanders.ExampleBlocks}, x::Markdown.Code, page::Documenter.Documents.Page, doc::Documenter.Documents.Document)
    @ Documenter.Expanders ~/.julia/packages/Documenter/ruzxx/src/Expanders.jl:610
 [19] dispatch(::Type{Documenter.Expanders.ExpanderPipeline}, ::Markdown.Code, ::Vararg{Any, N} where N)
    @ Documenter.Utilities.Selectors ~/.julia/packages/Documenter/ruzxx/src/Utilities/Selectors.jl:170
 [20] expand(doc::Documenter.Documents.Document)
    @ Documenter.Expanders ~/.julia/packages/Documenter/ruzxx/src/Expanders.jl:42
 [21] runner(#unused#::Type{Documenter.Builder.ExpandTemplates}, doc::Documenter.Documents.Document)
    @ Documenter.Builder ~/.julia/packages/Documenter/ruzxx/src/Builder.jl:227
 [22] dispatch(#unused#::Type{Documenter.Builder.DocumentPipeline}, x::Documenter.Documents.Document)
    @ Documenter.Utilities.Selectors ~/.julia/packages/Documenter/ruzxx/src/Utilities/Selectors.jl:170
 [23] #2
    @ ~/.julia/packages/Documenter/ruzxx/src/Documenter.jl:257 [inlined]
 [24] cd(f::Documenter.var"#2#3"{Documenter.Documents.Document}, dir::String)
    @ Base.Filesystem ./file.jl:106
 [25] #makedocs#1
    @ ~/.julia/packages/Documenter/ruzxx/src/Documenter.jl:256 [inlined]
 [26] top-level scope
    @ ~/work/WaveletsExt.jl/WaveletsExt.jl/docs/make.jl:4
in expression starting at /home/runner/work/WaveletsExt.jl/WaveletsExt.jl/docs/make.jl:4
Error: Process completed with exit code 1.

My make.jl file is also pretty standard and follows the basic tutorials on writing Julia documentation:

ENV["GKS_WSTYPE"]=100
using Documenter, WaveletsExt

makedocs(
    sitename = "WaveletsExt.jl",
    format = Documenter.HTML(),
    authors = ...,
    clean = ...,
    pages = ...
)

deploydocs(
    repo = ...
)

It seems, that for Plots.jl two environment variables are required:

        ENV["PLOTS_TEST"] = "true"
        ENV["GKSwstype"] = "100"

I took those information from their runtests.jl script.

2 Likes

Interesting! This works now, thank you so much for your help. Where can I find resources on setting these fields such as GKSwstype or PLOTS_TEST for ENV? My understanding is that ENV is just a dictionary interface that connects to a machine’s system variables.

Once again, big help! Thank you!

It seems that the PLOTS_TEST environment is obsolete in the meantime. GKSwstype=100 directs GR to open a dummy output driver instead of an interactive output device (which would fail on headless systems).