Closed mmaul closed 8 years ago
Thanks for the suggestion, but I'm not really excited about the idea.
replot
is one thing I tried to avoid in eazy-gnuplot, and is the very motivation/reason I wrote eazy-gnuplot.
When I used to write a gnuplot script by hand, replot
often causes incorrect plots. For example, on svg
terminal, replot
plots two overlapping graphs in one place, with different sizes and dimensions depending on the auto adjustments. This is probably because it does not erase the old plot.
You would then see why I implemented eazy-gnuplot's plot
so that it reads from the inline data, not as a sequence of replot
. Yes, this is one way to completely eliminate the use of replot
while plotting multiple data.
Re: gp-format, I think the meaning of plot stream is well defined and does not need additional abstraction. (with-plots (s ...) ...)
offers an environment where s
is bound to a stream dedicated to emitting a gnuplot script. I'd like to make it as transparent as possible so that no one gets scarred if there were some magic under the abstraction.
This is also relevant to the fact that I am not so active in supporting multiplots. (not against it, though.) It introduces problems like #22 , and makes the code much more complicated.
The primary cause of #22 is in the sequential/imperative nature of multiplot: It requires set
and unset
before plot
in order to render the figure appropriately. If further abstraction is possible, I rather want it to be more declarative. Unlike (format s ...)
vs (gp-format ...)
, this kind of abstraction helps the user and is in fact necessary.
In terms of personal needs, I mostly use eazy-gnuplot for single plots and then organize the results with latex (for writing a paper), so currently I am not using multiplots.
My point is, gnuplot team is extending gnuplot
too much, going beyond its minimalistic, original concept of plotting something. It even tries to increase the support for control structure like for
(in much less complete form, compared to lisp). We should be careful about this, and I won't support those features. However, I'm not sure if multiplot is one of them.
Regarding gp-format, it was not so much the need for a new abstraction so much as the need to render to plot-stream instead of user-stream, which relates to the ordering of statements. Which can be important especially in multiplot. For some stuff like variables or declaring functions in gnuplot it doesn't matter so much, other things it might. Another way of solving this problem is just set everything to render to plot-stream (Well except for the data).
Regarding replot, it is pretty much meant to be used interactively, to effect a change to a graph displayed in a terminal as opposed to constructing a final product. This is most likely why it does odd things in non-interactive terminals.
I propose removing gp-set
, gp-unset
, gp-clear
, withdrawing my request for gp-replot
and gp-format
and replacing them with two functions gp-stmt
and gp-zstmt
Below are the proposed implementations, descriptions in the docstrings. Look at the example below the implementation to see them in action.
(defun gp-zstmt (left-side &rest right-sides &key &allow-other-keys)
"Zipped statement ,render gnuplot `left-side` as string infront of each plist pair in `right-sides` rendering a gnuplot statement for each key-value pair in right sides.
For example:
(gp-zstmt :set :param '()
:lmargin 10)
Generates
set param
set lmargin 10
- Arguments:
- left-side : first word in gnuplot statement
- right-sides : Keyword arguments with gnuplot assignments, quoted by gp-quote.
- Return:
NIL
"
(if right-sides
(map-plist right-sides
(lambda (key val)
(format *plot-stream* "~&~a ~a ~a~%"
left-side key (gp-quote val))))
(format *plot-stream* "~&~a~%" left-side)))
(defun gp-stmt (left-side &rest right-side)
"Single statement ,render gnuplot `left-side` as string infront of gp-quoted contents of ars
For example:
Command:
(gp-stmt :set :param)
Generates:
set param
set lmargin 10
Command
(gp-stmt :style :line 1 :lc :rgb '(\"'#999999'\") :lt 1 '(\"#border\"))
Generates:
- Arguments:
- left-side : first word in gnuplot statement
- right-side : arguments remaining in the argument list rendered as parameters to left-side command
- Return:
NIL
"
(format *plot-stream* "~&~A ~A~%" left-side (gp-quote right-side))
)
And an example of their use:
(defun labeled-contour-plot ()
(eazy-gnuplot:with-plots (*standard-output* :debug t)
(eazy-gnuplot:gp-setup :output "-"
:terminal '(:wxt :persist))
(gp-stmt :clear)
(gp-stmt :unset :key)
(gp-stmt :unset :surf)
(gp-stmt :unset :clabel)
(gp-zstmt :set
:view :map
:contour :base
:xrange '("[0:5]")
:yrange '("[0:5]")
:style '( fill solid)
:for '("[n = 1:4]" cntrparam levels discrete ("n**2"))
:for '("[n = 1:4]" object n circle at n #\, n size 0.2 front fillcolor rgb ("'#ffffff'") lw 0)
:for '("[n = 1:4]" label n ("sprintf(\"%d\", n**2)") at n #\, n center front)
)
(gp-stmt "f(x,y)" := '("x < 5 ? sin(x) + (1+1/y): NaN"))
(func-splot "x*y" :with '(:lines :lt 2 :lw 4))
(func-splot "f(x,y)" :with '(:points :pt 7 :ps 2 ))
(gp-stmt :save "\"labeled-contour-plot.gp\"")
(gp-zstmt :set :title "Labeled Contour Plot")
(gp-stmt :replot)
))
sounds better than gp-set/unset or other specialized variations.
I'd like it if it is a single interface, i.e., could you remove one of gp-stmt / gp-zstmt ?
If so, the more appropriate name would be just gp
, which is just shorter.
by the way, I don't recommend using for
statements in gnuplot unless necessary. you can instead do
(apply #'gp-zstmt :set :cntrparam :levels :discrete (loop for n from 1 to 4 collect (expt n 2)))
One related idea is emulating a dynamic binding, i.e.,
(gp-let ((:view :map))
(xxx-plot yyy zzz))
;; unset :view when exiting the construct
So lets go with:
Change gp-stmt
to gp
.
Drop gp-zstmt
I like the gp-let
concept, It is a little more complicated than just issuing a unset
on everything that was set in gp-set
since the values you change could been have set to other values previously as opposed to being unset. What would be necessary is to save state by calling the show
command for each property set in gp-let
and then restoring the state when gp-let
is done.
Okay so, I'm sending a pull request with gp-set
,gp-unset
,gp-replot
, gp-clear
removed
and replaced by gp <command> &rest args
. Tests for issue 8 and 21 have been updated and should cover these changes. Also including the Ipython notebook and HTML output in the docs directory.
The replot command is somewhat common, I propose
gp-replot.
Also I propose a
gp-format
command, which takes a format string and arguments and renders to the plot-stream.