Mirko
12/14/2015 3:34:00 AM
On Tuesday, December 8, 2015 at 6:48:38 PM UTC-5, informatimago wrote:
> Mirko Vukovic <mirko.vukovic...> writes:
>
> > I am generating some classes with geometric information. I will
> > use cl-vectors or vecto or some other library to display them.
> >
> > For example sake, assume that the class describes a rectangle.
> >
> > I could *display-it*
> > - textually by printing out its dimensions
> > - generate a ps file
> > - generate a png file using vecto
> > - generate an svg file
> >
> > I am looking for an interface design that can decouple the
> > display method from the geometry information.
> >
> > I started writing a library *display-it* whose main method is
> >
> > (defgeneric display-it (it format &optional s)
> > (:documentation "Display object IT using FORMAT to stream S
> >
> > S is by default T
> >
> > FORMAT must be an object of class DISPLAY-FORMAT")
> > (:method (it (format t) &optional s)
> > (declare (ignore it format s))
> > (error "FORMAT must be an object that subclasses DISPLAY-FORMAT")))
>
> This is a choice.
>
> But notice that CLOS allows for duck typing, that is, it doesn't
> restrict a-priori the use of specific superclasses.
>
>
> The consequence, is that you can define interfaces basically as a set of
> generic functions, not as a base class.
>
OK, I will look at duck-typing - in general I always tend to restrict myself to
subclasses of a base class just as a matter of style - I never really had
a real need for that.
> Now, concerning:
>
> (defgeneric display-it (it format &optional s))
>
> > - textually by printing out its dimensions
> > - generate a ps file
> > - generate a png file using vecto
> > - generate an svg file
>
>
> 1- I'm a little bothered by the optional stream.
snip ...
I deleted the rest of the comments...
As I was thinking more about the problem, Leland Wilkinson's grammar
of graphics came to mind. I took a stab at that a few years ago but
that was a dismal failure.
I now came up with a different API using his Grammar of Graphics.
Here is an example (the cross operator combines two sequences into two concurrent sequences that can define a scatterplot)
(display-it (cross pop1980 pop2000)
:scale :x1e-6
:geom :point
:aesthetic (:radius (5 :mm) :color :dark-blue)
:guides (:x-title "Population (millions)"
:y-title "Population (millions)"
:caption "A 2D scatterplot of city populations")
:renderer (:gnuplot "populations-1980-vs-2000.png"))
Under the hood this expands into making an instance of a class
that stores the specification, and passing it to a render function.
For example, to generate two tables:
(let ((definition
(make-graphics-definition
:scale :x1e-6
:geom (format "~5,3")
:guides (:title "Population of some major US and world cities in 1980"
:column-title "Population\\(millions)"
:column-title-hline t
:table-bottom-hline t))))
(render '(:latex "populations-1980.pdf") definition pop-1980)
(render '(:latex "populations-2000.pdf") definition pop-2000))
Hadley Wickham (in his book on ggplot) noted that a grammar does not
guarantee meaningful sentences. This applies here too. The syntax above can
still create meaningless code - a syntax used to specify
a table in TeX format, would be meaningless to the gnuplot renderer.
Now I need a few clear days to code this - it will take longer than that :-)
Mirko