From 16235f9a9df88ad5cb538215ac7d4b0819e8011a Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Tue, 28 Jan 2025 18:36:44 +0530 Subject: [PATCH 01/11] cmap --- lib/matplotex.ex | 5 +++ lib/matplotex/blueprint/frame.ex | 3 +- lib/matplotex/colorscheme/colormap.ex | 42 +++++++++++++++++++++ lib/matplotex/element/cmap.ex | 37 +++++++++++++++++++ lib/matplotex/figure/areal.ex | 44 ++++++++++++++++------ lib/matplotex/figure/cast.ex | 53 ++++++++++++++++++++++++++- lib/matplotex/figure/dataset.ex | 3 ++ lib/matplotex/figure/rc_params.ex | 4 +- test/matplotex/figure/cast_test.exs | 9 +++++ test/matplotex/figure/lead_test.exs | 10 +++++ 10 files changed, 195 insertions(+), 15 deletions(-) create mode 100644 lib/matplotex/colorscheme/colormap.ex create mode 100644 lib/matplotex/element/cmap.ex diff --git a/lib/matplotex.ex b/lib/matplotex.ex index 97a9aef..b6907f9 100644 --- a/lib/matplotex.ex +++ b/lib/matplotex.ex @@ -161,6 +161,7 @@ defmodule Matplotex do """ + alias Matplotex.Figure.Areal.PlotOptions alias Matplotex.Figure.Areal.Spline alias Matplotex.Figure.Areal.Histogram alias Matplotex.InputError @@ -745,6 +746,10 @@ defmodule Matplotex do Figure.show_legend(figure) end + def set_options(figure, opts) do + PlotOptions.set_options_in_figure(figure, opts) + end + @doc """ Function to update rc params, rc stands for runtime configuration ## Examples diff --git a/lib/matplotex/blueprint/frame.ex b/lib/matplotex/blueprint/frame.ex index e3a477f..2958f06 100644 --- a/lib/matplotex/blueprint/frame.ex +++ b/lib/matplotex/blueprint/frame.ex @@ -100,7 +100,8 @@ defmodule Matplotex.Blueprint.Frame do show_x_ticks: @show_by_default, show_y_ticks: @show_by_default, show_ticks: @show_by_default, - border: nil + border: nil, + cmap: nil ] |> Keyword.merge(opts) ) diff --git a/lib/matplotex/colorscheme/colormap.ex b/lib/matplotex/colorscheme/colormap.ex new file mode 100644 index 0000000..e682793 --- /dev/null +++ b/lib/matplotex/colorscheme/colormap.ex @@ -0,0 +1,42 @@ +defmodule Matplotex.Colorscheme.Colormap do + defstruct [:color, :offset, opacity: 1] + @dark_purple "#2A132F" + @purple "#441E4B" + @yellow "#fbde41" + @red "#eb3767" + @orange "#EEA103" + @black "#1e1b13" + @dark_blue "#245BC1" + def viridis do + [@dark_purple, @yellow] + end + + def plasma do + [@dark_purple, @red, @yellow] + end + + def inferno do + [@black, @red, @orange, @yellow] + end + + def magma do + [@black, @purple, @red, @yellow] + end + + def civids do + [@dark_blue, @yellow] + end + + def make_colormap(colors) do + size = length(colors) + + colors + |> Enum.with_index() + |> Enum.map(&colormap(&1, size)) + end + + defp colormap({index, color}, size) do + offset = index / size / 100 + %__MODULE__{color: color, offset: offset} + end +end diff --git a/lib/matplotex/element/cmap.ex b/lib/matplotex/element/cmap.ex new file mode 100644 index 0000000..29d2cd7 --- /dev/null +++ b/lib/matplotex/element/cmap.ex @@ -0,0 +1,37 @@ +defmodule Matplotex.Element.Cmap do + alias Matplotex.Element.Rect + alias Matplotex.Element + use Element + + defstruct [ + type: "figure.cmap", + id: nil, + cmap: [], + container: %Rect{} + ] + + @impl Element + def assemble(element) do + ~s( + + #{for stp <- element.cmap do + tag_stop(stp) + end} + + + #{Element.assemble(element.container)}) + end + + def tag_stop(%{offset: offset, color: color, opacity: opacity}) do + ~s() + end + + def color_gradient(element) do + "url(##{element.id})" + end + + def get_x(%{x: x}), do: to_pixel(x) + def get_y(%{y: y}), do: to_pixel(y) + def get_width(%{width: width}), do: to_pixel(width) + def get_height(%{height: height}), do: to_pixel(height) +end diff --git a/lib/matplotex/figure/areal.ex b/lib/matplotex/figure/areal.ex index eae79df..416c9d1 100644 --- a/lib/matplotex/figure/areal.ex +++ b/lib/matplotex/figure/areal.ex @@ -266,18 +266,40 @@ defmodule Matplotex.Figure.Areal do 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} + axes: %{ + show_legend: true + } } = figure ) do + configure_region_legend(figure) + end + + def set_region_legend( + %Figure{ + axes: %{ + cmap: cmap + } + } = figure + ) + when not is_nil(cmap) do + configure_region_legend(figure) + end + + def set_region_legend(figure), do: figure + + defp configure_region_legend( + %Figure{ + axes: + %{ + 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 @@ -303,8 +325,6 @@ defmodule Matplotex.Figure.Areal do } end - def set_region_legend(figure), do: figure - def set_region_content( %Figure{ axes: diff --git a/lib/matplotex/figure/cast.ex b/lib/matplotex/figure/cast.ex index cdc78c8..8f9ce1f 100644 --- a/lib/matplotex/figure/cast.ex +++ b/lib/matplotex/figure/cast.ex @@ -1,5 +1,8 @@ defmodule Matplotex.Figure.Cast do @moduledoc false + alias Matplotex.Element.Rect + alias Matplotex.Colorscheme.Colormap + alias Matplotex.Element.Cmap alias Matplotex.Figure.Lead alias Matplotex.Element.Legend alias Matplotex.Utils.Algebra @@ -489,8 +492,56 @@ defmodule Matplotex.Figure.Cast do %Figure{figure | axes: %{axes | element: elements ++ legend_elements}} end - def cast_legends(figure), do: figure + def cast_legends( + %Figure{ + axes: + %{ + dataset: datasets, + element: elements, + region_legend: %Region{ + x: x_region_legend, + y: y_region_legend, + width: width_region_legend + }, + region_content: %Region{ + height: height_region_content + }, + rc_params: %RcParams{cmap_width: cmap_width} + } = axes + } = figure + ) do + + cmap_elements = + datasets + |> Enum.with_index() + |> Enum.map(fn {%Dataset{colors: colors, cmap: cmap}, idx} -> + {start, stop} = Enum.min_max(colors) + tick_labels = Nx.linspace(start, stop, n: 4)|> Nx.to_list() + {x_cmap, y_cmap} = + Algebra.transform_given_point( + x_region_legend, + y_region_legend, + idx * cmap_width, + 0 + ) + |> Algebra.flip_y_coordinate() + %Cmap{ + id: "colorGradient", + cmap: fetch_cmap(cmap), + container: %Rect{x: x_cmap, y: y_cmap, width: cmap_width, height: height_region_content} + } + + end) + + %Figure{figure | axes: %{axes | element: elements ++ cmap_elements}} + end + + def cast_legends(figure), do: figure + defp fetch_cmap(cmap) when is_binary(cmap), do: cmap|> String.to_atom()|> fetch_cmap() + defp fetch_cmap(cmap) do + apply(Colormap, cmap, []) + end defp calculate_center(%Region{x: x, y: y, width: width}, :x) do {calculate_distance({x, y}, {x + width, y}) / 2 + x, y} end diff --git a/lib/matplotex/figure/dataset.ex b/lib/matplotex/figure/dataset.ex index 5acf25c..ca84be5 100644 --- a/lib/matplotex/figure/dataset.ex +++ b/lib/matplotex/figure/dataset.ex @@ -15,7 +15,10 @@ defmodule Matplotex.Figure.Dataset do width: @default_width, x: [], y: [], + colors: [], + sizes: [], transformed: [], + cmap: :viridis, color: @default_color, alpha: @default_alpha, marker: @default_marker, diff --git a/lib/matplotex/figure/rc_params.ex b/lib/matplotex/figure/rc_params.ex index c79e590..22b679b 100644 --- a/lib/matplotex/figure/rc_params.ex +++ b/lib/matplotex/figure/rc_params.ex @@ -7,6 +7,7 @@ defmodule Matplotex.Figure.RcParams do @line_style "_" @grid_color "#ddd" @grid_linestyle "--" + @default_cmap_width 0.2 @legend_location "top right" @default_font_size 16 @@ -53,7 +54,8 @@ defmodule Matplotex.Figure.RcParams do legend_items_orientation: @default_legend_items_orientation, x_ticks_count: nil, y_ticks_count: nil, - concurrency: nil + concurrency: nil, + cmap_width: @default_cmap_width def get_rc(%__MODULE__{} = rc_param, get_func) do apply(__MODULE__, get_func, [rc_param]) diff --git a/test/matplotex/figure/cast_test.exs b/test/matplotex/figure/cast_test.exs index 8489a08..f30a007 100644 --- a/test/matplotex/figure/cast_test.exs +++ b/test/matplotex/figure/cast_test.exs @@ -108,5 +108,14 @@ defmodule Matplotex.Figure.CastTest do assert Enum.filter(elements, fn x -> x.type == "figure.legend" end) |> length() == length(dataset) end + test "add colormaps for charts with colormaps", %{figure: figure} do + assert %Figure{axes: %{element: elements}} = + figure + |> Lead.set_regions_areal() + |> Matplotex.set_options(cmap: "virids", colors: [3,4,5,6,7,3,2,4] ) + |> Cast.cast_legends() + + assert Enum.filter(elements, fn x -> x.type == "figure.cmap" end) |> length() == 1 + end end end diff --git a/test/matplotex/figure/lead_test.exs b/test/matplotex/figure/lead_test.exs index 1bc99b3..b04457f 100644 --- a/test/matplotex/figure/lead_test.exs +++ b/test/matplotex/figure/lead_test.exs @@ -70,6 +70,16 @@ defmodule Matplotex.Figure.LeadTest do assert Enum.all?([rlx, rly, rlwidth, rlheight], &(&1 != 0)) end + test "setting region for colormap", %{figure2: figure} do + figure = Matplotex.set_options(figure, cmap: "viridis") + assert %Figure{ + axes: %{ + region_legend: %Region{x: rlx, y: rly, width: rlwidth, height: rlheight} + } + } = Lead.set_regions_areal(figure) + assert Enum.all?([rlx, rly, rlwidth, rlheight], &(&1 != 0)) + end + test "setting content takes the same width of x region and y region", %{figure2: figure} do assert %Figure{ axes: %{ From 55ea0bb8656e7a7b6adadfc7221dbaf54c6bfcee Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Wed, 29 Jan 2025 18:57:13 +0530 Subject: [PATCH 02/11] color scheme --- lib/matplotex/colorscheme/colormap.ex | 4 +-- lib/matplotex/figure/cast.ex | 41 ++++++++++++++++++--------- test/matplotex/figure/cast_test.exs | 7 +++-- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/lib/matplotex/colorscheme/colormap.ex b/lib/matplotex/colorscheme/colormap.ex index e682793..5ce2cc4 100644 --- a/lib/matplotex/colorscheme/colormap.ex +++ b/lib/matplotex/colorscheme/colormap.ex @@ -35,8 +35,8 @@ defmodule Matplotex.Colorscheme.Colormap do |> Enum.map(&colormap(&1, size)) end - defp colormap({index, color}, size) do - offset = index / size / 100 + defp colormap({color, idx}, size) do + offset = idx/ size / 100 %__MODULE__{color: color, offset: offset} end end diff --git a/lib/matplotex/figure/cast.ex b/lib/matplotex/figure/cast.ex index 8f9ce1f..1cbbc62 100644 --- a/lib/matplotex/figure/cast.ex +++ b/lib/matplotex/figure/cast.ex @@ -498,41 +498,56 @@ defmodule Matplotex.Figure.Cast do %{ dataset: datasets, element: elements, + cmap: cmap, region_legend: %Region{ x: x_region_legend, - y: y_region_legend, - width: width_region_legend + y: y_region_legend }, region_content: %Region{ height: height_region_content - }, - rc_params: %RcParams{cmap_width: cmap_width} - } = axes + } + } = axes, + rc_params: %RcParams{cmap_width: cmap_width, x_tick_font: x_tick_font, tick_line_length: tick_line_length} } = figure - ) do - - + ) when not is_nil(cmap) do cmap_elements = datasets |> Enum.with_index() |> Enum.map(fn {%Dataset{colors: colors, cmap: cmap}, idx} -> + {start, stop} = Enum.min_max(colors) tick_labels = Nx.linspace(start, stop, n: 4)|> Nx.to_list() - {x_cmap, y_cmap} = + {x_cmap, y_cmap} = cmap_coords = Algebra.transform_given_point( x_region_legend, y_region_legend, idx * cmap_width, 0 ) - |> Algebra.flip_y_coordinate() - %Cmap{ + unit_size = height_region_content / 5 + ticks = tick_labels|>Enum.with_index()|>Enum.map( + fn {tick, idx} -> + position_on_bar = (idx + 1) * unit_size + tick_coords = {x_cmap_tick, y_cord_tick} = {x_cmap, y_cmap}|>Algebra.transform_given_point({cmap_width, position_on_bar}) + {x2_cmap_tick, _} = Algebra.transform_given_point(tick_coords, {0, tick_line_length}) + tick_label = Label.cast_label(%Label{text: tick}, x_tick_font) + %Tick{ + type: "tick.cmap", + tick_line: %Line{x1: x_cmap_tick, x2: x2_cmap_tick, y1: y_cord_tick, y2: y_cord_tick }, + label: tick_label + } + end + ) + + {x_cmap, y_cmap} = Algebra.flip_y_coordinate(cmap_coords) + [%Cmap{ id: "colorGradient", cmap: fetch_cmap(cmap), container: %Rect{x: x_cmap, y: y_cmap, width: cmap_width, height: height_region_content} - } + }] ++ ticks end) + |> List.flatten() %Figure{figure | axes: %{axes | element: elements ++ cmap_elements}} end @@ -540,7 +555,7 @@ defmodule Matplotex.Figure.Cast do def cast_legends(figure), do: figure defp fetch_cmap(cmap) when is_binary(cmap), do: cmap|> String.to_atom()|> fetch_cmap() defp fetch_cmap(cmap) do - apply(Colormap, cmap, []) + apply(Colormap, cmap, [])|>Colormap.make_colormap() end defp calculate_center(%Region{x: x, y: y, width: width}, :x) do {calculate_distance({x, y}, {x + width, y}) / 2 + x, y} diff --git a/test/matplotex/figure/cast_test.exs b/test/matplotex/figure/cast_test.exs index f30a007..579462e 100644 --- a/test/matplotex/figure/cast_test.exs +++ b/test/matplotex/figure/cast_test.exs @@ -108,14 +108,15 @@ defmodule Matplotex.Figure.CastTest do assert Enum.filter(elements, fn x -> x.type == "figure.legend" end) |> length() == length(dataset) end - test "add colormaps for charts with colormaps", %{figure: figure} do + test "add colormaps for charts with colormaps" do assert %Figure{axes: %{element: elements}} = - figure + [1,2,3,4,5,6] + |> Matplotex.plot([1,2,3,4,5], cmap: "viridis", colors: [3,4,5,6,7,3,2,4] ) |> Lead.set_regions_areal() - |> Matplotex.set_options(cmap: "virids", colors: [3,4,5,6,7,3,2,4] ) |> Cast.cast_legends() assert Enum.filter(elements, fn x -> x.type == "figure.cmap" end) |> length() == 1 + assert Enum.filter(elements, fn x -> x.type == "tick.cmap" end) |> length() == 4 end end end From 01bdb11a1de4f1afddde8a7b8ede21990f98a009 Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Thu, 30 Jan 2025 17:42:07 +0530 Subject: [PATCH 03/11] cbar with colors --- lib/matplotex/colorscheme/colormap.ex | 3 +- lib/matplotex/element.ex | 6 ++ lib/matplotex/element/cmap.ex | 14 ++-- lib/matplotex/figure/cast.ex | 101 ++++++++++++++++++-------- lib/matplotex/figure/rc_params.ex | 1 + lib/matplotex/figure/sketch.ex | 13 +--- test/matplotex/figure/cast_test.exs | 12 ++- test/matplotex/figure/lead_test.exs | 10 ++- 8 files changed, 101 insertions(+), 59 deletions(-) diff --git a/lib/matplotex/colorscheme/colormap.ex b/lib/matplotex/colorscheme/colormap.ex index 5ce2cc4..482a63c 100644 --- a/lib/matplotex/colorscheme/colormap.ex +++ b/lib/matplotex/colorscheme/colormap.ex @@ -29,14 +29,13 @@ defmodule Matplotex.Colorscheme.Colormap do def make_colormap(colors) do size = length(colors) - colors |> Enum.with_index() |> Enum.map(&colormap(&1, size)) end defp colormap({color, idx}, size) do - offset = idx/ size / 100 + offset = idx / size * 100 %__MODULE__{color: color, offset: offset} end end diff --git a/lib/matplotex/element.ex b/lib/matplotex/element.ex index 81bec7b..2a80b6d 100644 --- a/lib/matplotex/element.ex +++ b/lib/matplotex/element.ex @@ -14,6 +14,12 @@ defmodule Matplotex.Element do quote do @behaviour Matplotex.Element import Matplotex.Element, only: [to_pixel: 1] + + defimpl String.Chars, for: __MODULE__ do + def to_string(%module{} = element) do + module.assemble(element) + end + end end end end diff --git a/lib/matplotex/element/cmap.ex b/lib/matplotex/element/cmap.ex index 29d2cd7..ffa4948 100644 --- a/lib/matplotex/element/cmap.ex +++ b/lib/matplotex/element/cmap.ex @@ -3,12 +3,10 @@ defmodule Matplotex.Element.Cmap do alias Matplotex.Element use Element - defstruct [ - type: "figure.cmap", - id: nil, - cmap: [], - container: %Rect{} - ] + defstruct type: "figure.cmap", + id: nil, + cmap: [], + container: %Rect{} @impl Element def assemble(element) do @@ -26,8 +24,8 @@ defmodule Matplotex.Element.Cmap do ~s() end - def color_gradient(element) do - "url(##{element.id})" + def color_gradient(%__MODULE__{container: container} = element) do + %__MODULE__{element | container: %{container | color: "url(##{element.id})"}} end def get_x(%{x: x}), do: to_pixel(x) diff --git a/lib/matplotex/figure/cast.ex b/lib/matplotex/figure/cast.ex index 1cbbc62..ad9b98b 100644 --- a/lib/matplotex/figure/cast.ex +++ b/lib/matplotex/figure/cast.ex @@ -501,51 +501,90 @@ defmodule Matplotex.Figure.Cast do cmap: cmap, region_legend: %Region{ x: x_region_legend, - y: y_region_legend + y: y_region_legend, + width: width_region_legend }, region_content: %Region{ height: height_region_content } } = axes, - rc_params: %RcParams{cmap_width: cmap_width, x_tick_font: x_tick_font, tick_line_length: tick_line_length} + rc_params: %RcParams{ + cmap_width: cmap_width, + cmap_tick_font: cmap_tick_font, + tick_line_length: tick_line_length, + padding: padding + } } = figure - ) when not is_nil(cmap) do + ) + when not is_nil(cmap) do cmap_elements = datasets |> Enum.with_index() |> Enum.map(fn {%Dataset{colors: colors, cmap: cmap}, idx} -> - + cmap_padding = width_region_legend * padding * 4 {start, stop} = Enum.min_max(colors) - tick_labels = Nx.linspace(start, stop, n: 4)|> Nx.to_list() - {x_cmap, y_cmap} = cmap_coords = + tick_labels = Nx.linspace(start, stop, n: 4) |> Nx.to_list() + + {x_cmap, y_cmap} = + cmap_coords = Algebra.transform_given_point( x_region_legend, y_region_legend, idx * cmap_width, 0 ) - unit_size = height_region_content / 5 - ticks = tick_labels|>Enum.with_index()|>Enum.map( - fn {tick, idx} -> - position_on_bar = (idx + 1) * unit_size - tick_coords = {x_cmap_tick, y_cord_tick} = {x_cmap, y_cmap}|>Algebra.transform_given_point({cmap_width, position_on_bar}) - {x2_cmap_tick, _} = Algebra.transform_given_point(tick_coords, {0, tick_line_length}) - tick_label = Label.cast_label(%Label{text: tick}, x_tick_font) - %Tick{ - type: "tick.cmap", - tick_line: %Line{x1: x_cmap_tick, x2: x2_cmap_tick, y1: y_cord_tick, y2: y_cord_tick }, - label: tick_label - } - end - ) - - {x_cmap, y_cmap} = Algebra.flip_y_coordinate(cmap_coords) - [%Cmap{ - id: "colorGradient", - cmap: fetch_cmap(cmap), - container: %Rect{x: x_cmap, y: y_cmap, width: cmap_width, height: height_region_content} - }] ++ ticks - + |> Algebra.transform_given_point({cmap_padding, 0}) + + unit_size = height_region_content / 5 + + ticks = + tick_labels + |> Enum.with_index() + |> Enum.map(fn {tick, idx} -> + position_on_bar = (idx + 1) * unit_size + + tick_coords = + {x_cmap_tick, y_cord_tick} = + {x_cmap, y_cmap} + |> Algebra.transform_given_point({cmap_width, position_on_bar}) + |> Algebra.flip_y_coordinate() + |> Algebra.transform_given_point({0, height_region_content}) + + {x2_cmap_tick, _} = Algebra.transform_given_point(tick_coords, {tick_line_length, 0}) + + tick_label = + Label.cast_label( + %Label{type: "tick.cmap", x: x2_cmap_tick, y: y_cord_tick, text: tick}, + cmap_tick_font + ) + + %Tick{ + type: "tick.cmap", + tick_line: %Line{ + type: "tick.cmap", + x1: x_cmap_tick, + x2: x2_cmap_tick, + y1: y_cord_tick, + y2: y_cord_tick + }, + label: tick_label + } + end) + + {x_cmap, y_cmap} = Algebra.flip_y_coordinate(cmap_coords) + + [ + %Cmap{ + id: "colorGradient", + cmap: fetch_cmap(cmap), + container: %Rect{ + x: x_cmap, + y: y_cmap, + width: cmap_width, + height: height_region_content + } + }|>Cmap.color_gradient() + ] ++ ticks end) |> List.flatten() @@ -553,10 +592,12 @@ defmodule Matplotex.Figure.Cast do end def cast_legends(figure), do: figure - defp fetch_cmap(cmap) when is_binary(cmap), do: cmap|> String.to_atom()|> fetch_cmap() + defp fetch_cmap(cmap) when is_binary(cmap), do: cmap |> String.to_atom() |> fetch_cmap() + defp fetch_cmap(cmap) do - apply(Colormap, cmap, [])|>Colormap.make_colormap() + apply(Colormap, cmap, []) |> Colormap.make_colormap() end + defp calculate_center(%Region{x: x, y: y, width: width}, :x) do {calculate_distance({x, y}, {x + width, y}) / 2 + x, y} end diff --git a/lib/matplotex/figure/rc_params.ex b/lib/matplotex/figure/rc_params.ex index 22b679b..c72c293 100644 --- a/lib/matplotex/figure/rc_params.ex +++ b/lib/matplotex/figure/rc_params.ex @@ -25,6 +25,7 @@ defmodule Matplotex.Figure.RcParams do y_tick_font: %Font{text_anchor: "start"}, x_label_font: @font, y_label_font: @font, + cmap_tick_font: %Font{text_anchor: "start"}, title_font: %Font{font_size: @default_title_font_size, dominant_baseline: "auto"}, legend_font: %Font{text_anchor: "start"}, slice_label_font: @font, diff --git a/lib/matplotex/figure/sketch.ex b/lib/matplotex/figure/sketch.ex index 1315ef5..5b4a1e0 100644 --- a/lib/matplotex/figure/sketch.ex +++ b/lib/matplotex/figure/sketch.ex @@ -3,15 +3,6 @@ defmodule Matplotex.Figure.Sketch do alias Matplotex.Figure @dpi 96 - def call({stream, %Figure{figsize: {width, height}}}) do - stream - |> Stream.map(fn %module{} = elem -> - elem = module.flipy(elem, height) - module.assemble(elem) - end) - |> wrap_with_tag(width * @dpi, height * @dpi) - end - def call(%Figure{axes: %{element: elements}, figsize: {width, height}}) do elements |> build_elements() @@ -24,11 +15,11 @@ defmodule Matplotex.Figure.Sketch do defp build_elements(elements) do "#{for element <- elements do - svgfy_element(element) + to_string(element) end}" end - defp svgfy_element(%module{} = element), do: module.assemble(element) + defp wrap_with_tag(svg, width, height) do ~s( x.type == "figure.legend" end) |> length() == length(dataset) end + test "add colormaps for charts with colormaps" do assert %Figure{axes: %{element: elements}} = - [1,2,3,4,5,6] - |> Matplotex.plot([1,2,3,4,5], cmap: "viridis", colors: [3,4,5,6,7,3,2,4] ) - |> Lead.set_regions_areal() - |> Cast.cast_legends() + [1, 2, 3, 4, 5, 6] + |> Matplotex.plot([1, 2, 3, 4, 5], + cmap: "viridis", + colors: [3, 4, 5, 6, 7, 3, 2, 4] + ) + |> Lead.set_regions_areal() + |> Cast.cast_legends() assert Enum.filter(elements, fn x -> x.type == "figure.cmap" end) |> length() == 1 assert Enum.filter(elements, fn x -> x.type == "tick.cmap" end) |> length() == 4 diff --git a/test/matplotex/figure/lead_test.exs b/test/matplotex/figure/lead_test.exs index b04457f..a8cafb6 100644 --- a/test/matplotex/figure/lead_test.exs +++ b/test/matplotex/figure/lead_test.exs @@ -72,11 +72,13 @@ defmodule Matplotex.Figure.LeadTest do test "setting region for colormap", %{figure2: figure} do figure = Matplotex.set_options(figure, cmap: "viridis") + assert %Figure{ - axes: %{ - region_legend: %Region{x: rlx, y: rly, width: rlwidth, height: rlheight} - } - } = Lead.set_regions_areal(figure) + axes: %{ + region_legend: %Region{x: rlx, y: rly, width: rlwidth, height: rlheight} + } + } = Lead.set_regions_areal(figure) + assert Enum.all?([rlx, rly, rlwidth, rlheight], &(&1 != 0)) end From 789d7f68180a4b7b9371c1416e04e34f305be94a Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Thu, 30 Jan 2025 18:55:23 +0530 Subject: [PATCH 04/11] correcting colors --- lib/matplotex/colorscheme/colormap.ex | 20 ++++---------------- lib/matplotex/figure/cast.ex | 6 +++--- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/lib/matplotex/colorscheme/colormap.ex b/lib/matplotex/colorscheme/colormap.ex index 482a63c..4fb86bb 100644 --- a/lib/matplotex/colorscheme/colormap.ex +++ b/lib/matplotex/colorscheme/colormap.ex @@ -1,32 +1,20 @@ defmodule Matplotex.Colorscheme.Colormap do defstruct [:color, :offset, opacity: 1] - @dark_purple "#2A132F" - @purple "#441E4B" - @yellow "#fbde41" - @red "#eb3767" - @orange "#EEA103" - @black "#1e1b13" - @dark_blue "#245BC1" def viridis do - [@dark_purple, @yellow] + ["#fde725","#21918c","#3b528b","#440154"] end def plasma do - [@dark_purple, @red, @yellow] + ["#F7E425","#ED6925", "#9C179E", "#0C0786" ] end def inferno do - [@black, @red, @orange, @yellow] + ["#FCFFA4","#F56C3E","#B12A90","#000004"] end def magma do - [@black, @purple, @red, @yellow] + ["#FCFDBF","#FB8861", "#B73779", "#000004"] end - - def civids do - [@dark_blue, @yellow] - end - def make_colormap(colors) do size = length(colors) colors diff --git a/lib/matplotex/figure/cast.ex b/lib/matplotex/figure/cast.ex index ad9b98b..f04bb33 100644 --- a/lib/matplotex/figure/cast.ex +++ b/lib/matplotex/figure/cast.ex @@ -550,11 +550,11 @@ defmodule Matplotex.Figure.Cast do |> Algebra.flip_y_coordinate() |> Algebra.transform_given_point({0, height_region_content}) - {x2_cmap_tick, _} = Algebra.transform_given_point(tick_coords, {tick_line_length, 0}) - + {x2_cmap_tick, _} = tick_x2 = Algebra.transform_given_point(tick_coords, {tick_line_length, 0}) + {tick_label_x, _} = Algebra.transform_given_point(tick_x2, {tick_line_length, 0}) tick_label = Label.cast_label( - %Label{type: "tick.cmap", x: x2_cmap_tick, y: y_cord_tick, text: tick}, + %Label{type: "tick.cmap", x: tick_label_x, y: y_cord_tick, text: tick}, cmap_tick_font ) From 98c98189c43244864fe73fce88815d9bc2d6a3dc Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Fri, 31 Jan 2025 21:15:24 +0530 Subject: [PATCH 05/11] color mixer --- lib/matplotex/colorscheme/blender.ex | 91 ++++++++++++++++++++++++++++ lib/matplotex/colorscheme/garner.ex | 5 ++ lib/matplotex/colorscheme/rgb.ex | 65 ++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 lib/matplotex/colorscheme/blender.ex create mode 100644 lib/matplotex/colorscheme/garner.ex create mode 100644 lib/matplotex/colorscheme/rgb.ex diff --git a/lib/matplotex/colorscheme/blender.ex b/lib/matplotex/colorscheme/blender.ex new file mode 100644 index 0000000..1e4a9d1 --- /dev/null +++ b/lib/matplotex/colorscheme/blender.ex @@ -0,0 +1,91 @@ +defmodule Matplotex.Colorscheme.Blender do +alias Matplotex.Colorscheme.Rgb + + @rgb_fields [:red, :green, :blue, :alpha] + + @type color :: %Rgb{ + red: :float, + green: :float, + blue: :float, + alpha: :float + } + + + def mix(color1, color2, weight \\ 0.5) do + + p = weight + w = p * 2 - 1 + a = color1.alpha - color2.alpha + + w1 = (if(w * a == -1, do: w, else: (w + a) / (1 + w * a)) + 1) / 2.0 + w2 = 1 - w1 + + [r, g, b] = + [:red, :green, :blue] + |> Enum.map(fn key -> + get_attribute(color1, key) * w1 + get_attribute(color2, key) * w2 + end) + + alpha = get_alpha(color1) * p + get_alpha(color2) * (1 - p) + rgb(r, g, b, alpha) + end + defdelegate rgb(red, green, blue), to: Rgb + defdelegate rgb(red, green, blue, alpha), to: Rgb + + + @doc """ + Gets the `:red` property of the color. + """ + @spec get_red(color) :: float + def get_red(color), do: get_attribute(color, :red) + + @doc """ + Gets the `:green` property of the color. + """ + @spec get_green(color) :: float + def get_green(color), do: get_attribute(color, :green) + + @doc """ + Gets the `:blue` property of the color. + """ + @spec get_blue(color) :: float + def get_blue(color), do: get_attribute(color, :blue) + + @doc """ + Gets the `:hue` property of the color. + """ + @spec get_hue(color) :: float + def get_hue(color), do: get_attribute(color, :hue) + + @doc """ + Gets the `:saturation` property of the color. + """ + @spec get_saturation(color) :: float + def get_saturation(color), do: get_attribute(color, :saturation) + + @doc """ + Gets the `:lightness` property of the color. + """ + @spec get_lightness(color) :: float + def get_lightness(color), do: get_attribute(color, :lightness) + + @doc """ + Gets the `:alpha` property of the color. + """ + @spec get_alpha(color) :: float + def get_alpha(color), do: get_attribute(color, :alpha) + + @doc """ + Get's any color attribute from the color. + """ + @spec get_attribute(color, atom()) :: float + def get_attribute(color, key) do + color + |> cast_color_by_attribute(key) + |> Map.fetch!(key) + end + + defp cast_color_by_attribute(color, attribute) when attribute in @rgb_fields, do: color + + +end diff --git a/lib/matplotex/colorscheme/garner.ex b/lib/matplotex/colorscheme/garner.ex new file mode 100644 index 0000000..4445e98 --- /dev/null +++ b/lib/matplotex/colorscheme/garner.ex @@ -0,0 +1,5 @@ +defmodule Matplotex.Colorscheme.Garner do + + defstruct [:range, :cmap, :preceeding, :minor, :major, :final] + +end diff --git a/lib/matplotex/colorscheme/rgb.ex b/lib/matplotex/colorscheme/rgb.ex new file mode 100644 index 0000000..8cb034a --- /dev/null +++ b/lib/matplotex/colorscheme/rgb.ex @@ -0,0 +1,65 @@ +defmodule Matplotex.Colorscheme.Rgb do + @moduledoc false + + defstruct [ + red: 0.0, # 0-255 + green: 0.0, # 0-255 + blue: 0.0, # 0-255 + alpha: 1.0 # 0-1 + ] + + def rgb(red, green, blue, alpha\\1.0) + def rgb({red, :percent}, {green, :percent}, {blue, :percent}, alpha) do + rgb(red * 255, green * 255, blue * 255, alpha) + end + def rgb(red, green, blue, alpha) do + %__MODULE__{ + red: cast(red, :red), + green: cast(green, :green), + blue: cast(blue, :blue), + alpha: cast(alpha, :alpha) + } + end + + def to_string(struct, type\\nil) + + def to_string(struct, :nil) do + type = case struct.alpha do + 1.0 -> :hex + _ -> :rgba + end + to_string(struct, type) + end + + def to_string(%__MODULE__{red: r, green: g, blue: b, alpha: alpha}, :rgba) do + "rgba(#{round(r)}, #{round(g)}, #{round(b)}, #{alpha})" + end + def to_string(%__MODULE__{red: r, green: g, blue: b, alpha: 1.0}, :hex) do + "#" <> to_hex(r) <> to_hex(g) <> to_hex(b) + end + + def cast(value, field) when field in [:red, :green, :blue] do + value/1 + |> min(255.0) + |> max(0.0) + end + def cast(value, :alpha) do + value/1 + |> min(1.0) + |> max(0.0) + end + + defp to_hex(value) when is_float(value), do: + to_hex(round(value)) + defp to_hex(value) when value < 16, do: + "0" <> Integer.to_string(value, 16) + defp to_hex(value) when is_integer(value), do: + Integer.to_string(value, 16) + +end + +defimpl String.Chars, for: CssColors.RGB do +def to_string(struct) do + CssColors.RGB.to_string(struct) +end +end From 20c6e8c47044807e86d7ba39268d7da4b48cdbfd Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Mon, 3 Feb 2025 22:22:33 +0530 Subject: [PATCH 06/11] garner --- lib/matplotex/colorscheme/colormap.ex | 8 ++++ lib/matplotex/colorscheme/garner.ex | 43 +++++++++++++++++++++- lib/matplotex/colorscheme/rgb.ex | 2 +- lib/matplotex/figure/cast.ex | 6 +-- test/matplotex/colorscheme/garner_test.exs | 12 ++++++ 5 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 test/matplotex/colorscheme/garner_test.exs diff --git a/lib/matplotex/colorscheme/colormap.ex b/lib/matplotex/colorscheme/colormap.ex index 4fb86bb..f89b25c 100644 --- a/lib/matplotex/colorscheme/colormap.ex +++ b/lib/matplotex/colorscheme/colormap.ex @@ -15,6 +15,12 @@ defmodule Matplotex.Colorscheme.Colormap do def magma do ["#FCFDBF","#FB8861", "#B73779", "#000004"] end + + def fetch_cmap(cmap) when is_binary(cmap), do: cmap |> String.to_atom() |> fetch_cmap() + + def fetch_cmap(cmap) do + apply(Colormap, cmap, []) |> make_colormap() + end def make_colormap(colors) do size = length(colors) colors @@ -26,4 +32,6 @@ defmodule Matplotex.Colorscheme.Colormap do offset = idx / size * 100 %__MODULE__{color: color, offset: offset} end + + end diff --git a/lib/matplotex/colorscheme/garner.ex b/lib/matplotex/colorscheme/garner.ex index 4445e98..cd86cc1 100644 --- a/lib/matplotex/colorscheme/garner.ex +++ b/lib/matplotex/colorscheme/garner.ex @@ -1,5 +1,44 @@ defmodule Matplotex.Colorscheme.Garner do +alias Matplotex.Colorscheme.Blender +alias Matplotex.InputError +alias Matplotex.Colorscheme.Colormap - defstruct [:range, :cmap, :preceeding, :minor, :major, :final] + defstruct [:range, :color_cue, :cmap, :preceeding, :minor, :major, :final] -end + def garn_color({min, max} = range, point, cmap) when max != min do + cue = (point - min) / (max - min) + cmap + |> fetch_from_cmap() + |> put_range(range, cue) + |> point_color() + end + + defp fetch_from_cmap(cmap) do + cmap + |>Colormap.fetch_cmap() + |>place_edges() + end + + defp put_range(%__MODULE__{} = garner, range, cue) do + %__MODULE__{garner | range: range, color_cue: cue} + end + + defp place_edges([preceeding, minor, major,final]) do + %__MODULE__{preceeding: preceeding, minor: minor, major: major, final: final} + end + defp place_edges(_) do + raise InputError, message: "Invalid colormap" + end + + defp point_color(%__MODULE__{color_cue: cue, preceeding: preceeding, minor: minor}) when cue < minor do + Blender.mix(minor, preceeding, cue) + end + + defp point_color(%__MODULE__{color_cue: cue, minor: minor, major: major}) when cue < major do + Blender.mix(minor, major, cue) + end + + defp point_color(%__MODULE__{color_cue: cue, major: major, final: final}) when cue >= major do + final + end + end diff --git a/lib/matplotex/colorscheme/rgb.ex b/lib/matplotex/colorscheme/rgb.ex index 8cb034a..8796124 100644 --- a/lib/matplotex/colorscheme/rgb.ex +++ b/lib/matplotex/colorscheme/rgb.ex @@ -60,6 +60,6 @@ end defimpl String.Chars, for: CssColors.RGB do def to_string(struct) do - CssColors.RGB.to_string(struct) + Matplotex.Colorscheme.Rgb.to_string(struct) end end diff --git a/lib/matplotex/figure/cast.ex b/lib/matplotex/figure/cast.ex index f04bb33..7f2ecc8 100644 --- a/lib/matplotex/figure/cast.ex +++ b/lib/matplotex/figure/cast.ex @@ -576,7 +576,7 @@ defmodule Matplotex.Figure.Cast do [ %Cmap{ id: "colorGradient", - cmap: fetch_cmap(cmap), + cmap: Colormap.fetch_cmap(cmap), container: %Rect{ x: x_cmap, y: y_cmap, @@ -592,11 +592,7 @@ defmodule Matplotex.Figure.Cast do end def cast_legends(figure), do: figure - defp fetch_cmap(cmap) when is_binary(cmap), do: cmap |> String.to_atom() |> fetch_cmap() - defp fetch_cmap(cmap) do - apply(Colormap, cmap, []) |> Colormap.make_colormap() - end defp calculate_center(%Region{x: x, y: y, width: width}, :x) do {calculate_distance({x, y}, {x + width, y}) / 2 + x, y} diff --git a/test/matplotex/colorscheme/garner_test.exs b/test/matplotex/colorscheme/garner_test.exs new file mode 100644 index 0000000..95fac5e --- /dev/null +++ b/test/matplotex/colorscheme/garner_test.exs @@ -0,0 +1,12 @@ +defmodule Matplotex.Colorscheme.GarnerTest do + alias Matplotex.Colorscheme.Garner + use Matplotex.PlotCase + + describe "garn_color/3" do + test "garn the color for specific point in the number" do + colorset = [3,4,5,6,6,4,9] + color = Garner.garn_color(Enum.min_max(colorset), Enum.min(colorset), "viridis") + assert is_binary(color) + end + end +end From 3071b2c42a35fa5fda75da77e00d66038375df56 Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Tue, 4 Feb 2025 17:20:21 +0530 Subject: [PATCH 07/11] cmap --- lib/matplotex/colorscheme/colormap.ex | 2 +- lib/matplotex/colorscheme/garner.ex | 14 +++++++++---- lib/matplotex/colorscheme/rgb.ex | 22 +++++++++++++++++++- test/matplotex/colorscheme/garner_test.exs | 5 ++++- test/matplotex/figure/areal/scatter_test.exs | 1 + 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/lib/matplotex/colorscheme/colormap.ex b/lib/matplotex/colorscheme/colormap.ex index f89b25c..0fd155d 100644 --- a/lib/matplotex/colorscheme/colormap.ex +++ b/lib/matplotex/colorscheme/colormap.ex @@ -19,7 +19,7 @@ defmodule Matplotex.Colorscheme.Colormap do def fetch_cmap(cmap) when is_binary(cmap), do: cmap |> String.to_atom() |> fetch_cmap() def fetch_cmap(cmap) do - apply(Colormap, cmap, []) |> make_colormap() + apply(__MODULE__, cmap, []) |> make_colormap() end def make_colormap(colors) do size = length(colors) diff --git a/lib/matplotex/colorscheme/garner.ex b/lib/matplotex/colorscheme/garner.ex index cd86cc1..86e4474 100644 --- a/lib/matplotex/colorscheme/garner.ex +++ b/lib/matplotex/colorscheme/garner.ex @@ -1,4 +1,5 @@ defmodule Matplotex.Colorscheme.Garner do +alias Matplotex.Colorscheme.Rgb alias Matplotex.Colorscheme.Blender alias Matplotex.InputError alias Matplotex.Colorscheme.Colormap @@ -16,6 +17,7 @@ alias Matplotex.Colorscheme.Colormap defp fetch_from_cmap(cmap) do cmap |>Colormap.fetch_cmap() + |>to_rgb() |>place_edges() end @@ -23,22 +25,26 @@ alias Matplotex.Colorscheme.Colormap %__MODULE__{garner | range: range, color_cue: cue} end + defp to_rgb(color_map) do + Enum.map(color_map, &Rgb.from_cmap!(&1)) + end + defp place_edges([preceeding, minor, major,final]) do - %__MODULE__{preceeding: preceeding, minor: minor, major: major, final: final} + %__MODULE__{preceeding: preceeding.color, minor: minor.color, major: major.color, final: final.color} end defp place_edges(_) do raise InputError, message: "Invalid colormap" end defp point_color(%__MODULE__{color_cue: cue, preceeding: preceeding, minor: minor}) when cue < minor do - Blender.mix(minor, preceeding, cue) + minor|> Blender.mix(preceeding, cue)|> Rgb.to_string() end defp point_color(%__MODULE__{color_cue: cue, minor: minor, major: major}) when cue < major do - Blender.mix(minor, major, cue) + major|> Blender.mix(minor, cue)|> Rgb.to_string() end defp point_color(%__MODULE__{color_cue: cue, major: major, final: final}) when cue >= major do - final + final|> Blender.mix(major)|> Rgb.to_string() end end diff --git a/lib/matplotex/colorscheme/rgb.ex b/lib/matplotex/colorscheme/rgb.ex index 8796124..590c960 100644 --- a/lib/matplotex/colorscheme/rgb.ex +++ b/lib/matplotex/colorscheme/rgb.ex @@ -1,6 +1,6 @@ defmodule Matplotex.Colorscheme.Rgb do @moduledoc false - +alias Matplotex.Colorscheme.Colormap defstruct [ red: 0.0, # 0-255 green: 0.0, # 0-255 @@ -56,8 +56,28 @@ defmodule Matplotex.Colorscheme.Rgb do defp to_hex(value) when is_integer(value), do: Integer.to_string(value, 16) + def from_hex!(input) do + {:ok, color} = from_hex(input) + color + end + + def from_cmap!(%Colormap{color: color} = cmap) do + %Colormap{cmap | color: from_hex!(color) } + end + + def from_hex("#" <> <>) do + {:ok, rgb(parse_hex(r), parse_hex(g), parse_hex(b))} + end + def from_hex("#" <> <>) do + {:ok, rgb(parse_hex(r <> r), parse_hex(g <> g), parse_hex(b <> b))} + end + + defp parse_hex(s), do: String.to_integer(s, 16) + + end + defimpl String.Chars, for: CssColors.RGB do def to_string(struct) do Matplotex.Colorscheme.Rgb.to_string(struct) diff --git a/test/matplotex/colorscheme/garner_test.exs b/test/matplotex/colorscheme/garner_test.exs index 95fac5e..b2d20eb 100644 --- a/test/matplotex/colorscheme/garner_test.exs +++ b/test/matplotex/colorscheme/garner_test.exs @@ -6,7 +6,10 @@ defmodule Matplotex.Colorscheme.GarnerTest do test "garn the color for specific point in the number" do colorset = [3,4,5,6,6,4,9] color = Garner.garn_color(Enum.min_max(colorset), Enum.min(colorset), "viridis") - assert is_binary(color) + assert is_color(color) end end + + defp is_color("#" <> <<_r :: binary-size(2), _g :: binary-size(2), _b :: binary-size(2)>>), do: true + defp is_color(_), do: false end diff --git a/test/matplotex/figure/areal/scatter_test.exs b/test/matplotex/figure/areal/scatter_test.exs index 9b16fee..60d8540 100644 --- a/test/matplotex/figure/areal/scatter_test.exs +++ b/test/matplotex/figure/areal/scatter_test.exs @@ -12,6 +12,7 @@ defmodule Matplotex.Figure.Areal.ScatterTest do assert %Figure{axes: %{data: {x, _y}, element: elements}} = Scatter.materialize(figure) assert Enum.count(elements, fn elem -> elem.type == "plot.marker" end) == length(x) end + end describe "generate_ticks/2" do From 327f293489009be549e3687589d6f17dc42abad7 Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Wed, 5 Feb 2025 23:00:22 +0530 Subject: [PATCH 08/11] bubble --- lib/matplotex/colorscheme/colormap.ex | 2 ++ lib/matplotex/colorscheme/garner.ex | 6 ++---- test/matplotex/figure/areal/scatter_test.exs | 11 +++++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/matplotex/colorscheme/colormap.ex b/lib/matplotex/colorscheme/colormap.ex index 0fd155d..594bfe0 100644 --- a/lib/matplotex/colorscheme/colormap.ex +++ b/lib/matplotex/colorscheme/colormap.ex @@ -28,6 +28,8 @@ defmodule Matplotex.Colorscheme.Colormap do |> Enum.map(&colormap(&1, size)) end + def default_cmap(), do: viridis() + defp colormap({color, idx}, size) do offset = idx / size * 100 %__MODULE__{color: color, offset: offset} diff --git a/lib/matplotex/colorscheme/garner.ex b/lib/matplotex/colorscheme/garner.ex index 86e4474..cffdd7a 100644 --- a/lib/matplotex/colorscheme/garner.ex +++ b/lib/matplotex/colorscheme/garner.ex @@ -2,21 +2,19 @@ defmodule Matplotex.Colorscheme.Garner do alias Matplotex.Colorscheme.Rgb alias Matplotex.Colorscheme.Blender alias Matplotex.InputError -alias Matplotex.Colorscheme.Colormap defstruct [:range, :color_cue, :cmap, :preceeding, :minor, :major, :final] def garn_color({min, max} = range, point, cmap) when max != min do cue = (point - min) / (max - min) cmap - |> fetch_from_cmap() + |> make_from_cmap() |> put_range(range, cue) |> point_color() end - defp fetch_from_cmap(cmap) do + defp make_from_cmap(cmap) do cmap - |>Colormap.fetch_cmap() |>to_rgb() |>place_edges() end diff --git a/test/matplotex/figure/areal/scatter_test.exs b/test/matplotex/figure/areal/scatter_test.exs index 60d8540..66ebe4f 100644 --- a/test/matplotex/figure/areal/scatter_test.exs +++ b/test/matplotex/figure/areal/scatter_test.exs @@ -12,7 +12,18 @@ defmodule Matplotex.Figure.Areal.ScatterTest do assert %Figure{axes: %{data: {x, _y}, element: elements}} = Scatter.materialize(figure) assert Enum.count(elements, fn elem -> elem.type == "plot.marker" end) == length(x) end + test "adds point with specific color with color scheme" do + x = [1, 3, 7, 4, 2, 5, 6] + y = [1, 3, 7, 4, 2, 5, 6] + colors = [1, 3, 7, 4, 2, 5, 6] + assert %Figure{axes: %{element: elements}} = x + |> Matplotex.scatter(y, colors: colors) + |> Matplotex.figure(%{figsize: size, margin: margin}) + |> Scatter.materialize() + + assert elements|>Enum.filter(fn elem -> elem.type == "point.color" end)|>length() + end end describe "generate_ticks/2" do From fd2b6531b32027080b8000f9640f2c51be37e962 Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Fri, 7 Feb 2025 16:32:27 +0530 Subject: [PATCH 09/11] updated color scheme --- lib/matplotex/figure/areal/plot_options.ex | 18 ++++++++++++++++-- lib/matplotex/figure/cast.ex | 8 ++++---- test/matplotex/colorscheme/garner_test.exs | 4 +++- .../figure/areal/plot_options_test.exs | 9 +++++++++ test/matplotex/figure/areal/scatter_test.exs | 12 ------------ 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/lib/matplotex/figure/areal/plot_options.ex b/lib/matplotex/figure/areal/plot_options.ex index 8e9c526..1ff8001 100644 --- a/lib/matplotex/figure/areal/plot_options.ex +++ b/lib/matplotex/figure/areal/plot_options.ex @@ -1,5 +1,6 @@ defmodule Matplotex.Figure.Areal.PlotOptions do @moduledoc false + alias Matplotex.Colorscheme.Colormap alias Matplotex.Figure alias Matplotex.Figure.TwoD alias Matplotex.Figure.RcParams @@ -15,11 +16,11 @@ defmodule Matplotex.Figure.Areal.PlotOptions do :region_legend, :region_color_bar ] + @default_cmap :viridis @spec set_options_in_figure(Figure.t(), keyword()) :: Figure.t() def set_options_in_figure(%Figure{} = figure, opts) do opts = sanitize(opts) - figure |> cast_figure(opts) |> cast_axes(opts) @@ -31,11 +32,14 @@ defmodule Matplotex.Figure.Areal.PlotOptions do end defp cast_axes(%Figure{axes: axes} = figure, opts) do + opts = Keyword.delete(opts, :label) + cmap = Keyword.get(opts, :cmap) + colors = Keyword.get(opts, :colors) %Figure{ figure - | axes: axes |> struct(opts) |> cast_two_d_structs(opts) + | axes: axes |> struct(opts) |> cast_two_d_structs(opts)|> update_cmap(cmap, colors) } end @@ -58,4 +62,14 @@ defmodule Matplotex.Figure.Areal.PlotOptions do defp sanitize(opts) do Keyword.drop(opts, @immutable_keys) end + defp update_cmap(axes, nil, colors) when is_list(colors) do + + %{axes | cmap: Colormap.fetch_cmap(@default_cmap)} + end + + defp update_cmap(axes, cmap, colors) when is_list(colors) do + %{axes | cmap: Colormap.fetch_cmap(cmap)} + end + + defp update_cmap(figure, _, _), do: figure end diff --git a/lib/matplotex/figure/cast.ex b/lib/matplotex/figure/cast.ex index 7f2ecc8..a9c94c2 100644 --- a/lib/matplotex/figure/cast.ex +++ b/lib/matplotex/figure/cast.ex @@ -1,7 +1,6 @@ defmodule Matplotex.Figure.Cast do @moduledoc false alias Matplotex.Element.Rect - alias Matplotex.Colorscheme.Colormap alias Matplotex.Element.Cmap alias Matplotex.Figure.Lead alias Matplotex.Element.Legend @@ -20,6 +19,7 @@ defmodule Matplotex.Figure.Cast do @ytick_type "figure.y_tick" @lowest_tick 0 @zero_to_move 0 + @cmap_id "colorGradient" def cast_spines_by_region( %Figure{ @@ -516,7 +516,7 @@ defmodule Matplotex.Figure.Cast do } } = figure ) - when not is_nil(cmap) do + when is_list(cmap) do cmap_elements = datasets |> Enum.with_index() @@ -575,8 +575,8 @@ defmodule Matplotex.Figure.Cast do [ %Cmap{ - id: "colorGradient", - cmap: Colormap.fetch_cmap(cmap), + id: @cmap_id, + cmap: cmap, container: %Rect{ x: x_cmap, y: y_cmap, diff --git a/test/matplotex/colorscheme/garner_test.exs b/test/matplotex/colorscheme/garner_test.exs index b2d20eb..73f7d67 100644 --- a/test/matplotex/colorscheme/garner_test.exs +++ b/test/matplotex/colorscheme/garner_test.exs @@ -1,11 +1,13 @@ defmodule Matplotex.Colorscheme.GarnerTest do + alias Matplotex.Colorscheme.Colormap alias Matplotex.Colorscheme.Garner use Matplotex.PlotCase describe "garn_color/3" do test "garn the color for specific point in the number" do colorset = [3,4,5,6,6,4,9] - color = Garner.garn_color(Enum.min_max(colorset), Enum.min(colorset), "viridis") + viridis = Colormap.fetch_cmap(:viridis) + color = Garner.garn_color(Enum.min_max(colorset), Enum.min(colorset), viridis) assert is_color(color) end end diff --git a/test/matplotex/figure/areal/plot_options_test.exs b/test/matplotex/figure/areal/plot_options_test.exs index adf49be..807dc15 100644 --- a/test/matplotex/figure/areal/plot_options_test.exs +++ b/test/matplotex/figure/areal/plot_options_test.exs @@ -1,4 +1,5 @@ defmodule Matplotex.Figure.Areal.PlotOptionsTest do + alias Matplotex.Figure use Matplotex.PlotCase setup do @@ -27,5 +28,13 @@ defmodule Matplotex.Figure.Areal.PlotOptionsTest do refute figure.axes.element == nil refute figure.axes == nil end + test "updates cmap as a list by its name" do + assert %Figure{axes: %{cmap: cmap}} = [1, 2, 3, 4, 5, 6] + |> Matplotex.plot([1, 2, 3, 4, 5], + cmap: "viridis", + colors: [3, 4, 5, 6, 7, 3, 2, 4] + ) + assert is_list(cmap) + end end end diff --git a/test/matplotex/figure/areal/scatter_test.exs b/test/matplotex/figure/areal/scatter_test.exs index 66ebe4f..9b16fee 100644 --- a/test/matplotex/figure/areal/scatter_test.exs +++ b/test/matplotex/figure/areal/scatter_test.exs @@ -12,18 +12,6 @@ defmodule Matplotex.Figure.Areal.ScatterTest do assert %Figure{axes: %{data: {x, _y}, element: elements}} = Scatter.materialize(figure) assert Enum.count(elements, fn elem -> elem.type == "plot.marker" end) == length(x) end - test "adds point with specific color with color scheme" do - x = [1, 3, 7, 4, 2, 5, 6] - y = [1, 3, 7, 4, 2, 5, 6] - colors = [1, 3, 7, 4, 2, 5, 6] - - assert %Figure{axes: %{element: elements}} = x - |> Matplotex.scatter(y, colors: colors) - |> Matplotex.figure(%{figsize: size, margin: margin}) - |> Scatter.materialize() - - assert elements|>Enum.filter(fn elem -> elem.type == "point.color" end)|>length() - end end describe "generate_ticks/2" do From fa01835b3164f95ae9e3947728e14a5352aa0ded Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Fri, 7 Feb 2025 17:03:29 +0530 Subject: [PATCH 10/11] dissable module doc --- lib/matplotex/colorscheme/blender.ex | 1 + lib/matplotex/colorscheme/colormap.ex | 1 + lib/matplotex/colorscheme/garner.ex | 1 + lib/matplotex/element/cmap.ex | 1 + lib/matplotex/figure/areal/step.ex | 1 + 5 files changed, 5 insertions(+) diff --git a/lib/matplotex/colorscheme/blender.ex b/lib/matplotex/colorscheme/blender.ex index 1e4a9d1..460d32f 100644 --- a/lib/matplotex/colorscheme/blender.ex +++ b/lib/matplotex/colorscheme/blender.ex @@ -1,4 +1,5 @@ defmodule Matplotex.Colorscheme.Blender do +@moduledoc false alias Matplotex.Colorscheme.Rgb @rgb_fields [:red, :green, :blue, :alpha] diff --git a/lib/matplotex/colorscheme/colormap.ex b/lib/matplotex/colorscheme/colormap.ex index 594bfe0..1a8baee 100644 --- a/lib/matplotex/colorscheme/colormap.ex +++ b/lib/matplotex/colorscheme/colormap.ex @@ -1,4 +1,5 @@ defmodule Matplotex.Colorscheme.Colormap do +@moduledoc false defstruct [:color, :offset, opacity: 1] def viridis do ["#fde725","#21918c","#3b528b","#440154"] diff --git a/lib/matplotex/colorscheme/garner.ex b/lib/matplotex/colorscheme/garner.ex index cffdd7a..d3e279a 100644 --- a/lib/matplotex/colorscheme/garner.ex +++ b/lib/matplotex/colorscheme/garner.ex @@ -1,4 +1,5 @@ defmodule Matplotex.Colorscheme.Garner do +@moduledoc false alias Matplotex.Colorscheme.Rgb alias Matplotex.Colorscheme.Blender alias Matplotex.InputError diff --git a/lib/matplotex/element/cmap.ex b/lib/matplotex/element/cmap.ex index ffa4948..0494e1a 100644 --- a/lib/matplotex/element/cmap.ex +++ b/lib/matplotex/element/cmap.ex @@ -1,4 +1,5 @@ defmodule Matplotex.Element.Cmap do +@moduledoc false alias Matplotex.Element.Rect alias Matplotex.Element use Element diff --git a/lib/matplotex/figure/areal/step.ex b/lib/matplotex/figure/areal/step.ex index 5e513cb..11889db 100644 --- a/lib/matplotex/figure/areal/step.ex +++ b/lib/matplotex/figure/areal/step.ex @@ -1,4 +1,5 @@ defmodule Matplotex.Figure.Areal.Step do +@moduledoc false alias Matplotex.Figure.Areal.LinePlot alias Matplotex.Figure alias Matplotex.InputError From 28b93cad962f2ea3c4b775982e20107096e7f407 Mon Sep 17 00:00:00 2001 From: Mohammed Sadique Date: Fri, 7 Feb 2025 17:04:08 +0530 Subject: [PATCH 11/11] version update --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index d18cbd4..8b09896 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule Matplotex.MixProject do [ app: :matplotex, organization: :bigthinkcode, - version: "0.4.6", + version: "0.4.7", elixir: "~> 1.17", start_permanent: Mix.env() == :prod, elixirc_paths: elixirc_paths(Mix.env()),