Created
February 17, 2016 22:10
-
-
Save johnhamelink/9db12f0d51700eb7763b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| defmodule Api.Slack.Gnuplot do | |
| alias Porcelain.Process, as: Proc | |
| alias Porcelain.Result | |
| require Logger | |
| @type line :: %{title: String.t, dataset: [List.t]} | |
| @doc """ | |
| Produces a line-graph PNG. The result is in binary. | |
| iex> Api.Slack.Gnuplot.line_graph([%{title: "Test", dataset: [[0,1], [1,5], [2,3]]}]) | |
| iex> Api.Slack.Gnuplot.line_graph([ %{title: "A", dataset: [[0,1], [1,5], [2,3]]}, %{title: "B", dataset: [[0,3], [1,5], [2,9]]}, %{title: "C", dataset: [[0,4], [1,1], [2,6]]}, ]) | |
| """ | |
| @spec line_graph([line]) :: binary | |
| def line_graph(lines) do | |
| lines | |
| |> plot_series | |
| |> plot | |
| end | |
| @doc """ | |
| Generate the inline plot & dataset configuration | |
| to send to gnuplot | |
| """ | |
| def plot_series(series) do | |
| series = do_plot_series(series) | |
| require IEx | |
| IEx.pry | |
| axes = series | |
| |> Enum.map(fn(axis) -> axis.axis end) | |
| |> Enum.reduce("plot ", &(&2 <> &1 <> ", \n")) | |
| datasets = series | |
| |> Enum.map(fn(axis) -> axis.data end) | |
| |> Enum.reduce("", &(&2 <> &1 <> "\nEOF\n")) | |
| """ | |
| #{axes} | |
| #{datasets} | |
| """ | |
| end | |
| def do_plot_series([series | tail]) do | |
| [do_plot_series(series), do_plot_series(tail)] | |
| |> Enum.reject(&(&1 == nil)) | |
| end | |
| def do_plot_series([series = %{}]), do: do_plot_series(series) | |
| def do_plot_series([]), do: nil | |
| def do_plot_series(%{title: title, dataset: dataset}) do | |
| # TODO: figure out the size of each array instead of | |
| # hardcoding 0 and 1 | |
| data_string = | |
| dataset | |
| |> Enum.map(fn (set) -> | |
| "#{Enum.fetch!(set, 0)} #{Enum.fetch!(set, 1)}" | |
| end) | |
| |> Enum.join("\n") | |
| %{ | |
| axis: ~s('-' using 1:2 title "#{title}" with lp), | |
| data: data_string | |
| } | |
| end | |
| @doc """ | |
| plot will prepend generic styling rules to gnuplot, then send | |
| the final configuration to gnuplot to process. It'll then retrieve | |
| the response body and return it. | |
| """ | |
| def plot(msg) do | |
| content = [ | |
| "# Clean basis for SVG", | |
| "set encoding utf8", | |
| "set terminal pngcairo enhanced transparent font 'Verdana,10' size 640,480", | |
| "# Line width of the axes", | |
| "set border linewidth 1.5", | |
| "# line styles", | |
| "set style line 1 lt 1 lc rgb '#D53E4F' # red", | |
| "set style line 2 lt 1 lc rgb '#F46D43' # orange", | |
| "set style line 3 lt 1 lc rgb '#FDAE61' # pale orange", | |
| "set style line 4 lt 1 lc rgb '#FEE08B' # pale yellow-orange", | |
| "set style line 5 lt 1 lc rgb '#E6F598' # pale yellow-green", | |
| "set style line 6 lt 1 lc rgb '#ABDDA4' # pale green", | |
| "set style line 7 lt 1 lc rgb '#66C2A5' # green", | |
| "set style line 8 lt 1 lc rgb '#3288BD' # blue", | |
| "# palette", | |
| "set palette defined ( \\", | |
| "0 '#D53E4F',\\", | |
| "1 '#F46D43',\\", | |
| "2 '#FDAE61',\\", | |
| "3 '#FEE08B',\\", | |
| "4 '#E6F598',\\", | |
| "5 '#ABDDA4',\\", | |
| "6 '#66C2A5',\\", | |
| "7 '#3288BD'\\", | |
| ")", | |
| msg | |
| ] |> Enum.join("\n") | |
| |> String.replace(~s("), ~s(\\")) | |
| cmd = ~s(echo "#{content}" | gnuplot) | |
| IO.puts(cmd) | |
| %Porcelain.Result{err: nil, out: out, status: 0} = | |
| cmd | |
| |> Porcelain.shell | |
| File.write("/Users/john/out.png", out) | |
| out | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment