Maybe I'm the only one, but I think all those exclamation marks are a bit extraneous and feel like syntactic noise.
I have been following Plots.jl because I'm interested in plotting. My use of Julia comes down to either making plots, or post-processing data so I can make a plots. I get the idea from Plots.jl that functions that end in an exclamation mark are supposed to modify an existing plot. So you get things like:plot!(...) # Add another plot to an existing one.title!(...)xaxis!("mylabel", :log, :flip)xlims!(...)xticks!(...)
In PyPlot, all commands edit the current plot unless you explicitly call `figure()` to create a new plot. You can also use clf() to clear the current plot. I think this is something that PyPlot / Matplotlib get right.
# these will effectively call clf() before each command
using Plots
pyplot(reuse = true)
plot(rand(10))
plot(rand(10))
plot(rand(10))
It modifies a plot, and so follows Julia convention. Anything else is likely to induce confusion.
In PyPlot, all commands edit the current plot unless you explicitly call `figure()` to create a new plot. You can also use clf() to clear the current plot. I think this is something that PyPlot / Matplotlib get right.We can agree to disagree on this point. It's clunky and error-prone.
Quick tip: you can choose to reuse PyPlot windows by default if you want:# these will effectively call clf() before each commandusing Plotspyplot(reuse = true)
plot(rand(10))
plot(rand(10))
plot(rand(10))
IMO an extra ! is a small price to pay for consistency --- you are after
all modifying an existing object. Avoiding globals is also a good
strategy.
Actually, it doesn't seem entirely consistent with Julia conventions.The standard Julia convention (borrowed from Lisp/Scheme) is that a ! suffix means that a function modifies *one of its arguments*.
The `plot!` command is primarily `plot!(plt::AbstractPlot, args...; kw...)`. In this case it holds to convention.I have a convenience `current()` which stores the most recently updated AbstractPlot object in a global, so that any plotting command without a leading AbstractPlot object gets it added implicitly. (i.e. a call to `plot!(...)` is really a call to `plot!(current(), ...)`).I think this strategy is better than alternatives, and isn't too far from accepted conventions.
Ben!
I understand that to you this seems intuitive, but to me it is completely counter-intuitive. The function that I'm calling is not changing any of its inputs. Telling me that behind the scenes it calls "plots!" is describing an implementation detail that can change and should have no bearing on the exposed API.
plt = plot(rand(10))
plot!(plt, xlim = (0,20))
plt = plot(title = "...", xaxis = (...), ...)
for dir in directories
... do some work ...
plot!(plt, result, ...)
end
I would argue that "plots(plt, ...)" is like "write(stream, ...)"