├── .gitignore
├── LICENSE
├── README.md
├── config
└── config.exs
├── examples
├── README.md
├── acorr.exs
├── bar.exs
├── histogram.exs
├── spectrum.exs
├── title.exs
└── zorder.exs
├── images
├── bar.png
├── histogram.png
├── subplots.png
└── zorder.png
├── lib
├── codebuilder
│ └── codebuilder.ex
├── expyplot.ex
├── plot.ex
└── server
│ ├── commapi.ex
│ ├── export.ex
│ ├── pycomm.ex
│ ├── pyserver.ex
│ └── pysupervisor.ex
├── mix.exs
├── priv
└── mat.py
└── test
├── expyplot_test.exs
├── expyplotplot_test.exs
└── test_helper.exs
/.gitignore:
--------------------------------------------------------------------------------
1 | /_build
2 | /cover
3 | /deps
4 | erl_crash.dump
5 | *.ez
6 | *.swp
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Max Strange
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Expyplot
2 |
3 | Inspired by this project:
4 | https://github.com/JordiPolo/explot, but I wanted something more transparent.
5 |
6 | Documentation can be found at [https://hexdocs.pm/expyplot](https://hexdocs.pm/expyplot).
7 |
8 | Expyplot allows you to use 'all' of the functions in matplotlib.pyplot (in reality, there are some that I left out because they don't make any sense in this context, or
9 | are deprecated).
10 |
11 | Unfortunately, I have not tested anywhere near all of the functions, but they should mostly work. If any don't work, please open an issue, or better yet,
12 | make a fix and open a pull request! This library is simple enough that you should be able to grok it without too much effort.
13 |
14 | Perhaps the most limiting thing about this library is that it currently has to convert return values from the matplotlib functions into strings before
15 | sending them back to Elixir, so rather than returning `true`, you will get `"True"`, and good luck piecing back to gether complicated objects. The reason I went this route
16 | is that JSON is unable to parse pretty much any complicated data type that comes back from a matplotlib function, and I didn't feel like writing a JSON parser. If you
17 | want to do something about it, please by all means, write a JSON parser capable of serializing all the different return types from matplotlib functions: the python
18 | side of this library is very simple - it is located in priv/mat.py.
19 |
20 | ## Differences
21 |
22 | Unfortunately (or rather, fortunately if we are celebrating linguistic diversity!), I could not attain complete transparency. This is a list of some notable differences
23 | between this library and the real matplotlib.pyplot:
24 |
25 | - Return values are strings currently
26 | - Variable arguments must be wrapped in a list, so: `plt.plot(a, b)` becomes `Plot.plot([a, b])`, but especially notice: `Plot.plot([[1..10], other_args])`
27 | - Named args and keyword args are atoms: `Plot.grid(b: true)`, though they don't have to be, so: `Plot.plot([[1..10], "r+"])`
28 | - Keyword args that are not keyword only arguments must be written with keywords, you can't do them positionally, so while `plt.grid(True)` works in Python,
29 | you have to name the argument in Elixir: `Plot.grid(b: true)`; if you ever get the error: "argument error: :erlang.++(something, [])", this is the reason. You need
30 | to rewrite the argument list as a keyword list.
31 | - Any keyword argument or named argument that starts with a capital letter needs to be renamed with an underscore: `Fs` -> `:_Fs`
32 |
33 | ## Installation
34 |
35 | You must have python3 installed and in your path
36 |
37 | You must also pip3 install PyQt5 and matplotlib:
38 | `pip3 install PyQt5`, `pip3 install matplotlib`, or however you install packages for python3 on your particular system.
39 |
40 | ```elixir
41 | def deps do
42 | [{:expyplot, "~> 1.1.2"}]
43 | end
44 | ```
45 |
46 | ## Examples
47 |
48 | Examples taken from http://matplotlib.org/examples/pylab_examples and then rewritten in Elixir to use this Expyplot.
49 |
50 | To run the examples, start an iex -S mix session and run:
51 |
52 | ```elixir
53 | Code.load_file "./path/to/example/EXAMPLE.exs"
54 | ```
55 |
56 | ### Histogram
57 |
58 | ```elixir
59 | defmodule HistogramExample do
60 | alias Expyplot.Plot
61 |
62 | {mu, sigma} = {100, 15}
63 | x = 1..10_000 |> Stream.map(fn(_) -> Statistics.Distributions.Normal.rand(mu, sigma) end) |> Enum.to_list
64 |
65 | Plot.hist(x, bins: 50, normed: 1, facecolor: :green, alpha: 0.75)
66 | Plot.xlabel("Smarts")
67 | Plot.ylabel("Probability")
68 | Plot.title("IQ Scores")
69 | Plot.axis_set([40, 160, 0, 0.03])
70 | Plot.grid(b: true)
71 |
72 | Plot.show()
73 | end
74 | ```
75 | 
76 |
77 | ### Subplots
78 |
79 | ```elixir
80 | defmodule SpectralExample do
81 | alias Expyplot.Plot
82 |
83 | dt = 0.01
84 | fs = 1 / dt
85 | t = Stream.unfold(0, fn(acc) -> {acc, acc + dt} end) |> Stream.take_while(&(&1 < 10)) |> Enum.to_list
86 | nse = t |> Enum.map(fn(_) -> Statistics.Distributions.Normal.rand() end) |> Enum.to_list
87 | r = t |> Enum.map(&(Statistics.Math.exp(- &1 / 0.05)))
88 |
89 | cnse = nse |> Enum.map(&(&1 * Enum.random(r))) |> Enum.take(length(t)) # fake convolution. I didn't feel like writing a functional convolution.
90 | s = t |> Enum.map(&(:math.sin(2 * Statistics.Math.pi * &1))) |> Enum.zip(cnse) |> Enum.map(fn {el1, el2} -> el1 + el2 end)
91 |
92 | Plot.subplot([3, 2, 1])
93 | Plot.plot([t, s])
94 |
95 | Plot.subplot([3, 2, 1])
96 | Plot.plot([t, s])
97 |
98 | Plot.subplot([3, 2, 3])
99 | Plot.magnitude_spectrum(s, _Fs: fs)
100 |
101 | Plot.subplot([3, 2, 4])
102 | Plot.magnitude_spectrum(s, _Fs: fs, scale: :dB)
103 |
104 | Plot.subplot([3, 2, 5])
105 | Plot.angle_spectrum(s, _Fs: fs)
106 |
107 | Plot.subplot([3, 2, 6])
108 | Plot.phase_spectrum(s, _Fs: fs)
109 |
110 | Plot.show()
111 | end
112 | ```
113 | 
114 |
115 | ### Zorder/Scatterplots
116 |
117 | ```elixir
118 | defmodule ZorderExample do
119 | alias Expyplot.Plot
120 |
121 | x = 1..20 |> Enum.map(fn(_) -> Statistics.Distributions.Normal.rand() end) |> Enum.to_list
122 | y = 1..20 |> Enum.map(fn(_) -> Statistics.Distributions.Normal.rand() end) |> Enum.to_list
123 |
124 | Plot.figure()
125 | Plot.subplot([2, 1, 1])
126 | Plot.plot([x, y, :r], [lw: 3])
127 | Plot.scatter(x, y, [s: 120])
128 | Plot.title("Lines on top of dots")
129 |
130 | Plot.subplot([2, 1, 2])
131 | Plot.plot([x, y, :r], [zorder: 1, lw: 3])
132 | Plot.scatter(x, y, [s: 120], [zorder: 2])
133 | Plot.title("Dots on top of lines")
134 |
135 | Plot.show()
136 | end
137 | ```
138 | 
139 |
140 | ### Bar Graph
141 |
142 | ```elixir
143 | defmodule BarExample do
144 | alias Expyplot.Plot
145 |
146 | men_means = [20, 35, 30, 35, 27]
147 | women_means = [25, 32, 34, 20, 25]
148 | men_std = [2, 3, 4, 1, 2]
149 | women_std = [3, 5, 2, 3, 3]
150 | ind = 0..4
151 | width = 0.35
152 | yticks = Stream.unfold(0, fn(acc) -> {acc, acc + 10} end) |> Stream.take_while(&(&1 < 81)) |> Enum.to_list
153 |
154 | Plot.bar(ind, men_means, [width: width], color: "#d62728", yerr: men_std, label: "Men")
155 | Plot.bar(ind, women_means, [width: width, bottom: men_means], yerr: women_std, label: "Women")
156 | Plot.ylabel("Scores")
157 | Plot.title("Scores by group and gender")
158 | Plot.xticks([ind, {"G1", "G2", "G3", "G4", "G5"}])
159 | Plot.yticks([yticks])
160 | Plot.legend()
161 | Plot.show()
162 | end
163 | ```
164 | 
165 |
166 |
--------------------------------------------------------------------------------
/config/config.exs:
--------------------------------------------------------------------------------
1 | # This file is responsible for configuring your application
2 | # and its dependencies with the aid of the Mix.Config module.
3 | use Mix.Config
4 |
5 | # This configuration is loaded before any dependency and is restricted
6 | # to this project. If another project depends on this project, this
7 | # file won't be loaded nor affect the parent project. For this reason,
8 | # if you want to provide default values for your application for
9 | # 3rd-party users, it should be done in your "mix.exs" file.
10 |
11 | # You can configure for your application as:
12 | #
13 | # config :expyplot, key: :value
14 | #
15 | # And access this configuration in your application as:
16 | #
17 | # Application.get_env(:expyplot, :key)
18 | #
19 | # Or configure a 3rd-party app:
20 | #
21 | # config :logger, level: :info
22 | #
23 |
24 | # It is also possible to import configuration files, relative to this
25 | # directory. For example, you can emulate configuration per environment
26 | # by uncommenting the line below and defining dev.exs, test.exs and such.
27 | # Configuration from the imported file will override the ones defined
28 | # here (which is why it is important to import them last).
29 | #
30 | # import_config "#{Mix.env}.exs"
31 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | These examples are taken from http://matplotlib.org/1.2.1/examples/pylab_examples and modified.
2 |
3 |
--------------------------------------------------------------------------------
/examples/acorr.exs:
--------------------------------------------------------------------------------
1 | defmodule AcorrExample do
2 | alias Expyplot.Plot
3 |
4 | x = 1..100 |> Enum.map(fn(_) -> Statistics.Distributions.Normal.rand() end)
5 | y = 1..100 |> Enum.map(fn(_) -> Statistics.Distributions.Normal.rand() end)
6 |
7 | Plot.xcorr(x, y, usevlines: true, maxlags: 50, normed: true, lw: 2)
8 | Plot.grid(b: true)
9 | Plot.axhline(y: 0, color: :black, lw: 2)
10 | Plot.show()
11 | end
12 |
--------------------------------------------------------------------------------
/examples/bar.exs:
--------------------------------------------------------------------------------
1 | defmodule BarExample do
2 | alias Expyplot.Plot
3 |
4 | men_means = [20, 35, 30, 35, 27]
5 | women_means = [25, 32, 34, 20, 25]
6 | men_std = [2, 3, 4, 1, 2]
7 | women_std = [3, 5, 2, 3, 3]
8 | ind = 0..4
9 | width = 0.35
10 | yticks = Stream.unfold(0, fn(acc) -> {acc, acc + 10} end) |> Stream.take_while(&(&1 < 81)) |> Enum.to_list
11 |
12 | Plot.bar(ind, men_means, [width: width], color: "#d62728", yerr: men_std, label: "Men")
13 | Plot.bar(ind, women_means, [width: width, bottom: men_means], yerr: women_std, label: "Women")
14 | Plot.ylabel("Scores")
15 | Plot.title("Scores by group and gender")
16 | Plot.xticks([ind, {"G1", "G2", "G3", "G4", "G5"}])
17 | Plot.yticks([yticks])
18 | Plot.legend()
19 | Plot.show()
20 | end
21 |
--------------------------------------------------------------------------------
/examples/histogram.exs:
--------------------------------------------------------------------------------
1 | defmodule HistogramExample do
2 | alias Expyplot.Plot
3 |
4 | {mu, sigma} = {100, 15}
5 | x = 1..10_000 |> Stream.map(fn(_) -> Statistics.Distributions.Normal.rand(mu, sigma) end) |> Enum.to_list
6 |
7 | Plot.hist(x, bins: 50, normed: 1, facecolor: :green, alpha: 0.75)
8 | Plot.xlabel("Smarts")
9 | Plot.ylabel("Probability")
10 | Plot.title("IQ Scores")
11 | Plot.axis_set([40, 160, 0, 0.03])
12 | Plot.grid(b: true)
13 |
14 | Plot.show()
15 | end
16 |
--------------------------------------------------------------------------------
/examples/spectrum.exs:
--------------------------------------------------------------------------------
1 | defmodule SpectralExample do
2 | alias Expyplot.Plot
3 |
4 | dt = 0.01
5 | fs = 1 / dt
6 | t = Stream.unfold(0, fn(acc) -> {acc, acc + dt} end) |> Stream.take_while(&(&1 < 10)) |> Enum.to_list
7 | nse = t |> Enum.map(fn(_) -> Statistics.Distributions.Normal.rand() end) |> Enum.to_list
8 | r = t |> Enum.map(&(Statistics.Math.exp(- &1 / 0.05)))
9 |
10 | cnse = nse |> Enum.map(&(&1 * Enum.random(r))) |> Enum.take(length(t)) # fake convolution. I didn't feel like writing a functional convolution.
11 | s = t |> Enum.map(&(:math.sin(2 * Statistics.Math.pi * &1))) |> Enum.zip(cnse) |> Enum.map(fn {el1, el2} -> el1 + el2 end)
12 |
13 | Plot.subplot([3, 2, 1])
14 | Plot.plot([t, s])
15 |
16 | Plot.subplot([3, 2, 1])
17 | Plot.plot([t, s])
18 |
19 | Plot.subplot([3, 2, 3])
20 | Plot.magnitude_spectrum(s, _Fs: fs)
21 |
22 | Plot.subplot([3, 2, 4])
23 | Plot.magnitude_spectrum(s, _Fs: fs, scale: :dB)
24 |
25 | Plot.subplot([3, 2, 5])
26 | Plot.angle_spectrum(s, _Fs: fs)
27 |
28 | Plot.subplot([3, 2, 6])
29 | Plot.phase_spectrum(s, _Fs: fs)
30 |
31 | Plot.show()
32 | end
33 |
34 |
35 |
--------------------------------------------------------------------------------
/examples/title.exs:
--------------------------------------------------------------------------------
1 | defmodule TitleExample do
2 | alias Expyplot.Plot
3 |
4 | Plot.plot([1..10])
5 | Plot.title("Center Title")
6 | Plot.title("Left Title", [], [loc: :left])
7 | Plot.title("Right Title", [], [loc: :right])
8 |
9 | Plot.show()
10 | end
11 |
--------------------------------------------------------------------------------
/examples/zorder.exs:
--------------------------------------------------------------------------------
1 | defmodule ZorderExample do
2 | alias Expyplot.Plot
3 |
4 | x = 1..20 |> Enum.map(fn(_) -> Statistics.Distributions.Normal.rand() end) |> Enum.to_list
5 | y = 1..20 |> Enum.map(fn(_) -> Statistics.Distributions.Normal.rand() end) |> Enum.to_list
6 |
7 | Plot.figure()
8 | Plot.subplot([2, 1, 1])
9 | Plot.plot([x, y, :r], [lw: 3])
10 | Plot.scatter(x, y, [s: 120])
11 | Plot.title("Lines on top of dots")
12 |
13 | Plot.subplot([2, 1, 2])
14 | Plot.plot([x, y, :r], [zorder: 1, lw: 3])
15 | Plot.scatter(x, y, [s: 120], [zorder: 2])
16 | Plot.title("Dots on top of lines")
17 |
18 | Plot.show()
19 | end
20 |
--------------------------------------------------------------------------------
/images/bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaxStrange/expyplot/b11b8d7d14af1693ab374274b6e9500cf85959e7/images/bar.png
--------------------------------------------------------------------------------
/images/histogram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaxStrange/expyplot/b11b8d7d14af1693ab374274b6e9500cf85959e7/images/histogram.png
--------------------------------------------------------------------------------
/images/subplots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaxStrange/expyplot/b11b8d7d14af1693ab374274b6e9500cf85959e7/images/subplots.png
--------------------------------------------------------------------------------
/images/zorder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaxStrange/expyplot/b11b8d7d14af1693ab374274b6e9500cf85959e7/images/zorder.png
--------------------------------------------------------------------------------
/lib/codebuilder/codebuilder.ex:
--------------------------------------------------------------------------------
1 | defmodule Codebuilder do
2 | @moduledoc """
3 | This module holds the functions that translate Elixir function calls into Python function calls.
4 | """
5 |
6 | def build_code(funcname: name, nonnamed: args, named: namedargs) do
7 | args_string = args |> Enum.map(&stringify_variable/1) |> Enum.reduce("", fn(x, acc) -> acc <> ", " <> x end)
8 | args_string = if String.ends_with?(args_string, ", "), do: String.slice(args_string, 0..-3), else: args_string
9 | args_string = if String.starts_with?(args_string, ", "), do: String.slice(args_string, 2..-1), else: args_string
10 | namedargs_string = namedargs |> Enum.map(&stringify_namedarg/1) |> Enum.reduce("", fn(x, acc) -> acc <> ", " <> x end)
11 | namedargs_string = if String.ends_with?(namedargs_string, ", "), do: String.slice(namedargs_string, 0..-3), else: namedargs_string
12 | namedargs_string = if String.starts_with?(namedargs_string, ", "), do: String.slice(namedargs_string, 2..-1), else: namedargs_string
13 |
14 | if String.length(args_string) > 0 and String.length(namedargs_string) > 0 do
15 | "\n" <> name <> "(" <> args_string <> ", " <> namedargs_string <> ")"
16 | else
17 | "\n" <> name <> "(" <> args_string <> namedargs_string <> ")"
18 | end
19 | end
20 |
21 | ## These functions take a variable and turn it into its Python representation, then into a string from there
22 | defp stringify_variable(v) when is_boolean(v), do: if v, do: "True", else: "False"
23 | defp stringify_variable(v) when is_atom(v), do: if v == nil, do: "None", else: "\"" <> Atom.to_string(v) <> "\""
24 | defp stringify_variable(v) when is_binary(v), do: "\"" <> v <> "\""
25 | defp stringify_variable(v) when is_float(v), do: Float.to_string v
26 | defp stringify_variable(v) when is_integer(v), do: Integer.to_string v
27 | defp stringify_variable(v) when is_list(v) do
28 | list_as_str = v |> Enum.reduce("", fn (x, acc) -> acc <> ", " <> stringify_variable(x) end)
29 | list_as_str = if String.ends_with?(list_as_str, ", "), do: String.slice(list_as_str, 0..-3), else: list_as_str
30 | list_as_str = if String.starts_with?(list_as_str, ", "), do: String.slice(list_as_str, 2..-1), else: list_as_str
31 | "[" <> list_as_str <> "]"
32 | end
33 | defp stringify_variable(v) when is_map(v) do
34 | impl = Enumerable.impl_for v
35 | case impl do
36 | Enumerable.Range ->
37 | # Turns out that streams are maps, who'd have thunk it?
38 | v |> Enum.to_list |> stringify_variable
39 | Enumerable.Map ->
40 | dict_as_str = v |> Enum.reduce("", fn({name, val}, acc) -> acc <> ", " <> stringify_variable(name) <> ": " <> stringify_variable(val) end)
41 | dict_as_str = if String.starts_with?(dict_as_str, ", "), do: String.slice(dict_as_str, 2..-1), else: dict_as_str
42 | "{" <> dict_as_str <> "}"
43 | end
44 | end
45 | defp stringify_variable(v) when is_tuple(v) do
46 | list_as_str = v |> Tuple.to_list |> Enum.reduce("", fn (x, acc) -> acc <> ", " <> stringify_variable(x) end)
47 | list_as_str = if String.ends_with?(list_as_str, ", "), do: String.slice(list_as_str, 0..-3), else: list_as_str
48 | list_as_str = if String.starts_with?(list_as_str, ", "), do: String.slice(list_as_str, 2..-1), else: list_as_str
49 | "(" <> list_as_str <> ")"
50 | end
51 | defp stringify_variable(_) do
52 | raise ArgumentError, message: "Type not supported for serialization."
53 | end
54 |
55 | defp stringify_namedarg({name, val}) do
56 | name = Atom.to_string name
57 | name = if String.starts_with?(name, "_"), do: String.slice(name, 1..-1), else: name
58 | name <> "=" <> stringify_variable(val)
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/lib/expyplot.ex:
--------------------------------------------------------------------------------
1 | defmodule Expyplot do
2 | use Application
3 | @moduledoc """
4 | This is the supervisor that runs the application.
5 | For now, this module doesn't really do anything else.
6 | """
7 |
8 | def start(_type, _args) do
9 | Server.Pysupervisor.start_link
10 | connect_to_python()
11 | end
12 |
13 | defp connect_to_python do
14 | result = Server.Commapi.start_link
15 | case result do
16 | {:ok, pid} -> {:ok, pid}
17 | {:error, {:shutdown, {:failed_to_start_child, Server.Pycomm, {:bad_return_value, {:error, :econnrefused}}}}} -> connect_to_python()
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/plot.ex:
--------------------------------------------------------------------------------
1 | defmodule Expyplot.Plot do
2 | @moduledoc """
3 | This is the end-user API for pyplot.
4 |
5 | See the matplotlib.plot docs at:
6 | http://matplotlib.org/api/pyplot_api.html
7 |
8 | Most of these functions are UNTESTED. I know. That's terrible. But you can test them by using them! Then, if they don't work, open an issue on the github:
9 | https://github.com/MaxStrange/expyplot/issues
10 |
11 | Or better yet, you could write some tests or a patch and open a pull request!
12 |
13 | Also, since the return values are simply the string representations of whatever was returned to the python server, all of the return values
14 | will need to be converted into actual Elixir datastructures. I would love to get around to changing this behavior in the future, but for now, it is
15 | as it is. This also means that numpy arrays that are returned are likely to be truncated.
16 |
17 | This documentation is mostly just copied from the matplotlib.plot docs, and much of it isn't translated to Elixir like it should be.
18 | """
19 |
20 | @doc """
21 | Plot the autocorrelation of x.
22 | """
23 | def acorr(x, opts \\ [hold: nil, data: nil], kwargs \\ []) do
24 | Codebuilder.build_code(funcname: "plt.axis", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
25 | end
26 |
27 | @doc """
28 | Plot the angle spectrum.
29 |
30 | Compute the angle spectrum (wrapped phase spectrum) of x. Data is padded to a length of pad_to and the windowing function window Not used yet
31 | in Expyplot is applied to the signal.
32 |
33 | Example call:
34 |
35 | ```elixir
36 | 1..1_000_000 |> Enum.to_list |> Expyplot.Plot.angle_spectrum(x, [_Fs: 2, _Fc: 0, pad_to: nil, sides: "default"])
37 | ```
38 | """
39 | def angle_spectrum(x, opts \\ [_Fs: 2, _Fc: 0, pad_to: nil, sides: :default], kwargs \\ []) do
40 | Codebuilder.build_code(funcname: "plt.angle_spectrum", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
41 | end
42 |
43 | @doc """
44 | Annotate the point xy with text s.
45 |
46 | Additional kwargs are passed to Text.
47 | """
48 | def annotate(opts \\ [], kwargs \\ []) do
49 | Codebuilder.build_code(funcname: "plt.annotate", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
50 | end
51 |
52 | @doc """
53 | Add an arrow to the axes.
54 |
55 | Draws arrow on specified axis from (x, y) to (x + dx, y + dy). Uses FancyArrow patch to construct the arrow.
56 | """
57 | def arrow(x, y, dx, dy, opts \\ [hold: nil], kwargs \\ []) do
58 | Codebuilder.build_code(funcname: "plt.arrow", nonnamed: [x, y, dx, dy], named: opts ++ kwargs) |> Server.Commapi.add_code
59 | end
60 |
61 | @doc """
62 | Autoscale the axis view to the data (toggle).
63 |
64 | Convenience method for simple axis view autoscaling. It turns autoscaling on or off, and then, if autoscaling for either axis is on, it
65 | performs the autoscaling on the specified axis or axes.
66 | """
67 | def autoscale(opts \\ [enable: true, axis: :both, tight: nil]) do
68 | Codebuilder.build_code(funcname: "plt.autoscale", nonnamed: [], named: opts) |> Server.Commapi.add_code
69 | end
70 |
71 | @doc """
72 | Set the default colormap to autumn and apply to current image if any. See help(colormaps) for more information
73 | """
74 | def autumn do
75 | Codebuilder.build_code(funcname: "plt.autumn", nonnamed: [], named: []) |> Server.Commapi.add_code
76 | end
77 |
78 | @doc """
79 | Add an axes to the figure.
80 |
81 | The axes is added at position rect specified by:
82 |
83 | - axes() by itself creates a default full subplot(111) window axis.
84 | - axes(rect, [facecolor: :w]), where rect = [left, bottom, width, height] in normalized (0, 1) units. facecolor is the background
85 | color for the axis, default white.
86 | - axes(h) where h is an axes instance makes h the current axis.
87 | """
88 | def axes(opts \\ [], kwargs \\ []) do
89 | Codebuilder.build_code(funcname: "plt.axes", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
90 | end
91 |
92 | @doc """
93 | Add a horizontal line across the axis.
94 |
95 | Typical calls:
96 | ```elixir
97 | Expyplot.Plot.axhline(linewidth: 4, color: :r) # Draw a thick red hline at 'y'=0 that spans the xrange
98 | Expyplot.Plot.axhline(y: 1) # Draw a default hline at 'y'=1 that spans the xrange
99 | Expyplot.Plot.axhline(y: 0.5, xmin: 0.25, xmax: 0.75) # Draw a default hline at 'y'=0.5 that spans the middle half of the xrange
100 | ```
101 | """
102 | def axhline(opts \\ [y: 0, xmin: 0, xmax: 1, hold: nil], kwargs \\ []) do
103 | Codebuilder.build_code(funcname: "plt.axhline", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
104 | end
105 |
106 | @doc """
107 | Add a horizontal span (rectangle) across the axis.
108 |
109 | Draw a horizontal span (rectangle) from ymin to ymax. With the default values of xmin = 0 and xmax = 1, this always spans the xrange,
110 | regardless of the xlim settings, even if you change them, e.g., with the set_xlim() command. That is, the horizontal extent is in axes
111 | coords: 0=left, 0.5=middle, 1.0=right but the y location is in data coordinates.
112 | """
113 | def axhspan(ymin, ymax, opts \\ [xmin: 0, xmax: 1, hold: nil], kwargs \\ []) do
114 | Codebuilder.build_code(funcname: "plt.axhspan", nonnamed: [ymin, ymax], named: opts ++ kwargs) |> Server.Commapi.add_code
115 | end
116 |
117 | @doc """
118 | This is how axis has been implemented in this library: as two functions - a get and a set, rather than just the one
119 | Convenience method to get or set axis properties.
120 |
121 | This function is of limited usefulness at this stage, as it simply returns the string representation of the current axis.
122 |
123 | iex> Expyplot.Plot.axis_get()
124 | "(0.0, 1.0, 0.0, 1.0)"
125 |
126 | """
127 | def axis_get(kwargs \\ []) do
128 | Codebuilder.build_code(funcname: "plt.axis", nonnamed: [], named: kwargs) |> Server.Commapi.add_code
129 | end
130 |
131 | @doc """
132 | This is how axis has been implemented in this library: as two functions - a get and a set, rather than just the one
133 | Convenience method to get or set axis properties.
134 |
135 | ## Some examples:
136 |
137 | iex> Expyplot.Plot.axis_set("off") # Turn off the axis lines and labels
138 | "(0.0, 1.0, 0.0, 1.0)"
139 |
140 | iex> Expyplot.Plot.axis_set("equal") # Changes limits of x and y axis so that equal increments of x and y have the same length
141 | "(-0.055, 0.055, -0.055, 0.055)"
142 |
143 | """
144 | def axis_set(v, kwargs \\ []) do
145 | Codebuilder.build_code(funcname: "plt.axis", nonnamed: [v], named: kwargs) |> Server.Commapi.add_code
146 | end
147 |
148 | @doc """
149 | Add a vertical line across the axes.
150 |
151 | ## Examples
152 |
153 | - Draw a thick read vline at x = 0 that spans the yrange:
154 | ```elixir
155 | Expyplot.Plot.axvline(linewidth: 4, color: :r)
156 | ```
157 |
158 | - Draw a default vline at x = 1 that spans the yrange:
159 | ```elixir
160 | Expyplot.Plot.axvline(x: 1)
161 | ```
162 |
163 | - Draw a default vline at x = 0.5 that spans the middle half of the yrange
164 | ```elixir
165 | Expyplot.Plot.axvline(x: 0.5, ymin: 0.25, ymax: 0.75)
166 | ```
167 |
168 | """
169 | def axvline(opts \\ [x: 0, ymin: 0, ymax: 1, hold: nil], kwargs \\ []) do
170 | Codebuilder.build_code(funcname: "plt.axvline", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
171 | end
172 |
173 | @doc """
174 | Add a vertical span (rectangle) across the axes.
175 |
176 | Draw a vertical span (rectangle) from xmin to xmax. With the default values of ymin = 0 and ymax = 1. This always spans the yrange,
177 | regardless of the ylim settings, even if you change them, e.g., with the set_ylim() command. That is, the vertical extent is in axes
178 | coords: 0=bottom, 0.5=middle, 1.0=top but the y location is in data coordinates.
179 |
180 | ## Examples
181 |
182 | Draw a vertical, green, translucent rectangle from x = 1.25 to x = 1.55 that spans the yrange of the axes.
183 |
184 | iex> Expyplot.Plot.axvspan(1.25, 1.55, facecolor: :g, alpha: 0.5)
185 | ""
186 |
187 | """
188 | def axvspan(xmin, xmax, opts \\ [ymin: 0, ymax: 1, hold: nil], kwargs \\ []) do
189 | Codebuilder.build_code(funcname: "plt.axvspan", nonnamed: [xmin, xmax], named: opts ++ kwargs) |> Server.Commapi.add_code
190 | end
191 |
192 | @doc """
193 | Make a bar plot.
194 |
195 | Make a bar plot with rectangles bounded by: left, left + width, bottom, bottom + height
196 | (left, right, bottom and top edges).
197 | """
198 | def bar(left, height, opts \\ [width: 0.8, bottom: nil, hold: nil, data: nil], kwargs \\ []) do
199 | Codebuilder.build_code(funcname: "plt.bar", nonnamed: [left, height], named: opts ++ kwargs) |> Server.Commapi.add_code
200 | end
201 |
202 | @doc """
203 | Plot a 2-D field of barbs.
204 | """
205 | def barbs(opts \\ [], kwargs \\ []) do
206 | Codebuilder.build_code(funcname: "plt.barbs", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
207 | end
208 |
209 | @doc """
210 | Make a horizontal bar plot.
211 |
212 | Make a horizontal bar plot with rectangles bounded by: left, left + width, bottom, bottom + height
213 |
214 | (lft, right, bottom and top edges).
215 |
216 | bottom, width, height, and left can be either scalars or sequences
217 | """
218 | def barh(bottom, width, opts \\ [height: 0.8, left: nil, hold: nil], kwargs \\ []) do
219 | Codebuilder.build_code(funcname: "plt.barh", nonnamed: [bottom, width], named: opts ++ kwargs) |> Server.Commapi.add_code
220 | end
221 |
222 | @doc """
223 | Set the default colormap to bone and apply to current image if any.
224 | """
225 | def bone do
226 | Codebuilder.build_code(funcname: "plt.bone", nonnamed: [], named: []) |> Server.Commapi.add_code
227 | end
228 |
229 | @doc """
230 | Make a box and whisker plot.
231 |
232 | Make a box and whisker plot for each column of x or each vector in sequence x. The box extends from the lower to upper quartile values
233 | of the data, with a line at the median. The whiskers extend from the box to show the range of the data. Flier points are those past the end
234 | of the whiskers.
235 | """
236 | def boxplot(x, opts \\ [notch: nil, sym: nil, vert: nil, whis: nil, positions: nil, widths: nil, patch_artist: nil, bootstrap: nil, usermedians: nil,
237 | conf_intervals: nil, meanline: nil, showmeans: nil, showcaps: nil, showbox: nil, showfliers: nil, boxprops: nil, labels: nil,
238 | flierprops: nil, medianprops: nil, meanprops: nil, capprops: nil, whiskerprops: nil, manage_xticks: true, autorange: false,
239 | zorder: nil, hold: nil, data: nil]) do
240 | Codebuilder.build_code(funcname: "plt.boxplot", nonnamed: [x], named: opts) |> Server.Commapi.add_code
241 | end
242 |
243 | @doc """
244 | Plot horizontal bars.
245 |
246 | A collection of horizontal bars spanning yrange with a sequence of xranges.
247 | """
248 | def broken_barh(xranges, yrange, opts \\ [hold: nil, data: nil], kwargs \\ []) do
249 | Codebuilder.build_code(funcname: "plt.broken_barh", nonnamed: [xranges, yrange], named: opts ++ kwargs) |> Server.Commapi.add_code
250 | end
251 |
252 | @doc """
253 | Clear the current axes.
254 | """
255 | def cla do
256 | Codebuilder.build_code(funcname: "plt.cla", nonnamed: [], named: []) |> Server.Commapi.add_code
257 | end
258 |
259 | @doc """
260 | Label a contour plot.
261 | """
262 | def clabel(cs, opts \\ [], kwargs \\ []) do
263 | Codebuilder.build_code(funcname: "plt.clabel", nonnamed: [cs] ++ opts, named: kwargs) |> Server.Commapi.add_code
264 | end
265 |
266 | @doc """
267 | Clear the current figure.
268 | """
269 | def clf do
270 | Codebuilder.build_code(funcname: "plt.clf", nonnamed: [], named: []) |> Server.Commapi.add_code
271 | end
272 |
273 | @doc """
274 | Set the color limits of the current image.
275 |
276 | To apply clim to all axes images do:
277 | ```elixir
278 | clim(vmin: 0, vmax: 0.5)
279 | ```
280 | If either vmin or vmax is nil, the image min/max respectively will be used for color scaling.
281 | """
282 | def clim(opts \\ [vmin: nil, vmax: nil]) do
283 | Codebuilder.build_code(funcname: "plt.clim", nonnamed: [], named: opts) |> Server.Commapi.add_code
284 | end
285 |
286 | @doc """
287 | Close a figure window.
288 |
289 | close() by itself closes the current figure
290 |
291 | close(num) closes figure number num
292 |
293 | close(name) where name is a string, closes figure with that label
294 |
295 | close(:all) closes all the figure windows
296 | """
297 | def close(opts \\ []) do
298 | Codebuilder.build_code(funcname: "plt.close", nonnamed: opts, named: []) |> Server.Commapi.add_code
299 | end
300 |
301 | @doc """
302 | Plot the coherence between x and y.
303 |
304 | Plot the coherence between x and y. Coherence is the normalized cross spectral density.
305 | """
306 | def cohere(x, y, opts \\ [nfft: 256, _Fs: 2, _Fc: 0, noverlap: 0, pad_to: nil, sides: :default, scale_by_freq: nil, hold: nil, data: nil], kwargs \\ []) do
307 | Codebuilder.build_code(funcname: "plt.cohere", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
308 | end
309 |
310 | @doc """
311 | Add a colorbar to a plot.
312 | """
313 | def colorbar(opts \\ [mappable: nil, cax: nil, ax: nil], kwargs \\ []) do
314 | Codebuilder.build_code(funcname: "plt.colorbar", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
315 | end
316 |
317 | @doc """
318 | This is a do-nothing function to provide you with help on how matplotlib handles colors.
319 | """
320 | def colors do
321 | Codebuilder.build_code(funcname: "plt.colors", nonnamed: [], named: []) |> Server.Commapi.add_code
322 | end
323 |
324 | @doc """
325 | Plot contours.
326 |
327 | contour() and contourf() draw contour lines and filled contours, respectively. Except as noted, function signatures and return values
328 | are the same for both versions.
329 |
330 | contourf() differs from the MATLAB version in that it does not draw the polygon edges. To draw edges, add line contours with calls to contour().
331 | """
332 | def contour(opts \\ [], kwargs \\ []) do
333 | Codebuilder.build_code(funcname: "plt.contour", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
334 | end
335 |
336 | @doc """
337 | Plot contours.
338 |
339 | contour() and contourf() draw contour lines and filled contours, respectively. Except as noted, function signatures and return values
340 | are the same for both versions.
341 |
342 | contourf() differs from the MATLAB version in that it does not draw the polygon edges. To draw edges, add line contours with calls to contour().
343 | """
344 | def contourf(opts \\ [], kwargs \\ []) do
345 | Codebuilder.build_code(funcname: "plt.contourf", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
346 | end
347 |
348 | @doc """
349 | Set the default colormap to cool and apply to current image if any.
350 | """
351 | def cool do
352 | Codebuilder.build_code(funcname: "plt.cool", nonnamed: [], named: []) |> Server.Commapi.add_code
353 | end
354 |
355 | @doc """
356 | Set the default colormap to copper and apply to current image if any.
357 | """
358 | def copper do
359 | Codebuilder.build_code(funcname: "plt.copper", nonnamed: [], named: []) |> Server.Commapi.add_code
360 | end
361 |
362 | @doc """
363 | Plot the cross-spectral density.
364 | """
365 | def csd(x, y, opts \\ [nfft: 256, _Fs: 2, _Fc: 0, noverlap: 0, pad_to: nil, sides: :default, scale_by_freq: nil, return_line: nil], kwargs \\ []) do
366 | Codebuilder.build_code(funcname: "plt.csd", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
367 | end
368 |
369 | @doc """
370 | Remove an axes from the current figure. If ax doesn't exist, an error will be raised.
371 | """
372 | def delaxes(opts \\ []) do
373 | Codebuilder.build_code(funcname: "plt.delaxes", nonnamed: opts, named: []) |> Server.Commapi.add_code
374 | end
375 |
376 | @doc """
377 | Redraw the current figure.
378 |
379 | This is used to update a figure that has been altered, but not automatically re-drawn. If interactive mode is on (ion()), this should be only
380 | rarely needed, but there may be ways to modify the state of a figure without marking it as stale.
381 | """
382 | def draw do
383 | Codebuilder.build_code(funcname: "plt.draw", nonnamed: [], named: []) |> Server.Commapi.add_code
384 | end
385 |
386 | @doc """
387 | Plot an errorbar graph.
388 |
389 | Plot x versus y with error deltas in yerr and xerr. Vertical errorbars are plotted if yerr is not nil. Horizontal errorbars are plotted if xerr is
390 | not nil.
391 |
392 | x, y, xerr, and yerr can all be scalars, which plots a single error bar at x, y.
393 | """
394 | def errorbar(x, y, opts \\ [yerr: nil, xerr: nil, fmt: "", ecolor: nil, elinewidth: nil, capsize: nil, barsabove: false, lolims: false, uplims: false,
395 | xlolims: false, xuplims: false, errorevery: 1, capthick: nil, hold: nil, data: nil], kwargs \\ []) do
396 | Codebuilder.build_code(funcname: "plt.errorbar", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
397 | end
398 |
399 | @doc """
400 | Plot identical parallel lines at specific positions.
401 |
402 | Plot parallel lines at the given positions. positions should be a 1D or 2D array-like object, with each row corresponding to a row or
403 | column of lines.
404 |
405 | This type of plot is commonly used in neuroscience for representing neural events, where it is commonly called a spike raster, dot raster, or raster plot.
406 |
407 | However, it is useful in any situation where you wish to show the timing or position of multiple sets of discrete events, such as the arrival
408 | times of people to a business on each day of the month or the date of hurricanes each year of the last century.
409 | """
410 | def eventplot(positions, opts \\ [orientation: :horizontal, lineoffsets: 1, linelengths: 1, linewidths: nil, colors: nil, linestyles: :solid,
411 | hold: nil, data: nil], kwargs \\ []) do
412 | Codebuilder.build_code(funcname: "plt.eventplot", nonnamed: [positions], named: opts ++ kwargs) |> Server.Commapi.add_code
413 | end
414 |
415 | @doc """
416 | Adds a non-resampled image to the figure.
417 | """
418 | def figimage(opts \\ [], kwargs \\ []) do
419 | Codebuilder.build_code(funcname: "plt.figimage", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
420 | end
421 |
422 | @doc """
423 | Place a legend in the figure.
424 | """
425 | def figlegend(handles, labels, loc, kwargs \\ []) do
426 | Codebuilder.build_code(funcname: "plt.figlegend", nonnamed: [handles, labels, loc], named: kwargs) |> Server.Commapi.add_code
427 | end
428 |
429 | @doc """
430 | """
431 | def fignum_exists(num) do
432 | Codebuilder.build_code(funcname: "plt.fignum_exists", nonnamed: [num], named: []) |> Server.Commapi.add_code
433 | end
434 |
435 | @doc """
436 | Add text to figure.
437 |
438 | Add text to figure at location x, y (relative 0-1 coords).
439 | """
440 | def figtext(opts \\ [], kwargs \\ []) do
441 | Codebuilder.build_code(funcname: "plt.figtext", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
442 | end
443 |
444 | @doc """
445 | Creates a new figure.
446 | """
447 | def figure(opts \\ [num: nil, figsize: nil, dpi: nil, facecolor: nil, edgecolor: nil, frameon: true], kwargs \\ []) do
448 | Codebuilder.build_code(funcname: "plt.figure", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
449 | end
450 |
451 | @doc """
452 | Plot filled polygons.
453 | """
454 | def fill(opts \\ [], kwargs \\ []) do
455 | Codebuilder.build_code(funcname: "plt.fill", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
456 | end
457 |
458 | @doc """
459 | Make filled polygons between two curves.
460 | """
461 | def fill_between_vertical(x, y1, opts \\ [y2: 0, where: nil, interpolate: false, step: nil, hold: nil, data: nil], kwargs \\ []) do
462 | Codebuilder.build_code(funcname: "plt.fill_between", nonnamed: [x, y1], named: opts ++ kwargs) |> Server.Commapi.add_code
463 | end
464 |
465 | @doc """
466 | Make filled polygons between two horizontal curves.
467 | """
468 | def fill_between_horizontal(y, x1, opts \\ [x2: 0, where: nil, step: nil, hold: nil, data: nil], kwargs \\ []) do
469 | Codebuilder.build_code(funcname: "plt.fill_between", nonnamed: [y, x1], named: opts ++ kwargs) |> Server.Commapi.add_code
470 | end
471 |
472 | @doc """
473 | Find artist objects.
474 |
475 | Recursively find all Artist instances contained in self.
476 | """
477 | def findobj(opts \\ [o: nil, match: nil, include_self: true]) do
478 | Codebuilder.build_code(funcname: "plt.findobj", nonnamed: [], named: opts) |> Server.Commapi.add_code
479 | end
480 |
481 | @doc """
482 | Set the default colormap to flag and apply to current image if any.
483 | """
484 | def flag do
485 | Codebuilder.build_code(funcname: "plt.flag", nonnamed: [], named: []) |> Server.Commapi.add_code
486 | end
487 |
488 | @doc """
489 | Get the current Axes instance on the current figure matching the given keyword args, or create one.
490 | """
491 | def gca(kwargs \\ []) do
492 | Codebuilder.build_code(funcname: "plt.gca", named: [], nonnamed: kwargs) |> Server.Commapi.add_code
493 | end
494 |
495 | @doc """
496 | Get a reference to the current figure.
497 | """
498 | def gcf do
499 | Codebuilder.build_code(funcname: "plt.gcf", named: [], nonnamed: []) |> Server.Commapi.add_code
500 | end
501 |
502 | @doc """
503 | Get the current colorable artist. Specifically, returns the current ScalarMappable instance (image or patch collection), or "Nothing" if no
504 | images or patch collections have been defined. The commands imshow() and figimage() create Image instances, and the commands
505 | pcolor() and scatter() create Collection instances. The current image is an attribute of the current axes, or the nearest earlier axes
506 | in the current figure that contains an image.
507 | """
508 | def gci do
509 | Codebuilder.build_code(funcname: "plt.gci", nonnamed: [], named: []) |> Server.Commapi.add_code
510 | end
511 |
512 | @doc """
513 | """
514 | def get_current_fig_manager do
515 | Codebuilder.build_code(funcname: "plt.get_current_fig_manager", nonnamed: [], named: []) |> Server.Commapi.add_code
516 | end
517 |
518 | @doc """
519 | Return a list of existing figure labels.
520 | """
521 | def get_figlabels do
522 | Codebuilder.build_code(funcname: "plt.get_figlabels", nonnamed: [], named: []) |> Server.Commapi.add_code
523 | end
524 |
525 | @doc """
526 | Return a list of existing figure numbers.
527 | """
528 | def get_fignums do
529 | Codebuilder.build_code(funcname: "plt.get_fignums", nonnamed: [], named: []) |> Server.Commapi.add_code
530 | end
531 |
532 | @doc """
533 | Get a sorted list of all of the plotting commands.
534 | """
535 | def get_plot_commands do
536 | Codebuilder.build_code(funcname: "plt.get_plot_commands", nonnamed: [], named: []) |> Server.Commapi.add_code
537 | end
538 |
539 | @doc """
540 | This will wait for n clicks from the user and return a list of the coordinates of each click.
541 |
542 | If timeout is zero or negative, does not timeout.
543 |
544 | If n is zero or negative, accumulated clicks until a middle click (or potentially both mouse buttons at once) terminates the input.
545 |
546 | Right clicking cancels last input.
547 |
548 | The buttons used for the various actions (adding points, removing points, terminating the inputs) can be overriden via the arguments
549 | mouse_add, mouse_pop and mouse_stop, that give the associated mouse button: 1 for left, 2 for middle, 3 for right.
550 |
551 | The keyboard can also be used to select points in case your mouse does not have one or more of the buttons. The delete and backspace
552 | keys act like right clicking (i.e., remove last point), the enter key terminates input and any other key (not already used by the window
553 | manager) selects a point.
554 | """
555 | def ginput(opts \\ [], kwargs \\ []) do
556 | Codebuilder.build_code(funcname: "plt.ginput", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
557 | end
558 |
559 | @doc """
560 | Set the default colormap to gray and apply to current image if any.
561 | """
562 | def gray do
563 | Codebuilder.build_code(funcname: "plt.gray", nonnamed: [], named: []) |> Server.Commapi.add_code
564 | end
565 |
566 | @doc """
567 | Turn the axes grids on or off.
568 |
569 | Set the axes grids on or off; b is a boolean. (For MATLAB compatibility, b may also be an atom :on or :off.)
570 | """
571 | def grid(opts \\ [b: nil, which: :major, axis: :both], kwargs \\ []) do
572 | Codebuilder.build_code(funcname: "plt.grid", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
573 | end
574 |
575 | @doc """
576 | Make a hexagonal binning plot.
577 |
578 | Make a hexagonal binning plot of x versus y, where x, y are 1-D sequences of the same length, N. If C is
579 | nil (the default), this is a histogram of the number of occurrences of the observations at (x[i], y[i]).
580 |
581 | If C is specified, it specifies values at the coordinate (x[i], y[i]). These values are accumulated for each hexagonal bin and then reduced
582 | according to reduce_C_function, which defaults to numpy's mean function (np.mean). (If C is specified, it must also be a 1-D sequence
583 | of the same length as x and y.)
584 | """
585 | def hexbin(x, y, opts \\ [c: nil, gridsize: 100, bins: nil, xscale: :linear, yscale: :linear, extent: nil, cmap: nil, norm: nil, vmin: nil, vmax: nil,
586 | alpha: nil, linewidths: nil, edgecolors: :none, mincnt: nil, marginals: false, hold: nil, data: nil], kwargs \\ []) do
587 | Codebuilder.build_code(funcname: "plt.hexbin", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
588 | end
589 |
590 | @doc """
591 | Plot a histogram.
592 |
593 | Compute and draw the histogram of x. The return value is a tuple (n, bins, patches) or ([n0, n1, ...], bins, [patches0, patches1, ...])
594 | if the input contains multiple data.
595 |
596 | Multiple data can be provided via x as a list of datasets of potentially different length, or as a 2-D ndarray in which each column is a dataset.
597 | Note that the ndarray form is transposed relative to the list form.
598 |
599 | Masked arrays are not supported at present.
600 | """
601 | def hist(x, opts \\ [bins: nil, range: nil, normed: false, weights: nil, cumulative: false, bottom: nil, histtype: :bar, align: :mid, orientation: :vertical,
602 | rwidth: nil, log: false, color: nil, label: nil, stacked: false, hold: nil, data: nil], kwargs \\ []) do
603 | Codebuilder.build_code(funcname: "plt.hist", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
604 | end
605 |
606 | @doc """
607 | Make a 2D histogram plot.
608 | """
609 | def hist2d(x, y, opts \\ [bins: 10, range: nil, normed: false, weights: nil, cmin: nil, cmax: nil, hold: nil, data: nil], kwargs \\ []) do
610 | Codebuilder.build_code(funcname: "plt.hist2d", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
611 | end
612 |
613 | @doc """
614 | Plot horizontal lines at each y from xmin to xmax.
615 | """
616 | def hlines(y, xmin, xmax, opts \\ [colors: :k, linestyles: :solid, label: "", hold: nil, data: nil], kwargs \\ []) do
617 | Codebuilder.build_code(funcname: "plt.hlines", nonnamed: [y, xmin, xmax], named: opts ++ kwargs) |> Server.Commapi.add_code
618 | end
619 |
620 | @doc """
621 | Set the default colormap to hot and apply to current image if any.
622 | """
623 | def hot do
624 | Codebuilder.build_code(funcname: "plt.hot", nonnamed: [], named: []) |> Server.Commapi.add_code
625 | end
626 |
627 | @doc """
628 | Set the default colormap to hsv and apply to current image if any.
629 | """
630 | def hsv do
631 | Codebuilder.build_code(funcname: "plt.hsv", nonnamed: [], named: []) |> Server.Commapi.add_code
632 | end
633 |
634 | @doc """
635 | Read an image from a file into an array.
636 |
637 | fname may be a string path, or a valid URL.
638 |
639 | If format is provided, will try to read file of that type, otherwise the format is deduced from the filename. If nothing can be deduced, PNG
640 | is tried.
641 |
642 | Return value is a numpy.array But in expyplot, this will return a string, and it probably won't work. For grayscale images, the return array is MxN.
643 | For RGB images, the return value is MxNx4.
644 |
645 | matplotlib can only read PNGs natively, but if PIL is installed, it will use it to load the image and return an array (if possible) which can
646 | be used with imshow(). Note, URL strings may not be compatible with PIL. Check the PIL documentation for more information.
647 | """
648 | def imread(opts \\ [], kwargs \\ []) do
649 | Codebuilder.build_code(funcname: "plt.imread", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
650 | end
651 |
652 | @doc """
653 | Save an array as an image file.
654 |
655 | The output formats available depend on the backend being used.
656 | """
657 | def imsave(opts \\ [], kwargs \\ []) do
658 | Codebuilder.build_code(funcname: "plt.imsave", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
659 | end
660 |
661 | @doc """
662 | Display an image on the axes.
663 | """
664 | def imshow(x, opts \\ [cmap: nil, norm: nil, aspect: nil, interpolation: nil, alpha: nil, vmin: nil, vmax: nil,
665 | origin: nil, extent: nil, shape: nil, filternorm: 1, filterrad: 4.0, imlim: nil, resample: nil,
666 | url: nil, hold: nil, data: nil], kwargs \\ []) do
667 | Codebuilder.build_code(funcname: "plt.imshow", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
668 | end
669 |
670 | @doc """
671 | Set the default colormap to inferno and apply to current image if any.
672 | """
673 | def inferno do
674 | Codebuilder.build_code(funcname: "plt.inferno", nonnamed: [], named: []) |> Server.Commapi.add_code
675 | end
676 |
677 | @doc """
678 | Turn interactive mode off.
679 | """
680 | def ioff do
681 | Codebuilder.build_code(funcname: "plt.ioff", nonnamed: [], named: []) |> Server.Commapi.add_code
682 | end
683 |
684 | @doc """
685 | Turn interactive mode on.
686 | """
687 | def ion do
688 | Codebuilder.build_code(funcname: "plt.ion", nonnamed: [], named: []) |> Server.Commapi.add_code
689 | end
690 |
691 | @doc """
692 | Return status of interactive mode.
693 | """
694 | def isinteractive do
695 | Codebuilder.build_code(funcname: "plt.isinteractive", nonnamed: [], named: []) |> Server.Commapi.add_code
696 | end
697 |
698 | @doc """
699 | Set the default coormap to jet and apply to current image if any.
700 | """
701 | def jet do
702 | Codebuilder.build_code(funcname: "plt.jet", nonnamed: [], named: []) |> Server.Commapi.add_code
703 | end
704 |
705 | @doc """
706 | Places a legend on the axes.
707 | """
708 | def legend(opts \\ [], kwargs \\ []) do
709 | Codebuilder.build_code(funcname: "plt.legend", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
710 | end
711 |
712 | @doc """
713 | Control behavior of tick locators.
714 | """
715 | def locator_params(opts \\ [axis: :both, tight: nil], kwargs \\ []) do
716 | Codebuilder.build_code(funcname: "plt.locator_params", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
717 | end
718 |
719 | @doc """
720 | Make a plot with log scaling on both the x and y axis.
721 |
722 | loglog() supports all the keyword arguments of plot() and matplotlib.axes.Axes.set_xscale() / matplotlib.axes.Axes.set_yscale().
723 | """
724 | def loglog(opts \\ [], kwargs \\ []) do
725 | Codebuilder.build_code(funcname: "plt.loglog", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
726 | end
727 |
728 | @doc """
729 | Set the default colormap to magma and apply to current image if any.
730 | """
731 | def magma do
732 | Codebuilder.build_code(funcname: "plt.magma", nonnamed: [], named: []) |> Server.Commapi.add_code
733 | end
734 |
735 | @doc """
736 | Plot the magnitude spectrum.
737 | """
738 | def magnitude_spectrum(x, opts \\ [_Fs: nil, _Fc: nil, window: nil, pad_to: nil, sides: nil, scale: nil, hold: nil, data: nil], kwargs \\ []) do
739 | Codebuilder.build_code(funcname: "plt.magnitude_spectrum", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
740 | end
741 |
742 | @doc """
743 | Set or retrieve autoscaling margins.
744 | """
745 | def margins(opts \\ [], kwargs \\ []) do
746 | Codebuilder.build_code(funcname: "plt.margins", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
747 | end
748 |
749 | @doc """
750 | Display an array as a matrix in a new figure window.
751 |
752 | The origin is set at the upper left hand corner and rows (first dimension of the array) are displayed horizontally. The aspect ratio of the
753 | figure window is that of the array, unless this would make an excessively short or narrow figure.
754 |
755 | Tick labels for the xaxis are placed on top.
756 | """
757 | def matshow(a, opts \\ [fignum: nil], kwargs \\ []) do
758 | Codebuilder.build_code(funcname: "plt.matshow", nonnamed: [a], named: opts ++ kwargs) |> Server.Commapi.add_code
759 | end
760 |
761 | @doc """
762 | Remove minor ticks from the current plot.
763 | """
764 | def minorticks_off do
765 | Codebuilder.build_code(funcname: "plt.minorticks_off", nonnamed: [], named: []) |> Server.Commapi.add_code
766 | end
767 |
768 | @doc """
769 | Set the default colormap to nipy_spectral and apply to current image if any.
770 | """
771 | def nipy_spectral do
772 | Codebuilder.build_code(funcname: "plt.nipy_spectral", nonnamed: [], named: []) |> Server.Commapi.add_code
773 | end
774 |
775 | @doc """
776 | Pause for interval seconds.
777 |
778 | If there is an active figure it will be updated and displayed, and the GUI event loop will run during the pause.
779 |
780 | If there is no active figure, or if a non-interactive backend is in use, this executes time.sleep(interval).
781 |
782 | This can be used for crude animation.
783 | """
784 | def pause(interval) do
785 | Codebuilder.build_code(funcname: "plt.interval", nonnamed: [interval], named: []) |> Server.Commapi.add_code
786 | end
787 |
788 | @doc """
789 | Create a pseudocolor plot of a 2-D array.
790 | """
791 | def pcolor(opts \\ [], kwargs \\ []) do
792 | Codebuilder.build_code(funcname: "plt.pcolor", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
793 | end
794 |
795 | @doc """
796 | Plot a quadrilateral mesh.
797 | """
798 | def pcolormesh(opts \\ [], kwargs \\ []) do
799 | Codebuilder.build_code(funcname: "plt.pcolormesh", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
800 | end
801 |
802 | @doc """
803 | Plot the phase spectrum.
804 | """
805 | def phase_spectrum(x, opts \\ [_Fs: nil, _Fc: nil, window: nil, pad_to: nil, sides: nil, hold: nil, data: nil], kwargs \\ []) do
806 | Codebuilder.build_code(funcname: "plt.phase_spectrum", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
807 | end
808 |
809 | @doc """
810 | Plot a pie chart.
811 |
812 | Make a pie chart of array x. The fractional area of each wedge is given by x / sum(x). If sum(x) <= 1, then the values of x give the fractional
813 | area directly and the array will not be normalized. The wedges are plotted counterclockwise, by default starting from the x-axis.
814 | """
815 | def pie(x, opts \\ [explode: nil, labels: nil, colors: nil, autopct: nil, pctdistance: 0.6, shadow: false, labeldistance: 1.1, startangle: nil,
816 | radius: nil, counterclock: true, wedgeprops: nil, textprops: nil, center: {0, 0}, frame: false, hold: nil, data: nil]) do
817 | Codebuilder.build_code(funcname: "plt.pie", nonnamed: [x], named: opts) |> Server.Commapi.add_code
818 | end
819 |
820 | @doc """
821 | Set the default colormap to pink and apply to current image if any.
822 | """
823 | def pink do
824 | Codebuilder.build_code(funcname: "plt.pink", nonnamed: [], named: []) |> Server.Commapi.add_code
825 | end
826 |
827 | @doc """
828 | Set the default colormap to plasma and apply to current image if any.
829 | """
830 | def plasma do
831 | Codebuilder.build_code(funcname: "plt.plasma", nonnamed: [], named: []) |> Server.Commapi.add_code
832 | end
833 |
834 | @doc """
835 | Plot lines and/or markers to the Axes. args is a variable length argument, allowing for multiple x, y pairs with an optional format string.
836 |
837 | Each of the following is legal:
838 | ```elixir
839 | x = 1..10 |> Enum.to_list
840 | y = 11..20 |> Enum.to_list
841 | Expyplot.Plot.plot([x, y]) # plot x and y using default line style and color
842 | Expyplot.Plot.plot([x, y, "bo"]) # plot x and y using blue circle markers
843 | Expyplot.Plot.plot([y]) # plot y using x as index array 0..N-1
844 | Expyplot.Plot.plot([y, "r+"]) # ditto, but with red plusses
845 |
846 | x2 = 1..5 |> Enum.to_list
847 | y2 = 3..7 |> Enum.to_list
848 | Expyplot.Plot.plot([x, y, "g^", x2, y2, "g-"])
849 | ```
850 |
851 | Due to the differences between function signatures in Python and Elixir, the typical usage of this function is a little different than what you would
852 | expect:
853 |
854 | iex> Expyplot.Plot.plot([[1, 2, 3, 4, 5]])
855 | nil
856 |
857 | or
858 |
859 | iex> Expyplot.Plot.plot([1..5])
860 | nil
861 |
862 | Notice the nesting of the list or range.
863 |
864 | ## Examples with keyword args
865 |
866 | ```elixir
867 | Expyplot.Plot.plot([[1, 2, 3], [1, 2, 3], "go-"], label: "line 1", linewidth: 2)
868 | Expyplot.Plot.plot([[1, 2, 3], [1, 4, 9], "rs"], label: "line 2")
869 | Expyplot.Plot.axis_set([0, 4, 0, 10]) # Notice that this signature is 'axis_set', not 'axis' as in matplotlib
870 | Expyplot.Plot.legend()
871 | ```
872 | """
873 | def plot(opts \\ [], kwargs \\ []) do
874 | Codebuilder.build_code(funcname: "plt.plot", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
875 | end
876 |
877 | @doc """
878 | A plot with data that contains dates.
879 | """
880 | def plot_date(x, y, opts \\ [fmt: :o, tz: nil, xdate: true, ydate: false, hold: nil, data: nil], kwargs \\ []) do
881 | Codebuilder.build_code(funcname: "plt.plot_date", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
882 | end
883 |
884 | @doc """
885 | Plot the data in a file.
886 | """
887 | def plotfile(fname, opts \\ [cols: {0}, plotfuncs: nil, comments: "#", skiprows: 0, checkrows: 5, delimiter: ",", names: nil, subplots: true,
888 | newfig: true], kwargs \\ []) do
889 | Codebuilder.build_code(funcname: "plt.plotfile", nonnamed: [fname], named: opts ++ kwargs) |> Server.Commapi.add_code
890 | end
891 |
892 | @doc """
893 | make a polar plot.
894 | """
895 | def polar(opts \\ [], kwargs \\ []) do
896 | Codebuilder.build_code(funcname: "plt.polar", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
897 | end
898 |
899 | @doc """
900 | Set the default colormap to prism and apply to current image if any.
901 | """
902 | def prism do
903 | Codebuilder.build_code(funcname: "plt.prism", nonnamed: [], named: []) |> Server.Commapi.add_code
904 | end
905 |
906 | @doc """
907 | Plot the power spectral density.
908 | """
909 | def psd(x, opts \\ [nfft: nil, _Fs: nil, _Fc: nil, detrend: nil, window: nil, noverlap: nil, pad_to: nil, sides: nil, scale_by_freq: nil,
910 | return_line: nil, hold: nil, data: nil], kwargs \\ []) do
911 | Codebuilder.build_code(funcname: "plt.psd", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
912 | end
913 |
914 | @doc """
915 | Plot a 2-D field of arrows.
916 | """
917 | def quiver(opts \\ [], kwargs \\ []) do
918 | Codebuilder.build_code(funcname: "plt.quiver", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
919 | end
920 |
921 | @doc """
922 | Add a key to a quiver plot.
923 | """
924 | def quiverkey(opts \\ [], kwargs \\ []) do
925 | Codebuilder.build_code(funcname: "plt.quiverkey", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
926 | end
927 |
928 | @doc """
929 | Set the current rc params. Group is the grouping for the rc.
930 | """
931 | def rc(opts \\ [], kwargs \\ []) do
932 | Codebuilder.build_code(funcname: "plt.rc", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
933 | end
934 |
935 | @doc """
936 | Restore the default rc params. These are not the params loaded by the rc file, but mpl's internal params. See rc_file_defaults for reloading
937 | the default params from the rc file.
938 | """
939 | def rcdefaults do
940 | Codebuilder.build_code(funcname: "plt.rcdefaults", nonnamed: [], named: []) |> Server.Commapi.add_code
941 | end
942 |
943 | @doc """
944 | Get or set the radial gridlines on a polar plot.
945 | """
946 | def rgrids(opts \\ [], kwargs \\ []) do
947 | Codebuilder.build_code(funcname: "plt.rgrids", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
948 | end
949 |
950 | @doc """
951 | Save the current figure.
952 | """
953 | def savefig(opts \\ [], kwargs \\ []) do
954 | Codebuilder.build_code(funcname: "plt.savefig", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
955 | end
956 |
957 | @doc """
958 | Make a scatter plot of x vs y.
959 |
960 | Marker size is scaled by s and marker color is mapped to c.
961 | """
962 | def scatter(x, y, opts \\ [s: nil, c: nil, marker: nil, cmap: nil, norm: nil, vmin: nil, vmax: nil, alpha: nil,
963 | linewidths: nil, verts: nil, edgecolors: nil, hold: nil, data: nil], kwargs \\ []) do
964 | Codebuilder.build_code(funcname: "plt.scatter", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
965 | end
966 |
967 | @doc """
968 | Make a plot with log scaling on the x axis.
969 | """
970 | def semilogx(opts \\ [], kwargs \\ []) do
971 | Codebuilder.build_code(funcname: "plt.semilogx", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
972 | end
973 |
974 | @doc """
975 | Make a plot with log scaling on the y axis.
976 | """
977 | def semilogy(opts \\ [], kwargs \\ []) do
978 | Codebuilder.build_code(funcname: "plt.semilogy", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
979 | end
980 |
981 | @doc """
982 | Set the default colormap. Applies to the current image if any.
983 |
984 | cmap must be the name of a registered colormap.
985 | """
986 | def set_cmap(cmap) do
987 | Codebuilder.build_code(funcname: "plt.set_cmap", nonnamed: [cmap], named: []) |> Server.Commapi.add_code
988 | end
989 |
990 | @doc """
991 | Display a figure.
992 | """
993 | def show(opts \\ [], kwargs \\ []) do
994 | Codebuilder.build_code(funcname: "plt.show", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
995 | end
996 |
997 | @doc """
998 | Plot a spectrogram.
999 | """
1000 | def specgram(x, opts \\ [nfft: nil, _Fs: nil, _Fc: nil, detrend: nil, window: nil, noverlap: nil, cmap: nil, xextent: nil, pad_to: nil,
1001 | sides: nil, scale_by_freq: nil, mode: nil, scale: nil, vmin: nil, vmax: nil, hold: nil, data: nil], kwargs \\ []) do
1002 | Codebuilder.build_code(funcname: "plt.specgram", nonnamed: [x], named: opts ++ kwargs) |> Server.Commapi.add_code
1003 | end
1004 |
1005 | @doc """
1006 | Set the default colormap to spectral and apply to current image if any.
1007 | """
1008 | def spectral do
1009 | Codebuilder.build_code(funcname: "plt.spectral", nonnamed: [], named: []) |> Server.Commapi.add_code
1010 | end
1011 |
1012 | @doc """
1013 | Set the default colormap to spring and apply to current image if any.
1014 | """
1015 | def spring do
1016 | Codebuilder.build_code(funcname: "plt.spring", nonnamed: [], named: []) |> Server.Commapi.add_code
1017 | end
1018 |
1019 | @doc """
1020 | Plot the sparsity pattern on a 2-D array.
1021 |
1022 | spy(z) plots the sparsity pattern of the 2-D array z.
1023 | """
1024 | def spy(z, opts \\ [precision: 0, marker: nil, markersize: nil, aspect: :equal], kwargs \\ []) do
1025 | Codebuilder.build_code(funcname: "plt.spy", nonnamed: [z], named: opts ++ kwargs) |> Server.Commapi.add_code
1026 | end
1027 |
1028 | @doc """
1029 | Draws a stacked area plot.
1030 | """
1031 | def stackplot(x, opts \\ [], kwargs \\ []) do
1032 | Codebuilder.build_code(funcname: "plt.stackplot", nonnamed: [x] ++ opts, named: kwargs) |> Server.Commapi.add_code
1033 | end
1034 |
1035 | @doc """
1036 | Create a stem plot.
1037 | """
1038 | def stem(opts \\ [], kwargs \\ []) do
1039 | Codebuilder.build_code(funcname: "plt.stem", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1040 | end
1041 |
1042 | @doc """
1043 | Make a step plot.
1044 | """
1045 | def step(x, y, opts \\ [], kwargs \\ []) do
1046 | Codebuilder.build_code(funcname: "plt.step", nonnamed: [x, y] ++ opts, named: kwargs) |> Server.Commapi.add_code
1047 | end
1048 |
1049 | @doc """
1050 | Draws streamlinkes of a vector flow.
1051 | """
1052 | def streamplot(x, y, u, v, opts \\ [density: 1, linewidth: nil, color: nil, cmap: nil, norm: nil, arrowsize: 1, arrowstyle: "-|>", minlength: 0.1, transform: nil,
1053 | zorder: nil, start_points: nil, hold: nil, data: nil]) do
1054 | Codebuilder.build_code(funcname: "plt.streamplot", nonnamed: [x, y, u, v], named: opts) |> Server.Commapi.add_code
1055 | end
1056 |
1057 | @doc """
1058 | Return a subplot axes positioned by the given grid definition.
1059 | """
1060 | def subplot(opts \\ [], kwargs \\ []) do
1061 | Codebuilder.build_code(funcname: "plt.subplot", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1062 | end
1063 |
1064 | @doc """
1065 | Create a subplot in a grid. The grid is specified by shape, at location of loc, spanning rowspan, colspan cells in each direction.
1066 | The index for loc is 0-based.
1067 | """
1068 | def subplot2grid(shape, loc, opts \\ [rowspan: 1, colspan: 1], kwargs \\ []) do
1069 | Codebuilder.build_code(funcname: "plt.subplot2grid", nonnamed: [shape, loc], named: opts ++ kwargs) |> Server.Commapi.add_code
1070 | end
1071 |
1072 | @doc """
1073 | Launch a subplot tool window for a figure.
1074 | """
1075 | def subplot_tool(opts \\ [targetfig: nil], kwargs \\ []) do
1076 | Codebuilder.build_code(funcname: "plt.subplot_tool", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
1077 | end
1078 |
1079 | @doc """
1080 | Create a figure and a set of subplots.
1081 |
1082 | This utility wrapper makes it convenient to create common layouts of subplots, including the enclosing figure object, in a single call.
1083 | """
1084 | def subplots(opts \\ [nrows: 1, ncols: 1, sharex: false, sharey: false, squeeze: true, subplot_kw: nil, gridspec_kw: nil], kwargs \\ []) do
1085 | Codebuilder.build_code(funcname: "plt.subplots", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
1086 | end
1087 |
1088 | @doc """
1089 | Tune the subplot layout.
1090 | """
1091 | def subplots_adjust(opts \\ [], kwargs \\ []) do
1092 | Codebuilder.build_code(funcname: "plt.subplots_adjust", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1093 | end
1094 |
1095 | @doc """
1096 | Set the default colormap to summer and apply to current image if any.
1097 | """
1098 | def summer do
1099 | Codebuilder.build_code(funcname: "plt.summer", nonnamed: [], named: []) |> Server.Commapi.add_code
1100 | end
1101 |
1102 | @doc """
1103 | Add a centered title to the figure.
1104 | """
1105 | def suptitle(opts \\ [], kwargs \\ []) do
1106 | Codebuilder.build_code(funcname: "plt.suptitle", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1107 | end
1108 |
1109 | @doc """
1110 | Add a table to the current axes.
1111 | """
1112 | def table(kwargs \\ []) do
1113 | Codebuilder.build_code(funcname: "plt.table", nonnamed: [], named: kwargs) |> Server.Commapi.add_code
1114 | end
1115 |
1116 | @doc """
1117 | Add text to the axes.
1118 |
1119 | Add text in string s to axis at location x, y data coordinates.
1120 | """
1121 | def text(x, y, s, opts \\ [fontdict: nil, withdash: false], kwargs \\ []) do
1122 | Codebuilder.build_code(funcname: "plt.text", nonnamed: [x, y, s], named: opts ++ kwargs) |> Server.Commapi.add_code
1123 | end
1124 |
1125 | @doc """
1126 | Get or set the theta locations of the gridlines in a polar plot.
1127 |
1128 | If no arguments are passed, return a tuple (lines, labels) where lines is an array of radial gridlines (Line2D instances) and labels
1129 | is an array of tick labels (Text instances).
1130 | """
1131 | def thetagrids(opts \\ [], kwargs \\ []) do
1132 | Codebuilder.build_code(funcname: "plt.thetagrids", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1133 | end
1134 |
1135 | @doc """
1136 | Change the appearance of ticks and tick labels.
1137 | """
1138 | def tick_parameters(opts \\ [axis: :both], kwargs \\ []) do
1139 | Codebuilder.build_code(funcname: "plt.tick_parameters", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
1140 | end
1141 |
1142 | @doc """
1143 | Change the ScalarFormatter used by default for linear axes.
1144 | """
1145 | def ticklabel_format(kwargs \\ []) do
1146 | Codebuilder.build_code(funcname: "plt.ticklabel_format", nonnamed: [], named: kwargs) |> Server.Commapi.add_code
1147 | end
1148 |
1149 | @doc """
1150 | Automatically adjust subplot parameters to give specified padding.
1151 | """
1152 | def tight_layout(opts \\ [pad: 1.08, h_pad: nil, w_pad: nil, rect: nil]) do
1153 | Codebuilder.build_code(funcname: "plt.tight_layout", nonnamed: [], named: opts) |> Server.Commapi.add_code
1154 | end
1155 |
1156 | @doc """
1157 | Set a title of the current axes.
1158 |
1159 | Set one of hte three available axes titles. The available titles are positioned above the aces in the center, flush with the left edge, and flush
1160 | with the right edge.
1161 | """
1162 | def title(s, opts \\ [], kwargs \\ []) do
1163 | Codebuilder.build_code(funcname: "plt.title", nonnamed: [s] ++ opts, named: kwargs) |> Server.Commapi.add_code
1164 | end
1165 |
1166 | @doc """
1167 | Draw contours on an unstructured triangular grid tricontour() and tricontourf() draw contour lines and filled contours,
1168 | respectively.
1169 | """
1170 | def tricontour(opts \\ [], kwargs \\ []) do
1171 | Codebuilder.build_code(funcname: "plt.tricontour", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1172 | end
1173 |
1174 | @doc """
1175 | Draw contours on an unstructured triangular grid tricontour() and tricontourf() draw contour lines and filled contours,
1176 | respectively.
1177 | """
1178 | def tricontourf(opts \\ [], kwargs \\ []) do
1179 | Codebuilder.build_code(funcname: "plt.tricontourf", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1180 | end
1181 |
1182 | @doc """
1183 | Create a pseudocolor plot of an unstructured triangular grid.
1184 | """
1185 | def tripcolor(opts \\ [], kwargs \\ []) do
1186 | Codebuilder.build_code(funcname: "plt.tripcolor", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1187 | end
1188 |
1189 | @doc """
1190 | Draw an unstructured triangular grid as lines and/or markers.
1191 | """
1192 | def triplot(opts \\ [], kwargs \\ []) do
1193 | Codebuilder.build_code(funcname: "plt.triplot", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1194 | end
1195 |
1196 | @doc """
1197 | Make a second axes that shares the x-axis. The new axes will overlay ax (or the current axes if ax is nil). The ticks for
1198 | ax2 will be placed on the right, and the ax2 instance is returned.
1199 | """
1200 | def twinx(opts \\ [ax: nil]) do
1201 | Codebuilder.build_code(funcname: "plt.twinx", nonnamed: [], named: opts) |> Server.Commapi.add_code
1202 | end
1203 |
1204 | @doc """
1205 | Make a second axes that shares the y-axis. The new axis will overlay ax (or the current axes if ax is nil). The ticks for
1206 | ax2 will be placed on the top, and the ax2 instance is returned.
1207 | """
1208 | def twiny(opts \\ [ax: nil]) do
1209 | Codebuilder.build_code(funcname: "plt.twiny", nonnamed: [], named: opts) |> Server.Commapi.add_code
1210 | end
1211 |
1212 | @doc """
1213 | Uninstalls the matplotlib display hook.
1214 | """
1215 | def uninstall_repl_displayhook do
1216 | Codebuilder.build_code(funcname: "plt.uninstall_repl_displayhook", nonnamed: [], named: []) |> Server.Commapi.add_code
1217 | end
1218 |
1219 | @doc """
1220 | Make a violin plot.
1221 |
1222 | Make a violin plot for each column of dataset or each vector in sequence dataset. Each filled area extends to represent the entire data
1223 | range, with optional lines at the mean, the median, the minimum, and the maximum.
1224 | """
1225 | def violinplot(dataset, opts \\ [positions: nil, vert: true, widths: 0.5, showmeans: false, showextrema: true, showmedians: false, points: 100, bw_method: nil,
1226 | hold: nil, data: nil]) do
1227 | Codebuilder.build_code(funcname: "plt.violinplot", nonnamed: [dataset], named: opts) |> Server.Commapi.add_code
1228 | end
1229 |
1230 | @doc """
1231 | Set the default colormap to viridis and apply to current image if any.
1232 | """
1233 | def viridis do
1234 | Codebuilder.build_code(funcname: "plt.viridis", nonnamed: [], named: []) |> Server.Commapi.add_code
1235 | end
1236 |
1237 | @doc """
1238 | Plot vertical lines.
1239 |
1240 | Plot vertical lines at each x from ymin to ymax.
1241 | """
1242 | def vlines(x, ymin, ymax, opts \\ [colors: :k, linestyles: :solid, label: "", hold: nil, data: nil], kwargs \\ []) do
1243 | Codebuilder.build_code(funcname: "plt.vlines", nonnamed: [x, ymin, ymax], named: opts ++ kwargs) |> Server.Commapi.add_code
1244 | end
1245 |
1246 | @doc """
1247 | Blocking call to interact with the figure.
1248 |
1249 | This will return "True" if a key was pressed, "False" if a mouse button was pressed and "None" if timeout was reached without either being pressed.
1250 |
1251 | If timeout is negative, does not timeout.
1252 | """
1253 | def waitforbuttonpress(opts \\ [], kwargs \\ []) do
1254 | Codebuilder.build_code(funcname: "plt.waitforbuttonpress", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1255 | end
1256 |
1257 | @doc """
1258 | Set the default colormap to winter and apply to current image if any.
1259 | """
1260 | def winter do
1261 | Codebuilder.build_code(funcname: "plt.winter", nonnamed: [], named: []) |> Server.Commapi.add_code
1262 | end
1263 |
1264 | @doc """
1265 | Plot the cross correlation between x and y.
1266 | """
1267 | def xcorr(x, y, opts \\ [normed: true, usevlines: true, maxlags: 10, hold: nil, data: nil], kwargs \\ []) do
1268 | Codebuilder.build_code(funcname: "plt.xcorr", nonnamed: [x, y], named: opts ++ kwargs) |> Server.Commapi.add_code
1269 | end
1270 |
1271 | @doc """
1272 | Turns xkcd sketch-style drawing mode. This will only have effect on things drawn after this function is called.
1273 |
1274 | For best results, the "Humor Sans" font should be indstalled: it is not included with matplotlib.
1275 | """
1276 | def xkcd(opts \\ [scaled: 1, length: 100, randomness: 2], kwargs \\ []) do
1277 | Codebuilder.build_code(funcname: "plt.xkcd", nonnamed: [], named: opts ++ kwargs) |> Server.Commapi.add_code
1278 | end
1279 |
1280 | @doc """
1281 | Set the x axis label of the current axis.
1282 | """
1283 | def xlabel(s, opts \\ [], kwargs \\ []) do
1284 | Codebuilder.build_code(funcname: "plt.xlabel", nonnamed: [s] ++ opts, named: kwargs) |> Server.Commapi.add_code
1285 | end
1286 |
1287 | @doc """
1288 | Get or set the x limits of the current axes.
1289 | """
1290 | def xlim(opts \\ [], kwargs \\ []) do
1291 | Codebuilder.build_code(funcname: "plt.xlim", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1292 | end
1293 |
1294 | @doc """
1295 | Set the scaling of the x-axis.
1296 | """
1297 | def xscale(opts \\ [], kwargs \\ []) do
1298 | Codebuilder.build_code(funcname: "plt.xscale", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1299 | end
1300 |
1301 | @doc """
1302 | Get or set the x-limits of the current tick locations and labels.
1303 | """
1304 | def xticks(opts \\ [], kwargs \\ []) do
1305 | Codebuilder.build_code(funcname: "plt.xticks", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1306 | end
1307 |
1308 | @doc """
1309 | Set the y-axis label of the current axis.
1310 | """
1311 | def ylabel(s, opts \\ [], kwargs \\ []) do
1312 | Codebuilder.build_code(funcname: "plt.ylabel", nonnamed: [s] ++ opts, named: kwargs) |> Server.Commapi.add_code
1313 | end
1314 |
1315 | @doc """
1316 | Get or set the y-limits of the current axes.
1317 | """
1318 | def ylim(opts \\ [], kwargs \\ []) do
1319 | Codebuilder.build_code(funcname: "plt.ylim", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1320 | end
1321 |
1322 | @doc """
1323 | Set the scaling of the y-axis.
1324 | """
1325 | def yscale(opts \\ [], kwargs \\ []) do
1326 | Codebuilder.build_code(funcname: "plt.yscale", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1327 | end
1328 |
1329 | @doc """
1330 | Get or set the y-limits of the current tick locations and labels.
1331 | """
1332 | def yticks(opts \\ [], kwargs \\ []) do
1333 | Codebuilder.build_code(funcname: "plt.yticks", nonnamed: opts, named: kwargs) |> Server.Commapi.add_code
1334 | end
1335 | end
1336 |
--------------------------------------------------------------------------------
/lib/server/commapi.ex:
--------------------------------------------------------------------------------
1 | defmodule Server.Commapi do
2 | use Supervisor
3 | @moduledoc """
4 | This is the API for the pycomm server. Don't call anything in there except through here.
5 | This is also its supervisor.
6 | """
7 |
8 | def start_link do
9 | Supervisor.start_link(__MODULE__, :ok)
10 | end
11 |
12 | def init(:ok) do
13 | children = [ worker(Server.Pycomm, [Server.Pycomm]) ]
14 | supervise(children, strategy: :one_for_one)
15 | end
16 |
17 | def add_code(code) do
18 | Server.Pycomm.eval_code(Server.Pycomm, code)
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/server/export.ex:
--------------------------------------------------------------------------------
1 | defmodule Expyplot.Export do
2 | @moduledoc """
3 | Wrapper for Erlport stolen from the interwebs.
4 | """
5 |
6 | @doc """
7 | Start the python instance.
8 |
9 | ## Examples
10 |
11 | iex> pid = Expyplot.Export.start()
12 | iex> is_pid(pid)
13 | true
14 |
15 | """
16 | def start(opts \\ []) do
17 | default_opts = [buffer_size: 65_536, call_timeout: :infinity, cd: '.',
18 | compressed: 5, start_timeout: 5_000, python: 'python',
19 | python_path: ['.']]
20 | opts = Keyword.merge(default_opts, opts)
21 | {:ok, pid} = :python.start(opts)
22 | pid
23 | end
24 |
25 | @doc """
26 | Execute the given function found in the given module with the given arguments and
27 | return the result.
28 |
29 | ## Examples
30 |
31 | iex> pid = Expyplot.Export.start()
32 | iex> Expyplot.Export.call(pid, :operator, :add, [5, 2])
33 | 7
34 |
35 | """
36 | def call(pid, mod, func, args \\ []) do
37 | res = :python.call(pid, mod, func, args)
38 | case res do
39 | :undefined -> nil
40 | x -> x
41 | end
42 | end
43 |
44 | @doc """
45 | Stops the Python instance.
46 |
47 | ## Examples
48 |
49 | iex> pid = Expyplot.Export.start()
50 | iex> Expyplot.Export.stop(pid)
51 | :ok
52 |
53 | """
54 | def stop(pid) do
55 | :python.stop(pid)
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/lib/server/pycomm.ex:
--------------------------------------------------------------------------------
1 | defmodule Server.Pycomm do
2 | use GenServer
3 | @moduledoc """
4 | This module is a GenServer that manages the Python code that will be executed.
5 |
6 | The general idea is that you will call functions in the library's API and this will usually add
7 | code here. Then when you call Expyplot.Plot.show(), it will flush the code to the Python3
8 | interpretor, thus making the plot.
9 |
10 | TODO: Switch this over to using Export.ex (which uses erlport under the hood)
11 | """
12 |
13 | @pyport 9849
14 | @signal "$<>;;<>%"
15 |
16 | ## Client API
17 |
18 | @doc """
19 | Starts the server.
20 | """
21 | def start_link(name) do
22 | GenServer.start_link(__MODULE__, :ok, name: name)
23 | end
24 |
25 | @doc """
26 | Adds the given code to the buffer.
27 | """
28 | def eval_code(pid, code) do
29 | GenServer.call(pid, {:eval, code}, :infinity)
30 | end
31 |
32 | ## Server Callbacks
33 |
34 | def init(:ok) do
35 | :gen_tcp.connect('localhost', @pyport, [:binary, packet: :line, active: false])
36 | end
37 |
38 | def handle_call(call, _from, to_python) do
39 | case call do
40 | {:eval, ""} ->
41 | raise ArgumentError, message: "Cannot supply Python with empty code string"
42 | {:eval, code} ->
43 | return_val = send_to_python(code, to_python)
44 | {:reply, return_val, to_python}
45 | end
46 | end
47 |
48 | ## Helper Functions
49 |
50 | defp send_to_python(code, to_python) do
51 | do_send_to_python(code, to_python)
52 | end
53 |
54 | defp do_send_to_python(code, to_python) do
55 | max_size = 4096 - String.length(@signal)
56 | chunk = code |> String.slice(0..max_size)
57 | leftover = code |> String.slice((max_size + 1)..-1)
58 | cond do
59 | String.length(chunk) <= max_size ->
60 | write_line(chunk <> "\n" <> @signal, to_python)
61 | read_line to_python
62 | String.length(chunk) > max_size ->
63 | write_line(chunk, to_python)
64 | do_send_to_python(leftover, to_python)
65 | end
66 | end
67 |
68 | defp read_line(from) do
69 | do_read_line(from, "")
70 | end
71 |
72 | defp do_read_line(from, acc) do
73 | {:ok, data} = :gen_tcp.recv(from, 0)
74 | if String.ends_with?(data, @signal <> "\n") do
75 | i = String.length(data) - (String.length(@signal <> "\n") + 1)
76 | last = String.slice(data, 0..i)
77 | acc <> last
78 | else
79 | do_read_line(from, acc <> data)
80 | end
81 | end
82 |
83 | defp write_line(line, to) do
84 | :gen_tcp.send(to, line)
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/lib/server/pyserver.ex:
--------------------------------------------------------------------------------
1 | defmodule Server.Pyserver do
2 | use GenServer
3 |
4 | @pyport 9849
5 | @pyserver_location "mat.py"
6 |
7 | ## Client API
8 |
9 | @doc """
10 | Starts the server.
11 | """
12 | def start_link(name) do
13 | GenServer.start_link(__MODULE__, :ok, name: name)
14 | end
15 |
16 | ## Server Callbacks
17 |
18 | def init(:ok) do
19 | _pwd = File.cwd!()
20 | system_python = get_python()
21 | spawn fn -> System.cmd(system_python, [Path.join([:code.priv_dir(:expyplot), @pyserver_location]), Integer.to_string(@pyport)]) end
22 | {:ok, %{}}
23 | end
24 |
25 | ## Helper Functions
26 |
27 | defp get_python do
28 | # Check the system for python3, then for python
29 | if System.find_executable("python3") do
30 | "python3"
31 | else
32 | "python"
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/server/pysupervisor.ex:
--------------------------------------------------------------------------------
1 | defmodule Server.Pysupervisor do
2 | use Supervisor
3 | @moduledoc """
4 | This is the Supervisor for the python code. It restarts it whenever it goes down.
5 | """
6 |
7 | def start_link do
8 | Supervisor.start_link(__MODULE__, :ok)
9 | end
10 |
11 | def init(:ok) do
12 | children = [ worker(Server.Pyserver, [Server.Pyserver]) ]
13 | supervise(children, strategy: :one_for_one)
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/mix.exs:
--------------------------------------------------------------------------------
1 | defmodule Expyplot.Mixfile do
2 | use Mix.Project
3 |
4 | @version "1.1.3"
5 |
6 | def project do
7 | [app: :expyplot,
8 | version: @version,
9 | elixir: "~> 1.8",
10 | build_embedded: Mix.env == :prod,
11 | start_permanent: Mix.env == :prod,
12 | deps: deps(),
13 | docs: docs(),
14 | package: package(),
15 | description: description(),
16 | ]
17 | end
18 |
19 | # Configuration for the OTP application
20 | #
21 | # Type "mix help compile.app" for more information
22 | def application do
23 | # Specify extra applications you'll use from Erlang/Elixir
24 | [extra_applications: [:logger],
25 | mod: {Expyplot, []},
26 | ]
27 | end
28 |
29 | # Dependencies can be Hex packages:
30 | #
31 | # {:my_dep, "~> 0.3.0"}
32 | #
33 | # Or git/path repositories:
34 | #
35 | # {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
36 | #
37 | # Type "mix help deps" for more examples and options
38 | defp deps do
39 | [
40 | {:erlport, "~> 0.9"},
41 | {:statistics, "~> 0.4.1"},
42 | {:earmark, "~> 1.3.2"},
43 | {:ex_doc, "~> 0.20.2"},
44 | ]
45 | end
46 |
47 | defp docs do
48 | [main: "Expyplot.Plot"]
49 | end
50 |
51 | defp package do
52 | [
53 | files: ["lib", "mix.exs", "README.md", "config", "priv", "examples", "LICENSE"],
54 | maintainers: ["Max Strange"],
55 | licenses: ["MIT"],
56 | links: %{"GitHub" => "https://github.com/MaxStrange/expyplot"}
57 | ]
58 | end
59 |
60 | defp description do
61 | """
62 | Python's matplotlib.pyplot ported to Elixir. Inspired by https://github.com/JordiPolo/explot
63 |
64 | This library provides a fairly transparent wrapper for matplotlib.pyplot.
65 | """
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/priv/mat.py:
--------------------------------------------------------------------------------
1 | """
2 | This module is the Matplotlib server, Python side. It sits around waiting for Python code to come over the port, executes it, and returns
3 | the result to the sender wrapped up in JSON.
4 | """
5 | import numpy as np
6 | import os
7 | import socket
8 | import sys
9 | import traceback
10 |
11 | import matplotlib
12 | if "SSH_CONNECTION" in os.environ:
13 | matplotlib.use("agg")
14 | import matplotlib.pyplot as plt
15 | else:
16 | import matplotlib.pyplot as plt
17 | plt.switch_backend("Qt5Agg")
18 |
19 | signal = "$<>;;<>%"
20 |
21 | def accumulate(client):
22 | accumulated = ""
23 | while True:
24 | got = client.recv(4096).decode("ascii")
25 | print("Received:", got)
26 | accumulated += got
27 | if accumulated.endswith(signal):
28 | break
29 | print("Accumulated before strip:", accumulated)
30 | accumulated = accumulated.rstrip(signal)
31 | print("Accumulated after strip:", accumulated)
32 | return accumulated
33 |
34 | def try_evaluate(to_evaluate):
35 | try:
36 | print("Going to execute:", to_evaluate)
37 | val = eval(to_evaluate.strip())
38 | print("Success, got back:", val)
39 | return val
40 | except Exception as e:
41 | print("Exception:", e)
42 | traceback.print_exc()
43 | return str(e)
44 |
45 | def send_to_caller(result):
46 | to_send = (result + os.linesep).encode("ascii")
47 | client.send(to_send)
48 |
49 | def stringify(result):
50 | if isinstance(result, np.ndarray):
51 | return np.array_str(result) + signal
52 | else:
53 | return str(result) + signal
54 |
55 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
56 | host = "localhost"
57 | port = int(sys.argv[1])
58 | s.bind((host, port))
59 | s.listen(1)
60 |
61 | client, _addr = s.accept()
62 | while True:
63 | to_evaluate = accumulate(client)
64 | for stat in to_evaluate.split(os.linesep):
65 | if stat.strip().rstrip(signal).strip():
66 | result = try_evaluate(stat)
67 | result = stringify(result)
68 | print("Sending back:", result)
69 | send_to_caller(result)
70 |
71 |
--------------------------------------------------------------------------------
/test/expyplot_test.exs:
--------------------------------------------------------------------------------
1 | defmodule ExpyplotTest do
2 | use ExUnit.Case
3 | doctest Expyplot
4 |
5 | test "the truth" do
6 | assert 1 + 1 == 2
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/expyplotplot_test.exs:
--------------------------------------------------------------------------------
1 | defmodule ExpyplotPlotTest do
2 | use ExUnit.Case
3 | doctest Expyplot.Plot
4 | end
5 |
--------------------------------------------------------------------------------
/test/test_helper.exs:
--------------------------------------------------------------------------------
1 | ExUnit.start()
2 |
--------------------------------------------------------------------------------