How do I prevent the script from terminating when the plot window is still open? I cannot find it anywhere in the documentation.
using Plots
pyplot()
plot(1:50)
I see the window opening, but I cannot prevent the script from shutting down directly after the plot command.. I'm simply running 'julia test.jl'.
By directly using pyplot I can get this to work with the show command, but this appears to be missing in Plots?
using PyPlot
plot(1:50)
show()
Any particular reason for running julia like that from bash, rather than just running julia and working in an interactive session? You can include("test.jl") from the interactive prompt to run a script. I think for most script-based uses of Plots I'd assume the script to save the plot as an image file (savefig()).
I wasn't aware that this is the normal workflow for running scripts.
I guess that include() clutters the workspace right? Suppose all of my students hand in some exercise which is supposed to generate a plot(s). It seems natural to execute each of their scripts in a clean workspace, check the graph and proceed.
It very much is the normal workflow to just keep a Julia REPL open and work interactively. Most of the time you wouldn't want to write a script out of your session and run it, but instead work in Jupyter notebooks (ideal for students IMO since it keeps code, comments/reflections and plots together) or to have your script open in something like Juno and evaluate from there. You can also play with the plot, changing settings etc.
If you don't want to clutter the workspace, the technique is to use modules, they create independent global scopes. If you do want to work by include()'ing script files you can e.g. make each script a Module, wrap the script in a function in that module (good approach anyway to avoid globals) and export that function from the module.
Just add:
show()
At the end of the script. Example:
using PyPlot
plot(rand(10))
show()
@profesors This is the Plots repo, not the PyPlot repo. It doesn't make any sense to comment a solution using a different plotting package - AND the code snippet there was listed in the OP.
Closing as this is not a Plots issue, but a workflow problem.
Sad.
Thanks for your contributions here @jampekka
I don't think it is very sensible for this to be closed as "a workflow issue".
I guess the thing about workflows is, different people have different ones. For example, when I'm developing code I like it to run repeatably, exactly the same every time. Having to use a persistent REPL or notebook session brings the potential for subtle errors which would cause my code to work now, but not to work the next time I try it (potentially years later), because the state of my runtime environment has changed.
So to my mind the issue is "Plots fails to support a very common and extremely sensible workflow", and not "the user is in error for having the wrong workflow."
What exactly are you requesting though? You cannot have a plotting window open after your julia session closes - at least I don't see how that should be implemented from Plots.
If you've got specific workable suggestions other than just complaints I'm happy to reopen the issue.
The minimal feature that would enable this workflow is simply an option for the display method to block until the window is closed.
Potentially, for some users, it might be useful to have an event loop system, allowing user interaction to continue while dynamically updating the plot.
Improvements to the import time would go a long way towards making this kind of workflow feasible in practice, since you have to import the package every time you run the script.
OK, I have reopened the issue with a more suitable name. Anyone who wishes to implement this and add a PR to Plots are free to do so.
I feel I should note here, though:
when I'm developing code I like it to run repeatably, exactly the same every time. Having to use a persistent REPL or notebook session brings the potential for subtle errors
The ideomatic way of running code repeatedly, exactly the same every time is to wrap the code in a function, then run that. More generally, you control environment hygiene in Julia with modules. Reloading a module should clear the module namespace. But in this case it's easier to just use a function.
brings the potential for subtle errors which would cause my code to work now, but not to work the next time I try it (potentially years later), because the state of my runtime environment has changed.
This should not happen. Your code should not depend on the state of all kinds of bindings floating around in global scope. If it does, that is considered poor coding style, and will also make your julia code very slow. Just wrapping your code in a function and paying attention to scope will solve this.
(potentially years later), because the state of my runtime environment has changed.
What is it that you imagine have changed years later? Your global scope should not affect the running of your code, but over a time scale of years your julia version and dependencies may have changed. You use environments to deal with this - essentially you don't have to update the environment associated with a certain project, no matter how many years pass. If you do want to use a newer version of Julia and environments, you may suffer breakage - script or not.
Plots fails to support a very common and extremely sensible workflow
No.
Improvements to the import time would go a long way
I believe that is priority # 3 for the compiler core team: https://discourse.julialang.org/t/compiler-work-priorities/17623
Note that this is a general Julia issue - Plots is most likely loading as fast as possible under the circumstances, or at least a lot of work has gone into assuring this.
for some users, it might be useful to have an event loop system, allowing user interaction to continue while dynamically updating the plot
I may be mistaken here, but isn't this an exact description of the current system? Or do you mean click-and-drag?
Thanks for reopening, that's appreciated.
Regarding global variables, I am new to Julia and might be overcautious because of bad experience with Python, where it's quite easy to accidentally refer to global state without realising it, especially when reloading modules.
What is it that you imagine have changed years later?
Quite simply, I will not have the same REPL session open any more. Since years may have passed, I'm unlikely to remember anything special I did before running the script.
I may be mistaken here, but isn't this an exact description of the current system?
Maybe. In that case, how do I currently register a callback, e.g. for closing the window, and how does one actually enter the event loop?
Since years may have passed, I'm unlikely to remember anything special I did before running the script.
What would that be, and how would that be the responsibility of Plots? It does really seem like a workflow issue more than anything else.
I'm not sure how useful it is to have this conversation, since it's just an argument about my workflow versus your workflow, and it's not actually giving you any information that you would need in order to implement this. But here is an example to show what I mean.
First, put the following in Test.jl:
module Test
using Plots
unicodeplots()
function test()
plot([1,5,2])
end
end
Then, in a REPL, run
include("Test.jl");Test.test()
Everything is in a module, so it should run the same every time, right?
Now comment out the line unicodeplots() and run it again. The outcome is the same, a unicode plot. But now if you re-start the REPL and run the exact same code again, it will instead produce a graphical plot using the gr backend.
This happens because although includeing the Test module clears the namespace of the Test module, it does not clear any other namespaces, and global state can be stored in those. So even if my code is in a module it is quite possible that, unknown to me, it is actually relying on global state left over from running previous versions of the same code. I have been bitten by this kind of issue in Python, and I want to work in a way that it can be guaranteed not to occur.
The obvious way to do that is to run all my code in a script and not in a REPL, so a new process is started every time and there is no runtime state. The issue is that Plots doesn't readily support that workflow.
So yes, it is a "workflow issue", but it is one that seems to need changes to Plots in order to be convenient. (And also more major changes to julia itself, to avoid the long load times.) This is, of course, the only sense in which any of this is Plots' responsibility.
If that doesn't satisfy you, let's just agree to differ. It seems off-topic and counterproductive to continue arguing about whether one workflow is better than another.
If that doesn't satisfy you, let's just agree to differ. It seems off-topic and counterproductive to continue arguing about whether one workflow is better than another.
I think you're assuming my position far too soon. You wrote
I'm unlikely to remember anything special I did before running the script.
I took that to be something "outside of julia", since you said "before running my script".
I don't like the "global"-ness of pgfplots(), gr() at all. Unfortunately, I don't have time to contribute to Plots, but I'd much rather it was like a show(io, ...) kind of thing where you'd pass in the plotting backend as the first argument... Every time, or with a sensible default (but I'd prefer every time because it makes it easier to maintain, and is very explicit).
using Plots
# using PlotsBackends/GRBackend if we don't want to depend on the backend
pb = GRBackend(theme=..., size=..., ...)
x = ...
y = ...
p = plot(pb, x, y)
You could then `plot!(p, x2, y2) as the backend would be part of the plot object.
but.. yeah.. I don't have the time, and Plots doesn't exactly work like that either, so it would be quite some work I think.
Most helpful comment
OK, I have reopened the issue with a more suitable name. Anyone who wishes to implement this and add a PR to Plots are free to do so.
I feel I should note here, though:
The ideomatic way of running code repeatedly, exactly the same every time is to wrap the code in a function, then run that. More generally, you control environment hygiene in Julia with modules. Reloading a module should clear the module namespace. But in this case it's easier to just use a function.
This should not happen. Your code should not depend on the state of all kinds of bindings floating around in global scope. If it does, that is considered poor coding style, and will also make your julia code very slow. Just wrapping your code in a function and paying attention to scope will solve this.
What is it that you imagine have changed years later? Your global scope should not affect the running of your code, but over a time scale of years your julia version and dependencies may have changed. You use environments to deal with this - essentially you don't have to update the environment associated with a certain project, no matter how many years pass. If you do want to use a newer version of Julia and environments, you may suffer breakage - script or not.
No.
I believe that is priority # 3 for the compiler core team: https://discourse.julialang.org/t/compiler-work-priorities/17623
Note that this is a general Julia issue - Plots is most likely loading as fast as possible under the circumstances, or at least a lot of work has gone into assuring this.