From 15bc12df89fa9aa7fb70ef38818bee829eccd13d Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Fri, 13 Dec 2024 13:28:53 +0530 Subject: [PATCH 1/4] radial regions --- lib/matplotex/blueprint/chord.ex | 7 ++++- lib/matplotex/figure/areal.ex | 2 +- lib/matplotex/figure/lead.ex | 24 ++++++++++++--- test/matplotex/figure/cast_test.exs | 14 ++++----- test/matplotex/figure/lead_test.exs | 45 ++++++++++++++++++++++------- test/support/plot_case.ex | 4 +-- 6 files changed, 70 insertions(+), 26 deletions(-) diff --git a/lib/matplotex/blueprint/chord.ex b/lib/matplotex/blueprint/chord.ex index c22481f..d9fa876 100644 --- a/lib/matplotex/blueprint/chord.ex +++ b/lib/matplotex/blueprint/chord.ex @@ -1,6 +1,7 @@ defmodule Matplotex.Blueprint.Chord do @true_by_default false @false_by_default true + @chart_type :radial defmacro chord(opts \\ []) do build_chord(opts) end @@ -30,7 +31,11 @@ defmodule Matplotex.Blueprint.Chord do element: [], legend_pos: nil, border: nil, - show_legend: @false_by_default + show_legend: @false_by_default, + region_title: nil, + region_legend: nil, + region_content: nil, + border: nil ] |> Keyword.merge(opts) ) diff --git a/lib/matplotex/figure/areal.ex b/lib/matplotex/figure/areal.ex index 1aadc7b..268cb90 100644 --- a/lib/matplotex/figure/areal.ex +++ b/lib/matplotex/figure/areal.ex @@ -143,7 +143,7 @@ defmodule Matplotex.Figure.Areal do def materialized_by_region(figure) do figure - |> Lead.set_regions() + |> Lead.set_regions_areal() |> Cast.cast_xticks_by_region() |> Cast.cast_yticks_by_region() |> Cast.cast_hgrids_by_region() diff --git a/lib/matplotex/figure/lead.ex b/lib/matplotex/figure/lead.ex index 28ff82b..3c8c89d 100644 --- a/lib/matplotex/figure/lead.ex +++ b/lib/matplotex/figure/lead.ex @@ -11,9 +11,9 @@ defmodule Matplotex.Figure.Lead do @padding 10 / 96 @zero_to_move 0 - @spec set_regions(Matplotex.Figure.t()) :: Matplotex.Figure.t() + @spec set_regions_areal(Matplotex.Figure.t()) :: Matplotex.Figure.t() - def set_regions(%Figure{figsize: {width, height}} = figure) when width > 0 and height > 0 do + def set_regions_areal(%Figure{figsize: {width, height}} = figure) when width > 0 and height > 0 do figure |> set_frame_size() |> ensure_ticks_are_valid() @@ -23,8 +23,16 @@ defmodule Matplotex.Figure.Lead do |> set_region_content() end - def set_regions(figure), do: figure + def set_regions_areal(figure), do: figure + def set_regions_radial(%Figure{figsize: {width, height}} = figure) when width > 0 and height >0 do + figure + |> set_frame_size() + |> set_region_title() + |> set_region_legend() + |> set_region_content() + end + def set_regions_radial(figure), do: figure def set_border(%Figure{margin: margin, axes: axes, figsize: {fig_width, fig_height}} = figure) do margin = margin / 2 lx = fig_width * margin @@ -179,7 +187,7 @@ defmodule Matplotex.Figure.Lead do space_for_title = height_required_for_text(title_font, title) {x_region_title, y_region_title} = - Algebra.transform_given_point(@zero_to_move, -space_for_title, lx, ty, 0) + Algebra.transform_given_point(@zero_to_move, -space_for_title, lx, ty) %Figure{ figure @@ -200,6 +208,14 @@ defmodule Matplotex.Figure.Lead do } end + defp set_region_title(%Figure{axes: %{title: title, center: _center, border: {lx, _by, _rx, ty}, size: {width, height}} = axes, rc_params: %RcParams{title_font: title_font}} = figure) do + space_for_title = height_required_for_text(title_font, title) + + {x_region_title, y_region_title} = Algebra.transform_given_point(@zero_to_move, -space_for_title, lx, ty ) + + %Figure{figure | axes: %{axes | region_title: %Region{x: x_region_title, y: y_region_title, width: width, height: space_for_title}}} + end + defp set_region_legend( %Figure{ axes: diff --git a/test/matplotex/figure/cast_test.exs b/test/matplotex/figure/cast_test.exs index f78d994..ef89f9d 100644 --- a/test/matplotex/figure/cast_test.exs +++ b/test/matplotex/figure/cast_test.exs @@ -12,7 +12,7 @@ defmodule Matplotex.Figure.CastTest do describe "cast_spines_by_region/1" do test "add elements for borders in axes", %{figure: figure} do - figure = Lead.set_regions(figure) + figure = Lead.set_regions_areal(figure) assert %Figure{axes: %{element: elements}} = Cast.cast_spines_by_region(figure) assert Enum.any?(elements, fn x -> x.type == "spine.top" end) @@ -26,7 +26,7 @@ defmodule Matplotex.Figure.CastTest do test "add element for title in axes", %{figure: figure} do assert %Figure{axes: %{element: elements}} = figure - |> Lead.set_regions() + |> Lead.set_regions_areal() |> Cast.cast_spines_by_region() |> Cast.cast_title_by_region() @@ -38,7 +38,7 @@ defmodule Matplotex.Figure.CastTest do test "add element for label in axes", %{figure: figure} do assert %Figure{axes: %{element: elements}} = figure - |> Lead.set_regions() + |> Lead.set_regions_areal() |> Cast.cast_label_by_region() assert Enum.any?(elements, fn x -> x.type == "figure.x_label" end) @@ -50,7 +50,7 @@ defmodule Matplotex.Figure.CastTest do test "add element for tick in axes", %{figure: figure} do assert %Figure{axes: %{element: elements, tick: %{x: x_ticks, y: _y_ticks}}} = figure - |> Lead.set_regions() + |> Lead.set_regions_areal() |> Cast.cast_xticks_by_region() assert Enum.filter(elements, fn x -> x.type == "figure.x_tick" end) |> length() == @@ -62,7 +62,7 @@ defmodule Matplotex.Figure.CastTest do test "add element for tick in axes", %{figure: figure} do assert %Figure{axes: %{element: elements, tick: %{y: y_ticks}}} = figure - |> Lead.set_regions() + |> Lead.set_regions_areal() |> Cast.cast_yticks_by_region() assert Enum.filter(elements, fn x -> x.type == "figure.y_tick" end) |> length() == @@ -76,7 +76,7 @@ defmodule Matplotex.Figure.CastTest do test "add elements for horizontal grids", %{figure: figure} do assert %Figure{axes: %{element: elements, tick: %{y: y_ticks}}} = figure - |> Lead.set_regions() + |> Lead.set_regions_areal() |> Cast.cast_yticks_by_region() |> Cast.cast_hgrids_by_region() @@ -89,7 +89,7 @@ defmodule Matplotex.Figure.CastTest do test "add elements for vertical grids", %{figure: figure} do assert %Figure{axes: %{element: elements, tick: %{x: x_ticks}}} = figure - |> Lead.set_regions() + |> Lead.set_regions_areal() |> Cast.cast_xticks_by_region() |> Cast.cast_vgrids_by_region() diff --git a/test/matplotex/figure/lead_test.exs b/test/matplotex/figure/lead_test.exs index 5c1cd93..b9bf6bb 100644 --- a/test/matplotex/figure/lead_test.exs +++ b/test/matplotex/figure/lead_test.exs @@ -6,8 +6,18 @@ defmodule Matplotex.Figure.LeadTest do alias Matplotex.Figure.Lead - setup do - figure = Matplotex.FrameHelpers.sample_figure() + setup(context) do + figure = + if context.radial do + categories = ["2008", "2009", "2010", "2011"] + values = [18.48923375, 17.1923791, 17.48479218, 17.02021634] + + colors = ["#76b5c5", "#DEDEDE", "#FBD1A2", "#6195B4"] + Matplotex.pie(values, colors: colors, labels: categories) + else + Matplotex.FrameHelpers.sample_figure() + end + frame_width = 8 frame_height = 6 @@ -28,14 +38,14 @@ defmodule Matplotex.Figure.LeadTest do {:ok, %{figure: figure, figure2: figure2}} end - describe "set_regions/1" do + describe "set_regions_areal/1" do test "sets region_xy", %{figure2: figure} do assert %Figure{ axes: %{ region_x: %Region{x: rxx, y: rxy, width: rxwidth, height: rxheight}, region_y: %Region{x: ryx, y: ryy, width: rywidth, height: ryheight} } - } = Lead.set_regions(figure) + } = Lead.set_regions_areal(figure) assert Enum.all?([rxx, rxy, rxwidth, rxheight, ryx, ryy, rywidth, ryheight], &(&1 != 0)) end @@ -45,7 +55,7 @@ defmodule Matplotex.Figure.LeadTest do axes: %{ region_title: %Region{x: rtx, y: rty, width: rtwidth, height: rtheight} } - } = Lead.set_regions(figure) + } = Lead.set_regions_areal(figure) assert Enum.all?([rtx, rty, rtwidth, rtheight], &(&1 != 0)) end @@ -57,7 +67,7 @@ defmodule Matplotex.Figure.LeadTest do axes: %{ region_legend: %Region{x: rlx, y: rly, width: rlwidth, height: rlheight} } - } = Lead.set_regions(figure) + } = Lead.set_regions_areal(figure) assert Enum.all?([rlx, rly, rlwidth, rlheight], &(&1 != 0)) end @@ -69,7 +79,7 @@ defmodule Matplotex.Figure.LeadTest do region_y: %Region{y: ryy, height: ryheight}, region_content: %Region{x: rcx, y: rcy, width: rcwidth, height: rcheight} } - } = Lead.set_regions(figure) + } = Lead.set_regions_areal(figure) assert rxx == rcx assert ryy == rcy @@ -91,7 +101,7 @@ defmodule Matplotex.Figure.LeadTest do tick: %TwoD{x: xticks, y: yticks}, data: {x, y} } - } = Lead.set_regions(figure) + } = Lead.set_regions_areal(figure) assert Enum.min(xticks) == 0 assert Enum.min(yticks) == 0 @@ -112,7 +122,7 @@ defmodule Matplotex.Figure.LeadTest do region_title: %Region{x: rtx, y: rty, width: rtwidth, height: rtheight}, region_content: %Region{x: rcx, y: rcy, width: rcwidth, height: rcheight} } - } = Lead.set_regions(figure) + } = Lead.set_regions_areal(figure) assert rxx == 0 assert ryy == 0 @@ -137,7 +147,7 @@ defmodule Matplotex.Figure.LeadTest do region_title: %Region{height: rtheight}, region_content: %Region{height: rcheight} } - } = Lead.set_regions(figure) + } = Lead.set_regions_areal(figure) margin_two_side = height * margin * 2 assert height == margin_two_side + rxheight + rtheight + rcheight @@ -152,9 +162,22 @@ defmodule Matplotex.Figure.LeadTest do region_content: %Region{width: rcwidth}, region_legend: %Region{width: rlwidth} } - } = Lead.set_regions(figure) + } = Lead.set_regions_areal(figure) two_side_margin = width * margin * 2 assert width == two_side_margin + ry_width + rcwidth + rlwidth end + + describe "set_regions_areal" do + @tag radial: true + test "updates with all borders" do + %Figure{axes: %{border: {lx, by, rx, ty}}} = Lead.set_regions_radial(figure) + assert lx > 0 && by > 0 && rx > 0 && ty > 0 + end + @tag radial: true + test "updates region titles" do + %Figure{axes: %{region_title: %Region{}}} = Lead.set_regions_radial(figure) + end + + end end diff --git a/test/support/plot_case.ex b/test/support/plot_case.ex index 86f7d65..e2dc2be 100644 --- a/test/support/plot_case.ex +++ b/test/support/plot_case.ex @@ -9,11 +9,11 @@ defmodule Matplotex.PlotCase do end def set_figure() do - figure = Matplotex.FrameHelpers.sample_figure() |> Lead.set_spines() + figure = Matplotex.FrameHelpers.sample_figure() {:ok, %{figure: figure}} end def set_bar() do - {:ok, %{figure: Matplotex.FrameHelpers.bar() |> Lead.set_spines()}} + {:ok, %{figure: Matplotex.FrameHelpers.bar()}} end end From e32f301020f5e5c9ab215994521780a16f6d6918 Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Mon, 16 Dec 2024 19:01:09 +0530 Subject: [PATCH 2/4] radial regions --- lib/matplotex/blueprint/chord.ex | 4 +- lib/matplotex/figure/areal.ex | 114 ++++++++- lib/matplotex/figure/areal/bar_chart.ex | 9 +- lib/matplotex/figure/areal/region.ex | 8 +- lib/matplotex/figure/cast.ex | 9 +- lib/matplotex/figure/lead.ex | 309 +++++++++--------------- lib/matplotex/figure/radial.ex | 104 +++++++- lib/matplotex/figure/radial/pie.ex | 11 +- lib/matplotex/figure/rc_params.ex | 1 + lib/matplotex/helpers.ex | 2 +- lib/matplotex/utils/algebra.ex | 8 +- test/matplotex/figure/cast_test.exs | 1 - test/matplotex/figure/lead_test.exs | 89 ++++++- test/support/plot_case.ex | 1 - 14 files changed, 449 insertions(+), 221 deletions(-) diff --git a/lib/matplotex/blueprint/chord.ex b/lib/matplotex/blueprint/chord.ex index d9fa876..41940bd 100644 --- a/lib/matplotex/blueprint/chord.ex +++ b/lib/matplotex/blueprint/chord.ex @@ -1,7 +1,6 @@ defmodule Matplotex.Blueprint.Chord do @true_by_default false @false_by_default true - @chart_type :radial defmacro chord(opts \\ []) do build_chord(opts) end @@ -34,8 +33,7 @@ defmodule Matplotex.Blueprint.Chord do show_legend: @false_by_default, region_title: nil, region_legend: nil, - region_content: nil, - border: nil + region_content: nil ] |> Keyword.merge(opts) ) diff --git a/lib/matplotex/figure/areal.ex b/lib/matplotex/figure/areal.ex index 268cb90..92e4407 100644 --- a/lib/matplotex/figure/areal.ex +++ b/lib/matplotex/figure/areal.ex @@ -30,7 +30,10 @@ defmodule Matplotex.Figure.Areal do alias Matplotex.Figure.Dataset alias Matplotex.Figure.Text + alias Matplotex.Figure.Areal.Region + alias Matplotex.Figure.RcParams @default_tick_minimum 0 + @zero_to_move 0 def add_label(%__MODULE__{label: nil} = axes, {key, label}, opts) when is_binary(label) do label = Map.new() @@ -211,11 +214,119 @@ defmodule Matplotex.Figure.Areal do def set_frame_size(%__MODULE__{} = axes, frame_size) do %__MODULE__{axes | size: frame_size} end + + def set_region_title( + %Figure{ + axes: + %{ + title: title, + region_x: %Region{width: region_x_width}, + region_y: %Region{height: region_y_height} = region_y, + region_title: region_title, + size: {_f_width, _f_height}, + border: {lx, _by, _, ty} + } = axes, + rc_params: %RcParams{title_font: title_font} + } = figure + ) do + space_for_title = Lead.height_required_for_text(title_font, title) + + {x_region_title, y_region_title} = + Algebra.transform_given_point(@zero_to_move, -space_for_title, lx, ty) + + %Figure{ + figure + | axes: %{ + axes + | region_title: %Region{ + region_title + | x: x_region_title, + y: y_region_title + space_for_title, + width: region_x_width, + height: space_for_title + }, + region_y: %Region{ + region_y + | height: region_y_height - space_for_title + } + } + } + end + + def set_region_title(figure), do: figure + + + def set_region_legend( + %Figure{ + axes: + %{ + show_legend: true, + region_x: %Region{width: region_x_width} = region_x, + region_title: %Region{height: region_title_height}, + region_legend: region_legend, + size: {f_width, _f_height}, + border: {_lx, by, rx, ty} + } = axes, + rc_params: %RcParams{legend_width: legend_width} + } = figure + ) do + region_legend_width = f_width * legend_width + region_x_width_after_legend = region_x_width - region_legend_width + + {x_region_legend, y_region_legend} = + Algebra.transform_given_point(-region_legend_width, -region_title_height, rx, ty, 0) + + %Figure{ + figure + | axes: %{ + axes + | region_x: %Region{ + region_x + | width: region_x_width_after_legend + }, + region_legend: %Region{ + region_legend + | x: x_region_legend, + y: y_region_legend, + width: region_legend_width, + height: y_region_legend - by + } + } + } + end + def set_region_legend(figure), do: figure + def set_region_content( + %Figure{ + axes: + %{ + region_x: %Region{x: x_region_x, width: region_x_width}, + region_y: %Region{y: y_region_y, height: region_y_height}, + region_content: region_content + } = axes + } = figure + ) do + %Figure{ + figure + | axes: %{ + axes + | region_content: %Region{ + region_content + | x: x_region_x, + y: y_region_y, + width: region_x_width, + height: region_y_height + } + } + } + end + def set_region_content(figure), do: figure end end + def transformation({_labelx, x}, {_labely, y}, xminmax, yminmax, width, height, transition) do transformation(x, y, xminmax, yminmax, width, height, transition) end + def transformation({_label, x}, y, xminmax, yminmax, width, height, transition) do transformation(x, y, xminmax, yminmax, width, height, transition) end @@ -224,7 +335,6 @@ defmodule Matplotex.Figure.Areal do transformation(x, y, xminmax, yminmax, width, height, transition) end - def transformation( x, y, @@ -246,11 +356,11 @@ defmodule Matplotex.Figure.Areal do x |> Enum.zip(y) |> Enum.map(fn {x, y} -> - x |> transformation(y, xlim, ylim, width, height, transition) |> Algebra.flip_y_coordinate() end) + %Dataset{dataset | transformed: transformed} end end diff --git a/lib/matplotex/figure/areal/bar_chart.ex b/lib/matplotex/figure/areal/bar_chart.ex index c9ac286..414f22d 100644 --- a/lib/matplotex/figure/areal/bar_chart.ex +++ b/lib/matplotex/figure/areal/bar_chart.ex @@ -35,7 +35,12 @@ defmodule Matplotex.Figure.Areal.BarChart do dataset = Dataset.cast(%Dataset{x: x, y: values, pos: pos, width: width}, opts) datasets = data ++ [dataset] xydata = flatten_for_data(datasets) - %Figure{figure | rc_params: %RcParams{white_space: width, y_padding: 0}, axes: %{axes | data: xydata, dataset: datasets}} + + %Figure{ + figure + | rc_params: %RcParams{white_space: width, y_padding: 0}, + axes: %{axes | data: xydata, dataset: datasets} + } end @impl Areal @@ -146,7 +151,7 @@ defmodule Matplotex.Figure.Areal.BarChart do defp hypox(y) do nof_x = length(y) - @xmin_value|>Nx.linspace(nof_x, n: nof_x)|>Nx.to_list() + @xmin_value |> Nx.linspace(nof_x, n: nof_x) |> Nx.to_list() end defp bar_position(x, pos_factor) when pos_factor < 0 do diff --git a/lib/matplotex/figure/areal/region.ex b/lib/matplotex/figure/areal/region.ex index e4ad9f6..83a1836 100644 --- a/lib/matplotex/figure/areal/region.ex +++ b/lib/matplotex/figure/areal/region.ex @@ -1,7 +1,13 @@ defmodule Matplotex.Figure.Areal.Region do alias Matplotex.Figure.Areal.XyRegion.Coords @zero_by_default 0 - defstruct x: @zero_by_default, y: @zero_by_default, width: @zero_by_default, height: @zero_by_default, name: nil, theta: @zero_by_default, coords: nil + defstruct x: @zero_by_default, + y: @zero_by_default, + width: @zero_by_default, + height: @zero_by_default, + name: nil, + theta: @zero_by_default, + coords: nil def get_label_coords(%__MODULE__{x: x, y: y, coords: %Coords{label: {label_x, label_y}}}) do {x + label_x, y + label_y} diff --git a/lib/matplotex/figure/cast.ex b/lib/matplotex/figure/cast.ex index 73b8dcb..6ec8e1f 100644 --- a/lib/matplotex/figure/cast.ex +++ b/lib/matplotex/figure/cast.ex @@ -430,7 +430,6 @@ defmodule Matplotex.Figure.Cast do } = figure ) when is_list(x_ticks) do - x_ticks = confine_ticks(x_ticks, xlim) x_data = confine_data(x_data, xlim) dataset = confine_data(dataset, xlim, :x) @@ -448,12 +447,12 @@ defmodule Matplotex.Figure.Cast do Enum.map(ticks_width_position, fn {tick_position, label} -> {_, y_x_tick_line} = @zero_to_move - |>Algebra.transform_given_point(height_region_x, x_region_x, y_region_x) + |> Algebra.transform_given_point(height_region_x, x_region_x, y_region_x) |> Algebra.flip_y_coordinate() {x_x_tick, y_x_tick} = tick_position - |>Algebra.transform_given_point( + |> Algebra.transform_given_point( @zero_to_move, x_region_x_with_padding, y_x_tick @@ -480,6 +479,7 @@ defmodule Matplotex.Figure.Cast do {%Tick{type: @xtick_type, tick_line: line, label: label}, {x_x_tick, y_x_tick_line}} end) |> Enum.unzip() + elements = elements ++ x_tick_elements %Figure{ @@ -498,6 +498,7 @@ defmodule Matplotex.Figure.Cast do defp format_tick_label({label, _index}), do: label defp format_tick_label(label) when is_float(label), do: Float.round(label, 2) defp format_tick_label(label), do: label + defp content_linespace(number_of_ticks_required, axis_size) do @lowest_tick |> Nx.linspace(axis_size, n: number_of_ticks_required) |> Nx.to_list() end @@ -630,7 +631,7 @@ defmodule Matplotex.Figure.Cast do {x_y_tick, y_y_tick} = @zero_to_move - |>Algebra.transform_given_point( + |> Algebra.transform_given_point( tick_position, x_y_tick, y_region_y_with_padding diff --git a/lib/matplotex/figure/lead.ex b/lib/matplotex/figure/lead.ex index 3c8c89d..be0245e 100644 --- a/lib/matplotex/figure/lead.ex +++ b/lib/matplotex/figure/lead.ex @@ -13,26 +13,30 @@ defmodule Matplotex.Figure.Lead do @spec set_regions_areal(Matplotex.Figure.t()) :: Matplotex.Figure.t() - def set_regions_areal(%Figure{figsize: {width, height}} = figure) when width > 0 and height > 0 do + def set_regions_areal(%Figure{figsize: {width, height}, axes: %module{}} = figure) + when width > 0 and height > 0 do figure |> set_frame_size() |> ensure_ticks_are_valid() |> set_region_xy() - |> set_region_title() - |> set_region_legend() - |> set_region_content() + |> module.set_region_title() + |> module.set_region_legend() + |> module.set_region_content() end def set_regions_areal(figure), do: figure - def set_regions_radial(%Figure{figsize: {width, height}} = figure) when width > 0 and height >0 do + + def set_regions_radial(%Figure{figsize: {width, height}, axes: %module{}} = figure) + when width > 0 and height > 0 do figure |> set_frame_size() - |> set_region_title() - |> set_region_legend() - |> set_region_content() + |> module.set_region_title() + |> module.set_region_legend() + |> module.set_region_content() end def set_regions_radial(figure), do: figure + def set_border(%Figure{margin: margin, axes: axes, figsize: {fig_width, fig_height}} = figure) do margin = margin / 2 lx = fig_width * margin @@ -64,6 +68,7 @@ defmodule Matplotex.Figure.Lead do ) do {x_ticks, x_lim} = maybe_generate_ticks(x_ticks, x_lim, x_data, width) {y_ticks, y_lim} = maybe_generate_ticks(y_ticks, y_lim, y_data, height) + %Figure{ figure | axes: %{ @@ -139,10 +144,17 @@ defmodule Matplotex.Figure.Lead do {x_region_y, y_region_y} = Algebra.transform_given_point(@zero_to_move, space_required_for_region_x, lx, by) - x_label_coords = Algebra.transform_given_point(@zero_to_move, @zero_to_move, x_region_x, y_region_x) - x_tick_coords = Algebra.transform_given_point(@zero_to_move, space_for_x_label, x_region_x, y_region_x) - y_label_coords = Algebra.transform_given_point(@zero_to_move, @zero_to_move, x_region_y, y_region_y) - y_tick_coords = Algebra.transform_given_point(space_for_ylabel, @zero_to_move, x_region_y, y_region_y) + x_label_coords = + Algebra.transform_given_point(@zero_to_move, @zero_to_move, x_region_x, y_region_x) + + x_tick_coords = + Algebra.transform_given_point(@zero_to_move, space_for_x_label, x_region_x, y_region_x) + + y_label_coords = + Algebra.transform_given_point(@zero_to_move, @zero_to_move, x_region_y, y_region_y) + + y_tick_coords = + Algebra.transform_given_point(space_for_ylabel, @zero_to_move, x_region_y, y_region_y) %Figure{ figure @@ -168,162 +180,67 @@ defmodule Matplotex.Figure.Lead do } end - defp set_region_xy(figure), do: figure - - defp set_region_title( - %Figure{ - axes: - %{ - title: title, - region_x: %Region{width: region_x_width}, - region_y: %Region{height: region_y_height} = region_y, - region_title: region_title, - size: {_f_width, _f_height}, - border: {lx, _by, _, ty} - } = axes, - rc_params: %RcParams{title_font: title_font} - } = figure - ) do - space_for_title = height_required_for_text(title_font, title) - - {x_region_title, y_region_title} = - Algebra.transform_given_point(@zero_to_move, -space_for_title, lx, ty) - - %Figure{ - figure - | axes: %{ - axes - | region_title: %Region{ - region_title - | x: x_region_title, - y: y_region_title + space_for_title, - width: region_x_width, - height: space_for_title - }, - region_y: %Region{ - region_y - | height: region_y_height - space_for_title - } - } - } - end - - defp set_region_title(%Figure{axes: %{title: title, center: _center, border: {lx, _by, _rx, ty}, size: {width, height}} = axes, rc_params: %RcParams{title_font: title_font}} = figure) do - space_for_title = height_required_for_text(title_font, title) - - {x_region_title, y_region_title} = Algebra.transform_given_point(@zero_to_move, -space_for_title, lx, ty ) - - %Figure{figure | axes: %{axes | region_title: %Region{x: x_region_title, y: y_region_title, width: width, height: space_for_title}}} - end - - defp set_region_legend( - %Figure{ - axes: - %{ - show_legend: true, - region_x: %Region{width: region_x_width} = region_x, - region_title: %Region{height: region_title_height}, - region_legend: region_legend, - size: {f_width, _f_height}, - border: {_lx, by, rx, ty} - } = axes, - rc_params: %RcParams{legend_width: legend_width} - } = figure - ) do - region_legend_width = f_width * legend_width - region_x_width_after_legend = region_x_width - region_legend_width - - {x_region_legend, y_region_legend} = - Algebra.transform_given_point(-region_legend_width, -region_title_height, rx, ty, 0) - - %Figure{ - figure - | axes: %{ - axes - | region_x: %Region{ - region_x - | width: region_x_width_after_legend - }, - region_legend: %Region{ - region_legend - | x: x_region_legend, - y: y_region_legend, - width: region_legend_width, - height: y_region_legend - by - } - } - } - end - - defp set_region_legend(figure), do: figure - - defp set_region_content( - %Figure{ - axes: - %{ - region_x: %Region{x: x_region_x, width: region_x_width}, - region_y: %Region{y: y_region_y, height: region_y_height}, - region_content: region_content - } = axes - } = figure - ) do - %Figure{ - figure - | axes: %{ - axes - | region_content: %Region{ - region_content - | x: x_region_x, - y: y_region_y, - width: region_x_width, - height: region_y_height - } - } - } - end - - defp set_region_content(figure), do: figure - - def focus_to_origin( - %Figure{ - figsize: {width, height}, - margin: margin, - rc_params: %RcParams{title_font_size: title_font_size}, - axes: %{title: title} = axes - } = figure - ) do - leftx = width * margin - bottomy = height * margin - rightx = width - width * margin - topy = height - height * margin - title_coords = {leftx, topy} - title_offset = label_offset(title, title_font_size) - topy = topy - title_offset - inner_size = {width, height} = {width - 2 * leftx, height - 2 * bottomy - title_offset} - - {{centerx, centery}, radius} = - center_and_radius(width, height, {leftx, rightx, bottomy, topy}) - - coords = %Coords{ - title: title_coords, - bottom_left: {leftx, bottomy}, - top_left: {leftx, topy}, - bottom_right: {rightx, bottomy}, - top_right: {rightx, topy} - } + def focus_to_origin(%Figure{rc_params: %RcParams{padding: padding}, axes: %{region_content: %Region{x: x_region_content, y: y_region_content, width: width_region_content, height: height_region_content}}=axes}=figure) do + width_padding_value = width_region_content * padding + height_padding_value = height_region_content * padding + radius = plotable_radius(width_region_content, height_region_content, padding) + {center_x, center_y} = x_region_content|>Algebra.transform_given_point(y_region_content, width_padding_value, height_padding_value)|>Algebra.transform_given_point({radius, radius}) %Figure{ figure | axes: %{ axes | radius: radius, - center: %TwoD{x: centerx, y: centery}, - coords: coords, - size: inner_size, - legend_pos: {2 * leftx + 2 * radius, topy} + center: %TwoD{x: center_x, y: center_y} } } end + defp plotable_radius(width, height, padding) when height < width do + (height - height * padding) / 2 + end + defp plotable_radius(width, height, padding) when width < height do + (width - width * padding) / 2 + end + # def focus_to_origin( + # %Figure{ + # figsize: {width, height}, + # margin: margin, + # rc_params: %RcParams{title_font_size: title_font_size}, + # axes: %{title: title} = axes + # } = figure + # ) do + # leftx = width * margin + # bottomy = height * margin + # rightx = width - width * margin + # topy = height - height * margin + # title_coords = {leftx, topy} + # title_offset = label_offset(title, title_font_size) + # topy = topy - title_offset + # inner_size = {width, height} = {width - 2 * leftx, height - 2 * bottomy - title_offset} + + # {{centerx, centery}, radius} = + # center_and_radius(width, height, {leftx, rightx, bottomy, topy}) + + # coords = %Coords{ + # title: title_coords, + # bottom_left: {leftx, bottomy}, + # top_left: {leftx, topy}, + # bottom_right: {rightx, bottomy}, + # top_right: {rightx, topy} + # } + + # %Figure{ + # figure + # | axes: %{ + # axes + # | radius: radius, + # center: %TwoD{x: centerx, y: centery}, + # coords: coords, + # size: inner_size, + # legend_pos: {2 * leftx + 2 * radius, topy} + # } + # } + # end defp center_and_radius(width, height, {leftx, _rightx, bottomy, _topy}) when height < width do radius = height / 2 @@ -341,8 +258,6 @@ defmodule Matplotex.Figure.Lead do {{centerx, centery}, radius} end - - defp label_offset(nil, _font_size), do: 0 defp label_offset("", _font_size), do: 0 @@ -353,6 +268,7 @@ defmodule Matplotex.Figure.Lead do defp label_offset(_label, font_size) do font_size * @pt_to_inch + @padding end + defp tick_length(tick) when is_integer(tick) do tick |> Integer.to_string() |> String.length() end @@ -362,26 +278,29 @@ defmodule Matplotex.Figure.Lead do end defp tick_length(tick) when is_float(tick) do - tick|>Float.round(2) |> Float.to_string() |> String.length() + tick |> Float.round(2) |> Float.to_string() |> String.length() end defp tick_length({label, _v}) when is_binary(label) do String.length(label) end - defp height_required_for_text( - %Font{ - font_size: font_size, - pt_to_inch_ratio: pt_to_inch_ratio, - flate: flate, - rotation: 0 - }, - _text - ) do + @doc """ + Calculates the height required for a given text with given font details + """ + def height_required_for_text( + %Font{ + font_size: font_size, + pt_to_inch_ratio: pt_to_inch_ratio, + flate: flate, + rotation: 0 + }, + _text + ) do to_number(font_size) * pt_to_inch_ratio + flate end - defp height_required_for_text( + def height_required_for_text( %Font{ font_size: font_size, pt_to_inch_ratio: pt_to_inch_ratio, @@ -397,27 +316,31 @@ defmodule Matplotex.Figure.Lead do text_height + height_for_rotation + flate end - defp length_required_for_text( - %Font{ - font_size: font_size, - pt_to_inch_ratio: pt_to_inch_ratio, - flate: flate, - rotation: 0 - }, - text - ), - do: tick_length(text) * to_number(font_size) * (pt_to_inch_ratio/2) + flate - - defp length_required_for_text( - %Font{ - font_size: font_size, - pt_to_inch_ratio: pt_to_inch_ratio, - flate: flate, - rotation: rotation - }, - text - ) do - text_length = tick_length(text) * to_number(font_size) * (pt_to_inch_ratio/2) + @doc """ + Length required for a text string with given font details + """ + + def length_required_for_text( + %Font{ + font_size: font_size, + pt_to_inch_ratio: pt_to_inch_ratio, + flate: flate, + rotation: 0 + }, + text + ), + do: tick_length(text) * to_number(font_size) * (pt_to_inch_ratio / 2) + flate + + def length_required_for_text( + %Font{ + font_size: font_size, + pt_to_inch_ratio: pt_to_inch_ratio, + flate: flate, + rotation: rotation + }, + text + ) do + text_length = tick_length(text) * to_number(font_size) * (pt_to_inch_ratio / 2) rotation = deg_to_rad(rotation) leng_for_rotation = :math.cos(rotation) * text_length leng_for_rotation + flate diff --git a/lib/matplotex/figure/radial.ex b/lib/matplotex/figure/radial.ex index c039ee4..59b4c12 100644 --- a/lib/matplotex/figure/radial.ex +++ b/lib/matplotex/figure/radial.ex @@ -16,6 +16,12 @@ defmodule Matplotex.Figure.Radial do alias Matplotex.Figure.Text alias Matplotex.Figure.Lead alias Matplotex.Figure.Cast + alias Matplotex.Figure.RcParams + alias Matplotex.Figure + alias Matplotex.Figure.Areal.Region + alias Matplotex.Utils.Algebra + + @zero_to_move 0 def add_title(axes, title, opts) when is_binary(title) do %{axes | title: title, show_title: true} @@ -23,11 +29,105 @@ defmodule Matplotex.Figure.Radial do def materialized(figure) do figure - |> Lead.focus_to_origin() - |> Lead.set_border() + |> Lead.set_regions_radial() |> Cast.cast_border() |> Cast.cast_title() end + + def set_region_title( + %Figure{ + axes: + %{ + title: title, + center: _center, + border: {lx, _by, _rx, ty}, + size: {width, _height} + } = + axes, + rc_params: %RcParams{title_font: title_font} + } = figure + ) do + space_for_title = Lead.height_required_for_text(title_font, title) + + {x_region_title, y_region_title} = + Algebra.transform_given_point(@zero_to_move, -space_for_title, lx, ty) + + %Figure{ + figure + | axes: %{ + axes + | region_title: %Region{ + x: x_region_title, + y: y_region_title, + width: width, + height: space_for_title + } + } + } + end + def set_region_title(figure), do: figure + def set_region_legend( + %Figure{ + figsize: {fwidth, _fheight}, + rc_params: %RcParams{legend_width: legend_width}, + axes: + %{ + border: {_lx, by, rx, _ty}, + show_legend: true, + region_title: %Region{y: y_region_title} + } = axes + } = figure + ) do + width_region_legend = fwidth * legend_width + height_region_legend = abs(by - y_region_title) + + {x_region_legend, y_region_legend} = + Algebra.transform_given_point(rx - width_region_legend, 0, 0, by) + + %Figure{ + figure + | axes: %{ + axes + | region_legend: %Region{ + x: x_region_legend, + y: y_region_legend, + width: width_region_legend, + height: height_region_legend + } + } + } + end + def set_region_legend(figure), do: figure + + def set_region_content( + %Figure{ + axes: + %{ + border: {lx, by, _rx, _ty}, + region_title: %Region{height: height_region_title}, + region_legend: %Region{width: width_region_legend}, + size: {width, height} + } = axes + } = figure + ) do + width_region_content = width - width_region_legend + height_region_content = height - height_region_title + + %Figure{ + figure + | axes: %{ + axes + | region_content: %Region{ + x: lx, + y: by, + width: width_region_content, + height: height_region_content + } + } + } + end + + def set_region_content(figure), do: figure end end end diff --git a/lib/matplotex/figure/radial/pie.ex b/lib/matplotex/figure/radial/pie.ex index 618509d..e36b057 100644 --- a/lib/matplotex/figure/radial/pie.ex +++ b/lib/matplotex/figure/radial/pie.ex @@ -1,4 +1,5 @@ defmodule Matplotex.Figure.Radial.Pie do + alias Matplotex.Figure.Areal.Region alias Matplotex.Figure.Radial alias Matplotex.Element.RadLegend alias Matplotex.Figure.Radial.LegendAcc @@ -12,7 +13,15 @@ defmodule Matplotex.Figure.Radial.Pie do use Radial @full_circle 2 * :math.pi() - chord(center: %TwoD{}, lead: %TwoD{}, coords: %Coords{}) + chord( + center: %TwoD{}, + lead: %TwoD{}, + coords: %Coords{}, + region_title: %Region{}, + region_legend: %Region{}, + region_content: %Region{} + ) + @impl Radial def create(%Figure{axes: axes} = figure, sizes, opts) do dataset = Dataset.cast(%Dataset{sizes: sizes}, opts) diff --git a/lib/matplotex/figure/rc_params.ex b/lib/matplotex/figure/rc_params.ex index 1f963c2..cf22aea 100644 --- a/lib/matplotex/figure/rc_params.ex +++ b/lib/matplotex/figure/rc_params.ex @@ -44,6 +44,7 @@ defmodule Matplotex.Figure.RcParams do tick_line_length: @tick_line_length, x_padding: @chart_padding, y_padding: @chart_padding, + padding: @chart_padding, white_space: 0, label_padding: @label_padding, legend_width: @default_legend_width_percentage, diff --git a/lib/matplotex/helpers.ex b/lib/matplotex/helpers.ex index cbe8d5a..7f975d7 100644 --- a/lib/matplotex/helpers.ex +++ b/lib/matplotex/helpers.ex @@ -212,7 +212,7 @@ defmodule Matplotex.Helpers do |> Matplotex.plot(x, y2, color: "red", linestyle: "--", marker: "^", label: "Dataset 2") |> Matplotex.plot(x, y3, color: "green", linestyle: "-.", marker: "s", label: "Dataset 3") |> Matplotex.set_title("Title") - |> Matplotex.set_xticks([1,2,3,4,5]) + |> Matplotex.set_xticks([1, 2, 3, 4, 5]) |> Matplotex.set_xlabel("X-Axis") |> Matplotex.set_ylabel("Y-Axis") |> Matplotex.show() diff --git a/lib/matplotex/utils/algebra.ex b/lib/matplotex/utils/algebra.ex index 1fde07f..5fd13d5 100644 --- a/lib/matplotex/utils/algebra.ex +++ b/lib/matplotex/utils/algebra.ex @@ -51,6 +51,7 @@ defmodule Matplotex.Utils.Algebra do def transform_given_point(x, y, sx, sy, tx, ty, theta \\ 0) do point_matrix = Nx.tensor([x, y, 1], type: {:f, @tensor_data_type_bits}) + Nx.tensor( [ [sx * :math.cos(theta), sy * -:math.sin(theta), tx], @@ -64,9 +65,12 @@ defmodule Matplotex.Utils.Algebra do |> List.to_tuple() |> then(fn {x, y, _} -> {x, y} end) end - + def transform_given_point({x, y}, {ox, oy}, theta \\ 0) do + transform_given_point(x, y, ox, oy, theta) + end def transform_given_point(x, y, ox, oy, theta \\ 0) do point_matrix = Nx.tensor([x, y, 1], type: {:f, @tensor_data_type_bits}) + Nx.tensor( [ [:math.cos(theta), -:math.sin(theta), ox], @@ -81,6 +85,8 @@ defmodule Matplotex.Utils.Algebra do |> then(fn {x, y, _} -> {x, y} end) end + + def flip_y_coordinate({x, y}) do {x, -y} end diff --git a/test/matplotex/figure/cast_test.exs b/test/matplotex/figure/cast_test.exs index ef89f9d..fd58245 100644 --- a/test/matplotex/figure/cast_test.exs +++ b/test/matplotex/figure/cast_test.exs @@ -9,7 +9,6 @@ defmodule Matplotex.Figure.CastTest do {:ok, %{figure: figure}} end - describe "cast_spines_by_region/1" do test "add elements for borders in axes", %{figure: figure} do figure = Lead.set_regions_areal(figure) diff --git a/test/matplotex/figure/lead_test.exs b/test/matplotex/figure/lead_test.exs index b9bf6bb..7a7a4f3 100644 --- a/test/matplotex/figure/lead_test.exs +++ b/test/matplotex/figure/lead_test.exs @@ -5,10 +5,9 @@ defmodule Matplotex.Figure.LeadTest do use Matplotex.PlotCase alias Matplotex.Figure.Lead - setup(context) do figure = - if context.radial do + if Map.get(context, :radial, false) do categories = ["2008", "2009", "2010", "2011"] values = [18.48923375, 17.1923791, 17.48479218, 17.02021634] @@ -18,7 +17,6 @@ defmodule Matplotex.Figure.LeadTest do Matplotex.FrameHelpers.sample_figure() end - frame_width = 8 frame_height = 6 size = {frame_width, frame_height} @@ -168,16 +166,89 @@ defmodule Matplotex.Figure.LeadTest do assert width == two_side_margin + ry_width + rcwidth + rlwidth end - describe "set_regions_areal" do + describe "set_regions_radial" do + @tag radial: true + test "updates with all borders", %{figure: figure} do + %Figure{axes: %{border: {lx, by, rx, ty}}} = Lead.set_regions_radial(figure) + assert lx != 0 && by != 0 && rx != 0 && ty != 0 + end + @tag radial: true - test "updates with all borders" do - %Figure{axes: %{border: {lx, by, rx, ty}}} = Lead.set_regions_radial(figure) - assert lx > 0 && by > 0 && rx > 0 && ty > 0 + test "updates region titles", %{figure: figure} do + %Figure{ + margin: margin, + figsize: {fwidth, fheight}, + axes: %{ + region_title: %Region{ + x: x_region_title, + y: y_region_title, + width: width_region_title, + height: height_region_title + } + } + } = Lead.set_regions_radial(figure) + + width_margin_value = margin * fwidth + height_margin_value = margin * fheight + + assert x_region_title == width_margin_value + assert y_region_title == -(height_margin_value + height_region_title) + assert width_region_title == fwidth - 2 * width_margin_value end + @tag radial: true - test "updates region titles" do - %Figure{axes: %{region_title: %Region{}}} = Lead.set_regions_radial(figure) + test "updates region legend", %{figure: figure} do + %Figure{ + margin: margin, + figsize: {fwidth, fheight}, + axes: %{ + region_legend: %Region{ + x: x_region_legend, + y: y_region_legend, + width: width_region_legend, + height: height_region_legend + }, + region_title: %Region{height: height_region_title} + } + } = Lead.set_regions_radial(figure) + + width_margin_value = margin * fwidth + height_margin_value = margin * fheight + assert x_region_legend == fwidth - width_margin_value - width_region_legend + + assert y_region_legend == + -(height_margin_value + height_region_title + height_region_legend) end + @tag radial: true + test "updates region content", %{figure: figure} do + %Figure{ + figsize: {fwidth, fheight}, + axes: %{ + region_content: %Region{ + x: x_region_content, + y: y_region_content, + width: width_region_content, + height: height_region_content + }, + border: {lx, by, _rx, ty}, + region_legend: %Region{width: width_region_legend}, + region_title: %Region{height: height_region_title} + } + } = Lead.set_regions_radial(figure) + + assert x_region_content == lx + assert y_region_content == by + assert 2 * lx + width_region_content + width_region_legend == fwidth + assert 2 * abs(ty) + height_region_content + height_region_title == fheight + end + end + + describe "focus_to_origin/1" do + @tab radial: true + test "sets origin to center of the figure", %{figure: figure} do + assert %Figure{axes: %{center: {cx, cy}}} = Lead.focus_to_origin(figure) + assert cx != 0 && cy != 0 + end end end diff --git a/test/support/plot_case.ex b/test/support/plot_case.ex index e2dc2be..25bdca5 100644 --- a/test/support/plot_case.ex +++ b/test/support/plot_case.ex @@ -1,5 +1,4 @@ defmodule Matplotex.PlotCase do - alias Matplotex.Figure.Lead use ExUnit.CaseTemplate using do From 005d8bd3c41be383f3d18983edf4d1529b6e7c55 Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Tue, 17 Dec 2024 17:49:32 +0530 Subject: [PATCH 3/4] regional pie --- lib/matplotex/element/rad_legend.ex | 14 ++++----- lib/matplotex/figure.ex | 6 ++++ lib/matplotex/figure/cast.ex | 11 ++++--- lib/matplotex/figure/lead.ex | 46 +++++++++++++++-------------- lib/matplotex/figure/radial.ex | 12 +++++--- lib/matplotex/figure/radial/pie.ex | 31 ++++++++++++------- lib/matplotex/figure/rc_params.ex | 4 +-- lib/matplotex/helpers.ex | 5 ++-- lib/matplotex/utils/algebra.ex | 5 ++++ test/matplotex/figure/lead_test.exs | 7 ++--- 10 files changed, 84 insertions(+), 57 deletions(-) diff --git a/lib/matplotex/element/rad_legend.ex b/lib/matplotex/element/rad_legend.ex index 8f6034c..147b694 100644 --- a/lib/matplotex/element/rad_legend.ex +++ b/lib/matplotex/element/rad_legend.ex @@ -41,19 +41,19 @@ defmodule Matplotex.Element.RadLegend do x: x, y: y, width: width, - height: height, - label_margin: label_margin - } = legend + height: height + } = legend, legend_font ) do + %{ legend | label: %Label{ - x: x + width + label_margin, - y: y - height / 4, + x: x + width , + y: y + height / 2, text: text, - type: @label_type, - text_anchor: "start" + type: @label_type } + |> Label.cast_label(legend_font) } end end diff --git a/lib/matplotex/figure.ex b/lib/matplotex/figure.ex index ff375f2..ad3d563 100644 --- a/lib/matplotex/figure.ex +++ b/lib/matplotex/figure.ex @@ -31,6 +31,10 @@ defmodule Matplotex.Figure do def new(opts) do struct(__MODULE__, opts) end + # TODO: put error message in error + # def put_error(figure, opts) do + + # end def add_label(%__MODULE__{axes: %module{} = axes} = figure, label, opts), do: %{figure | axes: module.add_label(axes, label, opts)} @@ -110,4 +114,6 @@ defmodule Matplotex.Figure do defp update_rc_params(_, _) do raise Matplotex.InputError, keys: [:rc_params], message: "Invalid Input" end + + end diff --git a/lib/matplotex/figure/cast.ex b/lib/matplotex/figure/cast.ex index 6ec8e1f..2632cb9 100644 --- a/lib/matplotex/figure/cast.ex +++ b/lib/matplotex/figure/cast.ex @@ -138,6 +138,8 @@ defmodule Matplotex.Figure.Cast do rc_params: %RcParams{line_width: line_width} } = figure ) do + {lx, by} = Algebra.flip_y_coordinate({lx, by}) + {rx, ty} = Algebra.flip_y_coordinate({rx, ty}) left = %Line{x1: lx, y1: by, x2: lx, y2: ty, type: "border.left", stroke_width: line_width} right = %Line{x1: rx, y1: by, x2: rx, y2: ty, type: "border.right", stroke_width: line_width} top = %Line{x1: lx, x2: rx, y1: ty, y2: ty, type: "border.top", stroke_width: line_width} @@ -158,14 +160,14 @@ defmodule Matplotex.Figure.Cast do %Figure{ axes: %{ - coords: %Coords{title: title_coord} = coords, + region_title: region_title, title: title, element: elements } = axes, rc_params: %RcParams{title_font: title_font} } = figure ) do - {ttx, tty} = calculate_center(coords, title_coord, :x) + {ttx, tty} = calculate_center(region_title, :x) title = %Label{ @@ -189,14 +191,15 @@ defmodule Matplotex.Figure.Cast do %Figure{ axes: %{ - region_title: region, + region_title: region_title, title: title, element: elements } = axes, rc_params: %RcParams{title_font: title_font, label_padding: title_padding} } = figure ) do - {title_x, title_y} = region |> calculate_center(:x) |> Algebra.flip_y_coordinate() + + {title_x, title_y} = region_title |> calculate_center(:x) |> Algebra.flip_y_coordinate() title = %Label{ diff --git a/lib/matplotex/figure/lead.ex b/lib/matplotex/figure/lead.ex index be0245e..8c9b37c 100644 --- a/lib/matplotex/figure/lead.ex +++ b/lib/matplotex/figure/lead.ex @@ -33,6 +33,7 @@ defmodule Matplotex.Figure.Lead do |> module.set_region_title() |> module.set_region_legend() |> module.set_region_content() + |> focus_to_origin() end def set_regions_radial(figure), do: figure @@ -195,11 +196,12 @@ defmodule Matplotex.Figure.Lead do } } end + def focus_to_origin(figure), do: figure defp plotable_radius(width, height, padding) when height < width do - (height - height * padding) / 2 + (height - height * padding * 2) / 2 end defp plotable_radius(width, height, padding) when width < height do - (width - width * padding) / 2 + (width - width * padding * 2) / 2 end # def focus_to_origin( # %Figure{ @@ -242,32 +244,32 @@ defmodule Matplotex.Figure.Lead do # } # end - defp center_and_radius(width, height, {leftx, _rightx, bottomy, _topy}) when height < width do - radius = height / 2 + # defp center_and_radius(width, height, {leftx, _rightx, bottomy, _topy}) when height < width do + # radius = height / 2 - centerx = leftx + radius - centery = bottomy + radius - {{centerx, centery}, radius} - end + # centerx = leftx + radius + # centery = bottomy + radius + # {{centerx, centery}, radius} + # end - defp center_and_radius(width, _height, {leftx, _rightx, _bottomy, topy}) do - radius = width / 2 + # defp center_and_radius(width, _height, {leftx, _rightx, _bottomy, topy}) do + # radius = width / 2 - centerx = leftx + radius - centery = topy - radius - {{centerx, centery}, radius} - end + # centerx = leftx + radius + # centery = topy - radius + # {{centerx, centery}, radius} + # end - defp label_offset(nil, _font_size), do: 0 - defp label_offset("", _font_size), do: 0 + # defp label_offset(nil, _font_size), do: 0 + # defp label_offset("", _font_size), do: 0 - defp label_offset(ticks, font_size) when is_list(ticks) do - font_size * @pt_to_inch + @padding - end + # defp label_offset(ticks, font_size) when is_list(ticks) do + # font_size * @pt_to_inch + @padding + # end - defp label_offset(_label, font_size) do - font_size * @pt_to_inch + @padding - end + # defp label_offset(_label, font_size) do + # font_size * @pt_to_inch + @padding + # end defp tick_length(tick) when is_integer(tick) do tick |> Integer.to_string() |> String.length() diff --git a/lib/matplotex/figure/radial.ex b/lib/matplotex/figure/radial.ex index 59b4c12..b732ea3 100644 --- a/lib/matplotex/figure/radial.ex +++ b/lib/matplotex/figure/radial.ex @@ -1,4 +1,6 @@ defmodule Matplotex.Figure.Radial do + alias Matplotex.Utils.Algebra + @callback create(struct(), list(), keyword()) :: struct() @callback materialize(struct()) :: struct() @@ -31,7 +33,7 @@ defmodule Matplotex.Figure.Radial do figure |> Lead.set_regions_radial() |> Cast.cast_border() - |> Cast.cast_title() + |> Cast.cast_title_by_region() end def set_region_title( @@ -72,17 +74,18 @@ defmodule Matplotex.Figure.Radial do rc_params: %RcParams{legend_width: legend_width}, axes: %{ - border: {_lx, by, rx, _ty}, + border: {_lx, by, rx, ty}, show_legend: true, - region_title: %Region{y: y_region_title} + region_title: %Region{y: y_region_title, height: height_region_title} } = axes } = figure ) do + IO.inspect(legend_width) width_region_legend = fwidth * legend_width height_region_legend = abs(by - y_region_title) {x_region_legend, y_region_legend} = - Algebra.transform_given_point(rx - width_region_legend, 0, 0, by) + Algebra.transform_given_point(rx, abs(ty), -width_region_legend,height_region_title)|>Algebra.flip_y_coordinate() %Figure{ figure @@ -110,6 +113,7 @@ defmodule Matplotex.Figure.Radial do } = axes } = figure ) do + width_region_content = width - width_region_legend height_region_content = height - height_region_title diff --git a/lib/matplotex/figure/radial/pie.ex b/lib/matplotex/figure/radial/pie.ex index e36b057..e69a158 100644 --- a/lib/matplotex/figure/radial/pie.ex +++ b/lib/matplotex/figure/radial/pie.ex @@ -1,4 +1,7 @@ defmodule Matplotex.Figure.Radial.Pie do + + alias Matplotex.Figure.RcParams + alias Matplotex.Utils.Algebra alias Matplotex.Figure.Areal.Region alias Matplotex.Figure.Radial alias Matplotex.Element.RadLegend @@ -24,7 +27,11 @@ defmodule Matplotex.Figure.Radial.Pie do @impl Radial def create(%Figure{axes: axes} = figure, sizes, opts) do - dataset = Dataset.cast(%Dataset{sizes: sizes}, opts) + dataset = if sizes|>Enum.sum()|>abs() > 0 do + Dataset.cast(%Dataset{sizes: sizes}, opts) + else + raise Matplotex.InputError, "Invalid set of values for a pie chart, sum of sizes should be greater than 0" + end %Figure{figure | axes: %{axes | dataset: dataset}} end @@ -37,13 +44,14 @@ defmodule Matplotex.Figure.Radial.Pie do defp materialize_slices( %Figure{ - figsize: {_fwidth, fheight}, + figsize: {fwidth, fheight}, + rc_params: %RcParams{legend_font: legend_font}, axes: %__MODULE__{ size: {_width, height}, radius: radius, - center: %{y: cy} = center, - legend_pos: {legx, legy}, + center: center, + region_legend: region_legend, dataset: %Dataset{ sizes: sizes, labels: labels, @@ -53,11 +61,11 @@ defmodule Matplotex.Figure.Radial.Pie do element: elements } = axes } = figure - ) do + ) when fwidth > 0 and fheight > 0 do + %Region{x: legx, y: legy} = Algebra.flip_y_coordinate(region_legend) total_size = Enum.sum(sizes) legend_rect_side = height / length(sizes) / 2 - center = %{center | y: fheight - cy} - + center = Algebra.flip_y_coordinate(center) slices = sizes |> Enum.zip(labels) @@ -74,7 +82,7 @@ defmodule Matplotex.Figure.Radial.Pie do } }, fn raw, color, acc -> - roll_across(raw, color, acc, center, radius, total_size) + roll_across(raw, color, acc, center, radius, total_size, legend_font) end ) |> then(fn %Accumulator{slices: slices, legends: legends} -> @@ -108,7 +116,8 @@ defmodule Matplotex.Figure.Radial.Pie do }, %{x: cx, y: cy} = center, radius, - total_size + total_size, + legend_font ) do percentage = size / total_size angle_for_size = percentage * @full_circle + start_angle @@ -128,7 +137,7 @@ defmodule Matplotex.Figure.Radial.Pie do cy: cy } - y_legend = y_legend - legend_unit_height + {x_legend, y_legend} = Algebra.transform_given_point(0, legend_unit_height, x_legend, y_legend) legend = %RadLegend{ @@ -140,7 +149,7 @@ defmodule Matplotex.Figure.Radial.Pie do height: legend_unit_height, label: "#{label}-#{Float.ceil(percentage * 100, 2)}%" } - |> RadLegend.with_label() + |> RadLegend.with_label(legend_font) %Accumulator{ lead: {x2, y2}, diff --git a/lib/matplotex/figure/rc_params.ex b/lib/matplotex/figure/rc_params.ex index cf22aea..5308a80 100644 --- a/lib/matplotex/figure/rc_params.ex +++ b/lib/matplotex/figure/rc_params.ex @@ -23,8 +23,8 @@ defmodule Matplotex.Figure.RcParams do y_tick_font: %Font{text_anchor: "start"}, x_label_font: @font, y_label_font: @font, - title_font: %Font{font_size: @default_title_font_size}, - legend_font: @font, + title_font: %Font{font_size: @default_title_font_size, dominant_baseline: "auto"}, + legend_font: %Font{text_anchor: "start"}, figure_size: @default_figsize, figure_dpi: @default_dpi, line_width: @line_width, diff --git a/lib/matplotex/helpers.ex b/lib/matplotex/helpers.ex index 7f975d7..a9e2784 100644 --- a/lib/matplotex/helpers.ex +++ b/lib/matplotex/helpers.ex @@ -270,7 +270,8 @@ defmodule Matplotex.Helpers do sizes |> Matplotex.pie(colors: colors, labels: labels) |> Matplotex.set_title("Pie chart") - |> Matplotex.figure(%{figsize: {3.5, 2.5}, margin: 0.05}) + |> Matplotex.figure(%{figsize: {4, 3}, margin: 0.05}) + |> Matplotex.set_rc_params(%{line_width: 1, legend_width: 0.25}) |> Matplotex.show() |> copy() end @@ -305,7 +306,7 @@ defmodule Matplotex.Helpers do values |> Matplotex.pie(colors: colors, labels: categories) |> Matplotex.set_title("Asias Emission distribution(2008-2011)") - |> Matplotex.set_rc_params(%{line_width: 1}) + |> Matplotex.set_rc_params(%{line_width: 1, legend_width: 0.5}) |> Matplotex.figure(%{figsize: {10, 4}, margin: 0.15}) |> Matplotex.show() |> copy() diff --git a/lib/matplotex/utils/algebra.ex b/lib/matplotex/utils/algebra.ex index 5fd13d5..804b941 100644 --- a/lib/matplotex/utils/algebra.ex +++ b/lib/matplotex/utils/algebra.ex @@ -1,4 +1,5 @@ defmodule Matplotex.Utils.Algebra do + alias Matplotex.Figure.TwoD alias Nx @tensor_data_type_bits 64 @@ -90,4 +91,8 @@ defmodule Matplotex.Utils.Algebra do def flip_y_coordinate({x, y}) do {x, -y} end + + def flip_y_coordinate(%{y: y} = point) do + %{point | y: -y} + end end diff --git a/test/matplotex/figure/lead_test.exs b/test/matplotex/figure/lead_test.exs index 7a7a4f3..08e8478 100644 --- a/test/matplotex/figure/lead_test.exs +++ b/test/matplotex/figure/lead_test.exs @@ -242,12 +242,9 @@ defmodule Matplotex.Figure.LeadTest do assert 2 * lx + width_region_content + width_region_legend == fwidth assert 2 * abs(ty) + height_region_content + height_region_title == fheight end - end - - describe "focus_to_origin/1" do - @tab radial: true + @tag radial: true test "sets origin to center of the figure", %{figure: figure} do - assert %Figure{axes: %{center: {cx, cy}}} = Lead.focus_to_origin(figure) + assert %Figure{axes: %{center: %TwoD{x: cx, y: cy} }} = Lead.set_regions_radial(figure) assert cx != 0 && cy != 0 end end From 835c75e1ab49053bc912b27d6eaa26caa06f98ef Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Tue, 17 Dec 2024 17:57:48 +0530 Subject: [PATCH 4/4] test fix --- lib/matplotex/figure/lead.ex | 3 --- lib/matplotex/figure/radial.ex | 1 - lib/matplotex/utils/algebra.ex | 1 - test/matplotex/figure/lead_test.exs | 6 ++---- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/matplotex/figure/lead.ex b/lib/matplotex/figure/lead.ex index 8c9b37c..0528aff 100644 --- a/lib/matplotex/figure/lead.ex +++ b/lib/matplotex/figure/lead.ex @@ -4,11 +4,8 @@ defmodule Matplotex.Figure.Lead do alias Matplotex.Figure.Font alias Matplotex.Figure.Areal.Region alias Matplotex.Figure.TwoD - alias Matplotex.Figure.Coords alias Matplotex.Figure.RcParams alias Matplotex.Figure - @pt_to_inch 1 / 150 - @padding 10 / 96 @zero_to_move 0 @spec set_regions_areal(Matplotex.Figure.t()) :: Matplotex.Figure.t() diff --git a/lib/matplotex/figure/radial.ex b/lib/matplotex/figure/radial.ex index b732ea3..9cdc586 100644 --- a/lib/matplotex/figure/radial.ex +++ b/lib/matplotex/figure/radial.ex @@ -80,7 +80,6 @@ defmodule Matplotex.Figure.Radial do } = axes } = figure ) do - IO.inspect(legend_width) width_region_legend = fwidth * legend_width height_region_legend = abs(by - y_region_title) diff --git a/lib/matplotex/utils/algebra.ex b/lib/matplotex/utils/algebra.ex index 804b941..182fcbd 100644 --- a/lib/matplotex/utils/algebra.ex +++ b/lib/matplotex/utils/algebra.ex @@ -1,5 +1,4 @@ defmodule Matplotex.Utils.Algebra do - alias Matplotex.Figure.TwoD alias Nx @tensor_data_type_bits 64 diff --git a/test/matplotex/figure/lead_test.exs b/test/matplotex/figure/lead_test.exs index 08e8478..4f67f80 100644 --- a/test/matplotex/figure/lead_test.exs +++ b/test/matplotex/figure/lead_test.exs @@ -205,8 +205,7 @@ defmodule Matplotex.Figure.LeadTest do region_legend: %Region{ x: x_region_legend, y: y_region_legend, - width: width_region_legend, - height: height_region_legend + width: width_region_legend }, region_title: %Region{height: height_region_title} } @@ -216,8 +215,7 @@ defmodule Matplotex.Figure.LeadTest do height_margin_value = margin * fheight assert x_region_legend == fwidth - width_margin_value - width_region_legend - assert y_region_legend == - -(height_margin_value + height_region_title + height_region_legend) + assert abs(y_region_legend) == height_margin_value + height_region_title end @tag radial: true