Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/matplotex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule Matplotex do
@moduledoc """
Module to generate a graph.
"""
alias Matplotex.Figure.Areal.Histogram
alias Matplotex.InputError
alias Matplotex.Figure.Radial.Pie
alias Matplotex.Figure.Areal.Scatter
Expand Down Expand Up @@ -83,6 +84,10 @@ defmodule Matplotex do
|> LinePlot.create({x, y}, opts)
end

def hist(data, bins, opts) do
Histogram.create(%Figure{axes: %Histogram{}}, {data, bins}, opts)
end

@doc """
Sets X and Y labels for the graph with given font details

Expand Down
9 changes: 7 additions & 2 deletions lib/matplotex/element/rect.ex
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
defmodule Matplotex.Element.Rect do
alias Matplotex.Element

@default_stroke_width 1
@default_stroke "rgba(0,0,0,0)"
@default_stroke_width 2
@default_stroke "black"
@default_opacity 1.0
use Element

@type t :: %__MODULE__{
Expand All @@ -22,6 +23,8 @@ defmodule Matplotex.Element.Rect do
:color,
:type,
stroke: @default_stroke,
fill_opacity: @default_opacity,
stroke_opacity: @default_opacity,
stroke_width: @default_stroke_width
]

Expand All @@ -37,6 +40,8 @@ defmodule Matplotex.Element.Rect do
width="#{get_width(rect)}"
height="#{get_height(rect)}"
stroke-width="#{rect.stroke_width}"
stroke-opacity="#{rect.stroke_opacity}"
fill-opacity="#{rect.fill_opacity}"
filter="">
</rect>)
end
Expand Down
29 changes: 9 additions & 20 deletions lib/matplotex/figure/areal.ex
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
defmodule Matplotex.Figure.Areal do
alias Matplotex.Figure.Areal.Ticker
alias Matplotex.Utils.Algebra
alias Matplotex.Figure.Dataset
alias Matplotex.Figure.TwoD
@callback create(struct(), any(), keyword()) :: struct()
@callback materialize(struct()) :: struct()
@callback plotify(number(), tuple(), number(), number(), list(), atom()) :: number()
@callback with_legend_handle(struct(), struct()) :: struct()
@optional_callbacks with_legend_handle: 2
defmacro __using__(_) do
quote do
@behaviour Matplotex.Figure.Areal
Expand Down Expand Up @@ -79,8 +80,13 @@ defmodule Matplotex.Figure.Areal do
|> update_tick(tick)
end

def add_ticks(%__MODULE__{tick: tick, size: size} = axes, {key, {_min, _max} = lim}) do
{ticks, lim} = __MODULE__.generate_ticks(lim)
def add_ticks(%__MODULE__{tick: tick, size: {width, height}= size} = axes, {key, {_min, _max} = lim}) do
number_of_ticks = if key == :x do
ceil(width)
else
ceil(height)
end
{ticks, lim} = Ticker.generate_ticks(lim, number_of_ticks )

tick = Map.put(tick, key, ticks)

Expand Down Expand Up @@ -116,23 +122,6 @@ defmodule Matplotex.Figure.Areal do
%{axes | legend: legend}
end

def generate_xticks(%module{data: {x, _y}, tick: tick, limit: limit} = axes) do
{xticks, xlim} =
module.generate_ticks(x)

tick = Map.put(tick, :x, xticks)
limit = update_limit(limit, :x, xlim)
%__MODULE__{axes | tick: tick, limit: limit}
end

def generate_yticks(%module{data: {_x, y}, tick: tick, limit: limit} = axes) do
{yticks, ylim} =
module.generate_ticks(y)

tick = Map.put(tick, :y, yticks)
limit = update_limit(limit, :y, ylim)
%__MODULE__{axes | tick: tick, limit: limit}
end

defp update_limit(%TwoD{x: nil} = limit, :x, xlim) do
%TwoD{limit | x: xlim}
Expand Down
11 changes: 0 additions & 11 deletions lib/matplotex/figure/areal/bar_chart.ex
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,6 @@ defmodule Matplotex.Figure.Areal.BarChart do
%Figure{figure | axes: %{axes | element: elements_with_bar}}
end

@impl Areal
def plotify(value, {minl, maxl}, axis_size, transition, _data, :x) do
s = axis_size / (maxl - minl)
value * s + transition - minl * s
end

def plotify(value, {minl, maxl}, axis_size, transition, _data, :y) do
s = axis_size / (maxl - minl)
value * s + transition - minl * s
end

@impl Areal
def with_legend_handle(
%Legend{x: x, y: y, color: color, width: width, height: height} = legend,
Expand Down
127 changes: 127 additions & 0 deletions lib/matplotex/figure/areal/histogram.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
defmodule Matplotex.Figure.Areal.Histogram do
alias Matplotex.Element.Rect
alias Matplotex.Figure.RcParams
alias Matplotex.Figure.Areal.PlotOptions
alias Matplotex.Figure.Dataset
alias Matplotex.Figure.Areal.Region
alias Matplotex.Figure
alias Matplotex.Figure.Areal
use Areal

@make_it_zero 0

frame(
tick: %TwoD{},
limit: %TwoD{},
label: %TwoD{},
scale: %TwoD{},
region_x: %Region{},
region_y: %Region{},
region_title: %Region{},
region_legend: %Region{},
region_content: %Region{}
)

@impl Areal
def create(%Figure{axes: %__MODULE__{} = axes, rc_params: rc_params} = figure, {data, bins}, opts) do
{x, y} = bins_and_hists(data, bins)

dataset = Dataset.cast(%Dataset{x: x, y: y}, opts)
%Figure{figure | axes: %__MODULE__{axes | data: {x, y}, dataset: [dataset]}, rc_params: %RcParams{rc_params | y_padding: @make_it_zero}}
|> PlotOptions.set_options_in_figure(opts)
end

@impl Areal
def materialize(figure) do
figure
|> sanitize()
|> __MODULE__.materialized_by_region()
|> materialize_hist()
end

defp materialize_hist(%Figure{axes: %{dataset: data,limit: %TwoD{x: x_lim, y: y_lim}, region_content: %Region{x: x_region_content, y: y_region_content, width: width_region_content, height: height_region_content}, element: element}, rc_params: %RcParams{x_padding: x_padding, white_space: white_space}}) do
x_padding_value = width_region_content * x_padding + white_space
shrinked_width_region_content = width_region_content - x_padding_value * 2

hist_elements =
data
|>Enum.map(fn dataset ->
dataset
|> do_transform(x_lim, y_lim, shrinked_width_region_content, height_region_content, {x_region_content + x_padding_value, y_region_content})
|> capture(abs(y_region_content), shrinked_width_region_content)
end)
|>List.flatten()
%Figure{axes: %{element: element ++ hist_elements}}
end

defp capture(%Dataset{transformed: transformed} = dataset, bly, region_width) do
capture(transformed, [], dataset, bly, region_width)
end

defp capture(
[{x, y} | to_capture],
captured,
%Dataset{
color: color,
x: bins,
pos: pos_factor,
edge_color: edge_color,
alpha: alpha
} = dataset,
bly,
region_width
) do
capture(
to_capture,
captured ++
[
%Rect{
type: "figure.histogram",
x: bin_position(x, pos_factor),
y: y,
width: region_width / length(bins),
height: bly - y,
color: color,
stroke: edge_color,
fill_opacity: alpha,
stroke_opacity: alpha
}
],
dataset,
bly,
region_width
)
end

defp capture([], captured, _dataset, _bly, _region_width), do: captured


defp bin_position(x, pos_factor) when pos_factor < 0 do
x + pos_factor
end

defp bin_position(x, _pos_factor), do: x
defp bins_and_hists(data, bins) do
{data_min, data_max} = Enum.min_max(data)

bins_dist =
data_min
|> Nx.linspace(data_max, n: bins)
|> Nx.to_list()

{hists, _} =
Enum.map_reduce(bins_dist, data_min, fn bin, previous_bin ->
frequency = Enum.frequencies_by(data, fn point -> point < bin && point > previous_bin end)
{Map.get(frequency, true, 0), bin}
end)

{bins_dist, hists}
end

defp sanitize(%Figure{axes: %__MODULE__{data: {x, y}}= axes} = figure) do
{ymin, ymax} = Enum.min_max(y)
{xmin, xmax} = Enum.min_max(x)

%Figure{figure | axes: %__MODULE__{axes | limit: %TwoD{x: {floor(xmin), ceil(xmax)},y: {floor(ymin), ceil(ymax)}}}}
end
end
6 changes: 0 additions & 6 deletions lib/matplotex/figure/areal/line_plot.ex
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,6 @@ defmodule Matplotex.Figure.Areal.LinePlot do
%Figure{figure | axes: %{axes | element: elements}}
end

@impl Areal
def plotify(value, {minl, maxl}, axis_size, transition, _, _) do
s = axis_size / (maxl - minl)
value * s + transition - minl * s
end

@impl Areal
def with_legend_handle(
%Legend{x: x, y: y, color: color, width: marker_size} = legend,
Expand Down
5 changes: 0 additions & 5 deletions lib/matplotex/figure/areal/plot_options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,9 @@ defmodule Matplotex.Figure.Areal.PlotOptions do
%Figure{
figure
| axes: axes |> struct(opts) |> cast_two_d_structs(opts)
# |>fulfill_tick_and_lim()
}
end

# defp fulfill_tick_and_lim(%{tick: nil, limit: nil} = axes) do

# end

defp cast_two_d_structs(%{label: label, tick: tick, limit: limit} = axes, opts)
when is_map(opts) do
%{
Expand Down
5 changes: 0 additions & 5 deletions lib/matplotex/figure/areal/scatter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,6 @@ defmodule Matplotex.Figure.Areal.Scatter do
end

defp capture(_, captured, _), do: captured
@impl Areal
def plotify(value, {minl, maxl}, axis_size, transition, _, _) do
s = axis_size / (maxl - minl)
value * s + transition - minl * s
end

@impl Areal
def with_legend_handle(
Expand Down
3 changes: 3 additions & 0 deletions lib/matplotex/figure/areal/ticker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ defmodule Matplotex.Figure.Areal.Ticker do
step = (max - min) / @tick_in_plot
produce_ticks(min, max, step, [format_number(min)])
end
def generate_ticks({lower_limit, upper_limit} = lim, number_of_ticks) do
{lower_limit |> Nx.linspace(upper_limit, n: number_of_ticks) |> Nx.to_list(), lim}
end

defp produce_ticks(value, max, _step, ticks) when value >= max do
Enum.reverse(ticks)
Expand Down
Loading
Loading