Skip to content

Commit 1e9e1b9

Browse files
committed
Refactor comma lists to plots and splots
1 parent e02bbdb commit 1e9e1b9

File tree

7 files changed

+126
-40
lines changed

7 files changed

+126
-40
lines changed

README.md

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,17 @@ The command string sent (`_cmd` above) can be manually inspected should the char
5252
Write two datasets to a PNG file:
5353

5454
```elixir
55-
alias Gnuplot, as: G
55+
import Gnuplot
5656

57-
{:ok, _cmd} = G.plot([
58-
[:set, :term, :png],
57+
{:ok, _cmd} = plot([
58+
[:set, :term, :pngcairo],
5959
[:set, :output, "/tmp/rand.png"]
6060
[:set, :title, "rand uniform vs normal"],
6161
[:set, :key, :left, :top],
62-
[:plot,
63-
G.list(
62+
plots([
6463
["-", :title, "uniform", :with, :points],
65-
["-", :title, "normal", :with, :points])]
64+
["-", :title, "normal", :with, :points]
65+
])
6666
],
6767
[
6868
for(n <- 0..100, do: [n, n * :rand.uniform()]),
@@ -72,7 +72,9 @@ alias Gnuplot, as: G
7272

7373
![uniform-vs-rand](docs/rand.PNG)
7474

75-
NB When we are plotting multiple datasets in the same plot we need a comma separated list for the `plot` command which is made here with `G.list([ [...], [...], ... ])`
75+
When we are plotting multiple datasets in the same chart we need a comma separated list for the `plot` command which is made with the `plots`, `splots` or `list` function.
76+
77+
NB the `:png` terminal can also be used but it produces [rougher output](http://www.gnuplotting.org/output-terminals/).
7678

7779

7880
### Plot functions without datasets
@@ -95,6 +97,18 @@ NB [ranges](https://hexdocs.pm/elixir/Range.html) can be used
9597

9698
![rand](docs/atan_sin.PNG)
9799

100+
### Multiplot
101+
102+
The `multiplot` mode places serveral plots on the same page:
103+
104+
```elixir
105+
Gnuplot.plot([
106+
[:set, :multiplot, :layout, '2,1'],
107+
[:plot, 'sin(x)/x'],
108+
[:plot, 'cos(x)']
109+
])
110+
```
111+
98112
## Installation
99113

100114
This library is [available in Hex](https://hex.pm/packages/gnuplot), the package can be installed
@@ -103,7 +117,7 @@ by adding `gnuplot` to your list of dependencies in `mix.exs`:
103117
```elixir
104118
def deps do
105119
[
106-
{:gnuplot, "~> 1.19.88"}
120+
{:gnuplot, "~> 1.19.95"}
107121
]
108122
end
109123
```
@@ -140,8 +154,9 @@ clojure_gui = [1.487, 1.397, 1.400, 1.381, 1.440, 5.784, 49.275]
140154
elixir_gui = [0.005, 0.010, 0.004, 0.059, 0.939, 5.801, 43.464]
141155
elixir_png = [0.002, 0.010, 0.049, 0.040, 0.349, 4.091, 41.521]
142156
ubuntu_t2m = [0.004, 0.002, 0.001, 0.008, 0.211, 1.873, 19.916]
143-
ubuntu_stream = [0.002, 0.001, 0.001, 0.009, 0.204, 1.279, 12.858]
144-
datasets = for ds <- [clojure_gui, elixir_gui, elixir_png, ubuntu_t2m, ubuntu_stream], do: Enum.zip (points, ds)
157+
ubuntu_strm = [0.002, 0.001, 0.001, 0.009, 0.204, 1.279, 12.858]
158+
datasets = for ds <- [clojure_gui, elixir_gui, elixir_png, ubuntu_t2m, ubuntu_strm], do:
159+
Enum.zip(points, ds)
145160

146161
Gnuplot.plot([
147162
[:set, :title, "Time to render scatter plots"],
@@ -155,14 +170,15 @@ Gnuplot.plot([
155170
~w(set style line 3 lw 2 lc '#5E2750')a,
156171
~w(set style line 4 lw 2 lc '#E95420')a,
157172
~w(set style line 5 lw 4 lc '#77216F')a,
158-
[:plot, Gnuplot.list(
173+
Gnuplot.plots([
159174
["-", :title, "Clojure GUI", :with, :lines, :ls, 1],
160175
["-", :title, "Elixir GUI", :with, :lines, :ls, 2],
161176
["-", :title, "Elixir PNG", :with, :lines, :ls, 3],
162177
["-", :title, "Elixir t2.m", :with, :lines, :ls, 4],
163178
["-", :title, "Elixir Stream", :with, :lines, :ls, 5]
164-
)]], datasets
165-
])
179+
])],
180+
datasets
181+
)
166182
```
167183

168184
## Credits and licence

examples/perf.exs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule Perf do
2-
alias Gnuplot, as: G
2+
import Gnuplot
33

44
@moduledoc false
55

@@ -24,16 +24,13 @@ defmodule Perf do
2424
~w(set style line 3 lw 2 lc '#5E2750')a,
2525
~w(set style line 4 lw 2 lc '#E95420')a,
2626
~w(set style line 5 lw 4 lc '#77216F')a,
27-
[
28-
:plot,
29-
G.list(
30-
["-", :title, "Clojure GUI", :with, :lines, :ls, 1],
31-
["-", :title, "Elixir GUI", :with, :lines, :ls, 2],
32-
["-", :title, "Elixir PNG", :with, :lines, :ls, 3],
33-
["-", :title, "Elixir t2.m", :with, :lines, :ls, 4],
34-
["-", :title, "Elixir Stream", :with, :lines, :ls, 5]
35-
)
36-
]
27+
plots([
28+
["-", :title, "Clojure GUI", :with, :lines, :ls, 1],
29+
["-", :title, "Elixir GUI", :with, :lines, :ls, 2],
30+
["-", :title, "Elixir PNG", :with, :lines, :ls, 3],
31+
["-", :title, "Elixir t2.m", :with, :lines, :ls, 4],
32+
["-", :title, "Elixir Stream", :with, :lines, :ls, 5]
33+
])
3734
]
3835

3936
def data do
@@ -48,8 +45,8 @@ defmodule Perf do
4845
do: Enum.zip(points, ds)
4946
end
5047

51-
def plot, do: G.plot(target() ++ commands(), data())
48+
def draw, do: plot(target() ++ commands(), data())
5249
end
5350

5451
# mix run examples/perf.exs
55-
Perf.plot()
52+
{:ok, _} = Perf.draw()

examples/rand.exs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
defmodule Rand do
2-
alias Gnuplot, as: G
2+
import Gnuplot
33

44
@moduledoc false
55

@@ -16,13 +16,10 @@ defmodule Rand do
1616
~w(set key left top)a,
1717
~w(set style line 1 lc rgb '#77216F' pt 13)a,
1818
~w(set style line 2 lc rgb '#599B2B' pt 2)a,
19-
[
20-
:plot,
21-
G.list(
22-
["-", :title, "uniform", :with, :points, :ls, 1],
23-
["-", :title, "normal", :with, :points, :ls, 2]
24-
)
25-
]
19+
plots([
20+
["-", :title, "uniform", :with, :points, :ls, 1],
21+
["-", :title, "normal", :with, :points, :ls, 2]
22+
])
2623
]
2724

2825
def data,
@@ -31,8 +28,8 @@ defmodule Rand do
3128
for(n <- 0..99, do: [n, n * :rand.normal()])
3229
]
3330

34-
def plot, do: G.plot(target() ++ commands(), data())
31+
def draw, do: plot(target() ++ commands(), data())
3532
end
3633

3734
# mix run examples/rand.exs
38-
Rand.plot()
35+
{:ok, _} = Rand.draw()

lib/gnuplot.ex

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,53 @@ defmodule Gnuplot do
6666
|> Stream.run()
6767
end
6868

69+
@doc """
70+
Builds a comma separated list of plot commands that are overlayed in a single plot.
71+
72+
Only useful inside `plot/1`:
73+
74+
import Gnuplot
75+
76+
plot([
77+
[:set, :title, "Sine vs Cosine"],
78+
plots([
79+
['sin(x)'],
80+
['cos(x)']
81+
])
82+
])
83+
84+
is equivalent to:
85+
86+
set title "Sine vs Cosine"
87+
plot sin(x),cos(x)
88+
89+
"""
90+
@spec plots(list(command())) :: list()
91+
def plots(commands) do
92+
[:plot, list(commands)]
93+
end
94+
95+
@doc """
96+
Build a comma separated list of two or more overlayed 3D plots (as 2D projections).
97+
98+
Only useful inside `plot/1`:
99+
100+
import Gnuplot
101+
102+
plot([
103+
[:set, :grid],
104+
splots([
105+
['x**2+y**2'],
106+
['x**2-y**2']
107+
])
108+
])
109+
110+
"""
111+
@spec splots(list(command())) :: list()
112+
def splots(commands) do
113+
[:splot, list(commands)]
114+
end
115+
69116
@doc "Build a comma separated list from a list of terms."
70117
def list(xs) when is_list(xs), do: %Commands.List{xs: xs}
71118

lib/gnuplot/dataset.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Gnuplot.Dataset do
22
@moduledoc false
33

4-
@type point :: list(number()) | tuple()
4+
@type point :: list(number() | String.t()) | tuple()
55
@type t :: list(point())
66

77
@gnuplot_end_row "\n"
@@ -37,6 +37,7 @@ defmodule Gnuplot.Dataset do
3737

3838
defp to_str(f) when is_float(f), do: Float.to_string(f)
3939
defp to_str(i) when is_integer(i), do: Integer.to_string(i)
40+
4041
defp to_str(s) when is_binary(s) do
4142
if contains_space?(s) do
4243
"\"" <> s <> "\""

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule Gnuplot.MixProject do
44
def project do
55
[
66
app: :gnuplot,
7-
version: "1.19.88",
7+
version: "1.19.95",
88
elixir: "~> 1.6",
99
start_permanent: Mix.env() == :prod,
1010
description: "Interface between Elixir and Gnuplot graphing library",

test/gnuplot_test.exs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,45 @@ defmodule GnuplotTest do
7777
plot = [
7878
[:set, :xrange, -3..3],
7979
[:set, :yrange, -3..3],
80-
[:splot, 'sin(x) * cos(y)']
80+
G.splots([['x**2+y**2'], ['x**2-y**2']])
8181
]
8282

83-
expected = "set xrange [-3:3];\nset yrange [-3:3];\nsplot sin(x) * cos(y)"
83+
expected = "set xrange [-3:3];\nset yrange [-3:3];\nsplot x**2+y**2,x**2-y**2"
8484
assert {:ok, expected} == G.plot(plot)
8585
end
8686

8787
test "Strings with spaces in datasets" do
8888
input = [[0, "label", 100], [1, "label2", 450], [2, "bar label", 75]]
8989
expected = ["0 label 100", "\n", "1 label2 450", "\n", "2 \"bar label\" 75", "\ne\n"]
90+
9091
assert expected ==
9192
[input] |> D.format_datasets() |> Enum.to_list()
9293
end
94+
95+
test "Multiplot with two plot(s)" do
96+
input = [[:set, :multiplot, :layout, '2,1'], [:plot, 'sin(x)'], [:plot, 'cos(x)']]
97+
expected = "set multiplot layout 2,1;\nplot sin(x);\nplot cos(x)"
98+
99+
assert expected == C.format(input)
100+
end
101+
102+
test "Multiplot with plots" do
103+
input = [[:set, :multiplot, :layout, '2,1'], G.plots([['sin(x)'], ['cos(x)']])]
104+
expected = "set multiplot layout 2,1;\nplot sin(x),cos(x)"
105+
106+
assert expected == C.format(input)
107+
end
108+
109+
test "Multiplot with list" do
110+
input = [[:set, :multiplot, :layout, '2,1'], [:plot, G.list([['sin(x)'], ['cos(x)']])]]
111+
expected = "set multiplot layout 2,1;\nplot sin(x),cos(x)"
112+
113+
assert expected == C.format(input)
114+
end
115+
116+
test "Splots" do
117+
input = G.splots([['x**2+y**2'], ['x**2-y**2']])
118+
expected = "splot x**2+y**2,x**2-y**2"
119+
assert expected == C.format([input])
120+
end
93121
end

0 commit comments

Comments
 (0)