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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/matplotex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion lib/matplotex/blueprint/frame.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
Expand Down
92 changes: 92 additions & 0 deletions lib/matplotex/colorscheme/blender.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
defmodule Matplotex.Colorscheme.Blender do
@moduledoc false
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
40 changes: 40 additions & 0 deletions lib/matplotex/colorscheme/colormap.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
defmodule Matplotex.Colorscheme.Colormap do
@moduledoc false
defstruct [:color, :offset, opacity: 1]
def viridis do
["#fde725","#21918c","#3b528b","#440154"]
end

def plasma do
["#F7E425","#ED6925", "#9C179E", "#0C0786" ]
end

def inferno do
["#FCFFA4","#F56C3E","#B12A90","#000004"]
end

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(__MODULE__, cmap, []) |> make_colormap()
end
def make_colormap(colors) do
size = length(colors)
colors
|> Enum.with_index()
|> 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}
end


end
49 changes: 49 additions & 0 deletions lib/matplotex/colorscheme/garner.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
defmodule Matplotex.Colorscheme.Garner do
@moduledoc false
alias Matplotex.Colorscheme.Rgb
alias Matplotex.Colorscheme.Blender
alias Matplotex.InputError

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
|> make_from_cmap()
|> put_range(range, cue)
|> point_color()
end

defp make_from_cmap(cmap) do
cmap
|>to_rgb()
|>place_edges()
end

defp put_range(%__MODULE__{} = garner, range, cue) do
%__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.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
minor|> Blender.mix(preceeding, cue)|> Rgb.to_string()
end

defp point_color(%__MODULE__{color_cue: cue, minor: minor, major: major}) when cue < major do
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|> Blender.mix(major)|> Rgb.to_string()
end
end
85 changes: 85 additions & 0 deletions lib/matplotex/colorscheme/rgb.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
defmodule Matplotex.Colorscheme.Rgb do
@moduledoc false
alias Matplotex.Colorscheme.Colormap
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)

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("#" <> <<r :: binary-size(2), g :: binary-size(2), b :: binary-size(2)>>) do
{:ok, rgb(parse_hex(r), parse_hex(g), parse_hex(b))}
end
def from_hex("#" <> <<r :: binary-size(1), g :: binary-size(1), b :: binary-size(1)>>) 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)
end
end
6 changes: 6 additions & 0 deletions lib/matplotex/element.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
36 changes: 36 additions & 0 deletions lib/matplotex/element/cmap.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
defmodule Matplotex.Element.Cmap do
@moduledoc false
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(<defs>
<linearGradient id="#{element.id}" x1="0%" y1="0%" x2="0%" y2="100%">
#{for stp <- element.cmap do
tag_stop(stp)
end}
</linearGradient>
</defs>
#{Element.assemble(element.container)})
end

def tag_stop(%{offset: offset, color: color, opacity: opacity}) do
~s(<stop offset="#{offset}%" style="stop-color:#{color};stop-opacity:#{opacity}" />)
end

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)
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
Loading