├── .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 | ![Histogram](images/histogram.png) 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 | ![Subplots](images/subplots.png) 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 | ![Zorder](images/zorder.png) 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 | ![Bar Graph](images/bar.png) 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 | --------------------------------------------------------------------------------