Get rid of the AbbrvKW dependency

This commit is contained in:
Giorgio Calderone 2017-08-28 01:28:30 +02:00
parent 0f827598fc
commit c441a3ce99
4 changed files with 213 additions and 39 deletions

View File

@ -5,9 +5,7 @@
**Gnuplot.jl** allows easy and fast use
of [Gnuplot](http://gnuplot.info/) as data visualization tool in
Julia. It is mainly focused on
GnuplotFeatures:
Julia. Its main features are:
- transparent interface between Julia and gnuplot to exploit all
functionalities of the latter, both present and future ones;
@ -15,15 +13,22 @@ GnuplotFeatures:
- fast data transmission to gnuplot through system pipes (no temporary
files involved);
- support for running multiple gnuplot istances simulatneously;
- support for running multiple gnuplot process simulatneously;
- support for multiplots;
- extremely concise syntax (see Examples below) makes it ideal for
interactive use and data exploration;
- extremely concise syntax (see examples below), makes it ideal for
interactive data exploration;
- very easy to use: if you know gnuplot you're ready to go.
The purpose is similar to
the [Gaston](https://github.com/mbaz/Gaston.jl) package, but
**Gnuplot.jl** main focus is on on the syntax conciseness and ease of
use.
## Installation
In the Julia REPL type:
@ -35,26 +40,68 @@ You'll also need gnuplot (ver. >= 4.7) installed on your system.
## Quick start:
Here we will show basic usage:
Here we will show a very basic usage:
``` Julia
using Gnuplot
# Create some noisy data
# Create some noisy data...
x = collect(linspace(-2pi, 2pi, 100))
y = 1.5 * sin.(0.3 + 0.7x)
noise = randn(length(x))./2
e = 0.5 * ones(x)
@gp("set key horizontal",
x, y, "w l dt 1 lw 2 t 'Real model'",
# ...and show them using gnuplot.
@gp("set key horizontal", "set grid",
xrange=(-7,7), ylab="Y label",
x, y, "w l t 'Real model' dt 2 lw 2 lc rgb 'red'",
x, y+noise, e, "w errorbars t 'Data'")
```
That's it for the first plot. The syntax should be familitar to most
gnuplot users.
That's it for the first plot, the syntax should be familiar to most
gnuplot users. With this code we:
- set a few gnuplot properties (`key` and `grid`);
- set the X axis range and Y axis label;
- passed the data to gnuplot;
- plot two data sets specifying a few details (style, line
width, color, legend, etc...).
Note that this simple example already covers the vast majority of use
cases, since the remaining details of the plot can be easily tweaked
by adding the appropriate gnuplot command. Also note that you would
barely recognize the Julia language by just looking at the `@gp` macro
since **Gnuplot.jl** aims to be the mostly transparent: the user is
supposed to focus only on the data and on the gnuplot commands, rather
than the **Gnuplot.jl** package details.
Now some more advanced usage (fit the data and overplot the results):
Before proceeding we will brief discuss the four symbols exported
by the package:
- `@gp`: the *swiss army knife* of the package, it allows to send
command and data to gnuplot, and produce very complex plots;
- `@gpi`: very similar to `@gp`, but it allows to build a plot in
several calls, rather than a single `@gp` call;
- `@gp_str`: run simple gnuplot commands
using
[non-standard string literal](https://docs.julialang.org/en/stable/manual/strings/#non-standard-string-literals-1),
e.g.
``` Julia
gp"print GPVAL_TERM"
```
- `@gp_cmd`: load a gnuplot script file using a non-standard string literal, e.g.
``` Julia
gp`test.gp`
```
The last two macros are supposed to be used only in the REPL, not in
Julia function. As you can see there is not much more to know before
starting *gnuplotting*!
Clearly, the **Gnuplot.jl** hides much more under the hood. The
documentation for each of this function can be retrieved with the
`@doc` macro or by typing `?` in the REPL followed by the function
name.
Now let's discuss some more advanced usage: fit the data (with
gnuplot) and overplot the results.
``` Julia
const gp = Gnuplot # use an alias for the package name to quickly
# access non exported symbols.
@ -72,8 +119,7 @@ gp.plot("f(x) w l lw 2 t 'Fit'")
(a, b, c) = parse.(Float64, gp.getVal("a", "b", "c"))
# Add param. values in the title and the Y label
gp.cmd(title="Fit param: " * @sprintf("a=%5.2f, b=%5.2f, c=%5.2f", a, b ,c),
ylab="Y label")
gp.cmd(title="Fit param: " * @sprintf("a=%5.2f, b=%5.2f, c=%5.2f", a, b ,c))
# Refresh the plot
gp.dump()
@ -92,7 +138,7 @@ gp.dump()
m = a * sin.(b + c * x)
# Start a new gnuplot process and plot again using the @gp macro.
@gp("set key horizontal",
@gp("set key horizontal", "set grid",
:multi, "layout 2,1",
title="Fit param: " * @sprintf("a=%5.2f, b=%5.2f, c=%5.2f", a, b ,c),
ylab="Y label",
@ -114,22 +160,3 @@ any other program.
similar to gaston
Work in progress...
Examples:
Multiplot:
Multiple instaces:
Documentation:
? at the repl or use the `@doc` macro
AbbrvKW (si puo scaricare la versione master?)

View File

@ -1,2 +1 @@
julia 0.6
AbbrvKW

View File

@ -1,10 +1,8 @@
module Gnuplot
using AbbrvKW
include("GnuplotInternals.jl")
importall .p_
import .p_.@AbbrvKW
######################################################################
# Get/set options

View File

@ -6,6 +6,156 @@ module p_
importall Gnuplot
const P_ = Gnuplot
import StatsBase.countmap
function findAbbrv(symLong::Vector{Symbol})
if length(symLong) == 0
return symLong
end
out = Dict()
for sym in symLong
out[sym] = Vector{Symbol}()
end
symAbbr = deepcopy(symLong)
symStr = convert.(String, symLong)
kwCount = length(symLong)
# Max length of string representation of keywords
maxLen = maximum(length.(symStr))
# Identify all abbreviations
for len in 1:maxLen
for i in 1:kwCount
s = symStr[i]
if length(s) >= len
s = s[1:len]
push!(symLong, symLong[i])
push!(symAbbr, convert(Symbol, s))
push!(symStr , s)
end
end
end
symStr = nothing # no longer needed
# Identify unique abbreviations
abbrCount = 0
for (sym, count) in countmap(symAbbr)
if count == 1
i = find(symAbbr .== sym)
@assert length(i) == 1
i = i[1]
if symLong[i] != symAbbr[i]
push!(out[symLong[i]], symAbbr[i])
abbrCount += 1
end
end
end
for (key, val) in out
sort!(out[key])
end
return (out, abbrCount)
end
macro AbbrvKW(func)
@assert func.head == :function "Not a function"
if length(func.args[1].args) <= 1
# Empty parameter list"
return esc(func)
end
if (typeof(func.args[1].args[2]) != Expr) ||
(func.args[1].args[2].head != :parameters)
# No keywords given
return esc(func)
end
sym = Vector{Symbol}() # Symbol, long version
typ = Dict() # Data type
splat = Symbol()
splatFound = false
for k in func.args[1].args[2].args
@assert typeof(k) == Expr "Expr expected"
@assert k.head in (:kw, :(...)) "Expected :kw or :..., got $(k.head)"
#dump(k)
if k.head == :kw
@assert typeof(k.args[1]) in (Expr, Symbol) "Expected Expr or Symbol"
if typeof(k.args[1]) == Symbol
push!(sym, k.args[1])
typ[sym[end]] = :Any
elseif typeof(k.args[1]) == Expr
@assert k.args[1].head == :(::) "Expected :(::), got $(k.args[1].head)"
push!(sym, k.args[1].args[1])
typ[sym[end]] = k.args[1].args[2]
end
elseif k.head == :(...)
splat = k.args[1]
splatFound = true
end
end
# Find abbreviations
(abbr, count) = findAbbrv(sym)
if count == 0
# No abbreviations found
return esc(func)
end
# Add a splat variable if not present
if !splatFound
splat = :_abbrvkw_
a = :($splat...)
a = a.args[1]
push!(func.args[1].args[2].args, a)
a = nothing
end
# Build output Expr
expr = Expr(:block)
push!(expr.args, :(_ii_ = 1))
push!(expr.args, Expr(:while, :(_ii_ <= length($splat)), Expr(:block)))
for (sym, tup) in abbr
length(tup) > 0 || continue
tup = tuple(tup...)
push!(expr.args[end].args[end].args,
:(
if $(splat)[_ii_][1] in $tup
typeassert($(splat)[_ii_][2], $(typ[sym]))
$(sym) = $(splat)[_ii_][2]
deleteat!($splat, _ii_)
continue
end
))
end
push!(expr.args[end].args[end].args, :(_ii_ += 1))
push!(expr.args, :(_ii_ = nothing))
if !splatFound
push!(expr.args, :(if length($splat) !=0 ;
error("Unrecognized keyword abbreviation(s): " * string($splat))
end))
push!(expr.args, :($splat = nothing))
end
@assert length(func.args) == 2 "Function Expr has " * string(length(func.args)) * " args"
@assert func.args[2].head == :block "Function block is not a block, but " * string(func.args[2].head)
prepend!(func.args[2].args, [expr])
#@show func
return esc(func)
end
######################################################################
# Structure definitions
######################################################################