forked from GiovineItalia/Gadfly.jl
/
poetry.jl
162 lines (131 loc) · 3.65 KB
/
poetry.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# Particularly useful or beautiful grammar of graphics invocations.
## Return a DataFrame with x, y column suitable for plotting a function.
#
# Args:
# f: Function/Expression to be evaluated.
# a: Lower bound.
# b: Upper bound.
# n: Number of points to evaluate the function at.
#
# Returns:
# A data frame with "x" and "f(x)" columns.
#
function evalfunc(f::Function, a, b, n)
@assert n > 1
step = (b - a) / (n - 1)
xs = Array(typeof(a + step), n)
for i in 1:n
xs[i] = a + (i-1) * step
end
df = DataFrame(xs, map(f, xs))
# NOTE: 'colnames!' is the older deprecated name. 'names!' was also defined
# but threw an error.
try
names!(df, [:x, :f_x])
catch
colnames!(df, ["x", "f_x"])
end
df
end
evalfunc(f::Expr, a, b, n) = evalfunc(eval(:(x -> $f)), a, b, n)
# Create a dataframe and mapping from a list of functions or expressions.
function datafy(fs::Array, a, b)
df = DataFrame()
name_levels = ASCIIString[]
for (i, f) in enumerate(fs)
df_i = evalfunc(f, a, b, 250)
name = typeof(f) == Expr ? string(f) : @sprintf("f<sub>%d</sub>", i)
try
df_i[:f] = fill(name, size(df_i, 1))
catch
df_i["f"] = fill(name, size(df_i, 1))
end
push!(name_levels, name)
df = vcat(df, df_i)
end
df[:f] = PooledDataArray(df[:f], name_levels)
mapping = {:x => "x", :y => "f_x"}
if length(fs) > 1
mapping[:color] = "f"
end
df, mapping
end
# A convenience plot function for quickly plotting functions or expressions.
#
# Args:
# fs: An array in which each object is either a single argument function or an
# expression computing some value on x.
# a: Lower bound on x.
# b: Upper bound on x.
# elements: One ore more grammar elements.
#
# Returns:
# A plot objects.
#
function plot(fs::Array, a, b, elements::ElementOrFunction...; mapping...)
df, mappingdict = datafy(fs, a, b)
for (k, v) in mapping
mappingdict[k] = v
end
if b < a
if isempty(elements)
elements = ElementOrFunction[]
end
push!(elements, Coord.cartesian(xflip=true))
end
plot(df, mappingdict, Geom.line, Guide.ylabel("f(x)"), elements...)
end
# Plot a single function.
function plot(f::Function, a, b, elements::ElementOrFunction...; mapping...)
plot([f], a, b, elements...; mapping...)
end
# Plot a single expression.
function plot(f::Expr, a, b, elements::ElementOrFunction...; mapping...)
plot([f], a, b, elements...; mapping...)
end
# Plot an expression from a to b.
macro plot(expr, a, b)
quote
plot(x -> $(expr), $(a), $(b))
end
end
# Create a layer from a list of functions or expressions.
function layer(fs::Array, a, b)
df, mapping = datafy(fs, a, b)
layer(df, Stat.nil(), Geom.line; mapping...)
end
# Create a layer from a single function.
function layer(f::Function, a, b)
layer([f], a, b)
end
# Create a layer from a single expression.
function layer(f::Expr, a, b)
layer([f], a, b)
end
# Create a layer from an expression from a to b.
macro layer(expr, a, b)
quote
layer(x -> $(expr), $(a), $(b))
end
end
# Simple heatmap plots of matrices.
#
# Args:
# M: A matrix.
#
# Returns:
# A plot object.
#
function spy(M::AbstractMatrix, elements::ElementOrFunction...; mapping...)
is, js, values = findnz(M)
df = DataFrame(i=is, j=js, value=values)
plot(df, x="j", y="i", color="value",
Coord.cartesian(yflip=true),
Scale.continuous_color,
Scale.x_discrete,
Scale.y_discrete,
Geom.rectbin,
Stat.identity,
elements...;
mapping...)
end