Gnuplot.jl
Gnuplot.jl copied to clipboard
Switch to using display() to show the plots
This brings better compatibility with the Julia package ecosystem. Now, if Gnuplot.jl is used in an environment capable of showing multimedia content (IJulia, VS Code, Pluto), their internal viewer will take precedence over using gnuplot's built-in viewer. In the REPL, gnuplot viewer is still used by default.
In VS Code, for example, when the Use Plot Pane settings is enabled, the plots show in that pane, but when it is disabled, gnuplot viewer is automatically used.
For people who prefer to always use the gnuplot viewer, they can set Gnuplot.options.gpviewer to true. This should result in the same behaviour as before this commit.
Things done:
- [x] Updated documentation
- [x] Tested (with
gpviewer = false
)- [x] Gnuplot.jl functionality
- [x] Plotting from REPL
- [x] Test suite
- [x] Documentation build
- [x] DrySessions
- [x] Plot in a terminal application (dumb, sixelgd)
- [x] Integrations
- [x] VS Code
- [x] With Plot Pane enabled
- [x] With Plot Pane disabled
- [x] IJulia
- [x] Pluto
- [x] Juno
- [x] Weave.jl
- [x] VS Code
- [x] Gnuplot.jl functionality
Summary
The table below is copied from display.ipynb and updated. Only the false
/REPL column needed to be changed. The values are almost the same as in true
/REPL, the difference is in Calls to display() / automatic display (trailing ;) and The top level code works also within a function?.
Gnuplot.options.gpviewer = true |
REPL, Jupyter or Juno |
---|---|
Plots are shown | in dedicated window(s) |
Updating a plot | updates window content |
Output of different session goes to | separate windows |
How many simultaneous plots can be shown? | all windows fitting the screen |
Calls to display() / automatic display (trailing ; ) |
does nothing / not applicable |
The top level code works also within a function? | yes, explicit display() calls are not required |
Terminal options are specified in | Gnuplot.options.term |
Gnuplot.options.gpviewer = false |
REPL | Jupyter | Juno |
---|---|---|---|
Plots are shown | in dedicated window(s) | as inline images in the notebook | as image in the plot pane |
Updating a plot | updates window content | creates a separate image | overwrites the plot pane content |
Output of different session goes to | separate windows | the same notebook | the plot pane |
How many simultaneous plots can be shown? | all windows fitting the screen | all those fitting in the visible part of the notebook | only one |
Calls to display() / automatic display (trailing ; ) |
updates the plot/applicable | updates the plot / applicable | updates the plot / applicable |
The top level code works also within a function? | no, explicit display() calls are are required |
no, explicit display() calls are required |
no, explicit display() calls are are required |
Terminal options are specified in | Gnuplot.options.term |
Gnuplot.options.mime |
Gnuplot.options.mime |
Related to #45
@pfitzseb Do you know why Plots.jl
has this code?
# Copied from Plots - insert GnuplotDisplay before text displays, but after graphic displays such as IJulia, VSCodeDisplay, etc.
insert!(Base.Multimedia.displays, findlast(x -> x isa Base.TextDisplay || x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, GnuplotDisplay())
atreplinit(i -> begin
while GnuplotDisplay() in Base.Multimedia.displays
popdisplay(GnuplotDisplay())
end
insert!(Base.Multimedia.displays, findlast(x -> x isa REPL.REPLDisplay, Base.Multimedia.displays) + 1, GnuplotDisplay())
end)
It seems it's not necessary. In my tests, plain pushdisplay(GnuplotDisplay())
seems to work in all environments where I test it. VS Code always reorders displays to make its display last, and in IJulia, the order seems not to be important. Pluto does not hook itself into the displays
.
Do you know why
Plots.jl
has this code?
I was able to see the difference only in IJulia
. With pushdisplay
, the order of IJulia and Gnuplot displays was sometimes swapped, which resulted in different behavior when explicitly calling display()
.
@gcalderone Can you try/review this? I tried hard not to break any functionality of gpviewer = true
. All the changes are in gpviewer = false
, which is now the default.
I see that @gcalderone is working on Gnuplot.jl now, so I'm posting a comment about my experience with using this change for several months.
Having gpviewer = false
being the default sometimes produces surprises (when one refactors the code by moving top-level code to a function). This was expected and pointed out by @gcalderone in advance.
However, when I want to use packages like Weave.jl, having gpviewer = true
is not an option, because then Weave.jl cannot capture the output. The problem with Weave.jl is that when one creates a report by calling weave()
from the REPL, it needs gpviewer = false
but when calling other functions from the REPL, one wants gpviewer = true
.
So my conclusion is that this change allows me to use Weave.jl, but it's not perfect. Ideally, we'd need a better way than a global variable to distinguish when to send the plot to Julia's Multimedia I/O and when to Gnuplot.
One idea, that comes to my mind (inspired by #51), is to check whether stdout is a terminal and decide based on that. If we're lucky packages like Weave.jl will run the code with stdout redirected to a pipe and we could use this as a sign to use Multimedia I/O. On the other hand, it will likely cause other problems in non-standard use-cases. So I'm not really sure what's the best.
Hi @wentasah , thank you very much for providing such valuable insights on the interplay between the display()
machinery and Gnuplot.jl.
However, as already discussed in #45, the best usage of Gnuplot.jl is (IMHO) outside tools like Jupyter, Juno, Weave, and the like, and therefore I would like to avoid introducing special cases or workarounds which are not thoroughly tested and coherent with the aim of the package. As a specific example, I would really like to avoid having gpviewer = false
as default, or having a gnuplot viewer window being shown even if gpviewer = false
.
I'm afraid the desire to make Gnuplot.jl works seamlessly in such tools/IDEs may lead to inconsistencies with its original use case, namely the use through the gnuplot external viewer.
As anticipated in #45,I would really love to see those functionalities moved in an external package, and I encourage anyone willing to do so. Besides, I have definitely limited experience with Jupyter, Juno, etc., and zero experience with Weave, making it very difficult for me to foresee all the consequences of a choice.
For the moment I will leave this PR open, in the hope that it could be used as a starting point for a discussion leading to new packages being developed which allow to use the Gnuplot.jl syntax in all the available (and amazing!) environments. If I understand correctly it all amounts to define the proper show(::IO, MIME, ::SessionID)
methods and insert the proper structure in Base.Multimedia.displays
. We may even use Reexport to avoid the direct dependency on Gnuplot.jl itself, and leave the user with a very simple using GnuplotOnJupyter
or similar statemens.
I will be more than happy to modify the Gnuplot.jl source code to facilitate this changes, and make it usable / compatible with the new package.