Skip to content

Commit

Permalink
Linestyle type (#3193)
Browse files Browse the repository at this point in the history
* define custom Linestyle, add conversion

* small cleanups

* fix bug + export Linestyle

* Update conversions.jl

---------

Co-authored-by: Datseris <datseris.george@gmail.com>
  • Loading branch information
SimonDanisch and Datseris authored Aug 30, 2023
1 parent 12f01a1 commit fe17d4d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 35 deletions.
1 change: 1 addition & 0 deletions src/Makie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ import MakieCore: convert_arguments, convert_attribute, default_theme, conversio
export @L_str, @colorant_str
export ConversionTrait, NoConversion, PointBased, SurfaceLike, ContinuousSurface, DiscreteSurface, VolumeLike
export Pixel, px, Unit, plotkey, attributes, used_attributes
export Linestyle

const RealVector{T} = AbstractVector{T} where T <: Number
const RGBAf = RGBA{Float32}
Expand Down
97 changes: 62 additions & 35 deletions src/conversions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -868,38 +868,65 @@ convert_attribute(c::Number, ::key"strokewidth") = Float32(c)
convert_attribute(c, ::key"glowcolor") = to_color(c)
convert_attribute(c, ::key"strokecolor") = to_color(c)

convert_attribute(x::Nothing, ::key"linestyle") = x
####
## Line style conversions
####

# `AbstractVector{<:AbstractFloat}` for denoting sequences of fill/nofill. e.g.
#
# [0.5, 0.8, 1.2] will result in 0.5 filled, 0.3 unfilled, 0.4 filled. 1.0 unit is one linewidth!
convert_attribute(A::AbstractVector, ::key"linestyle") = [float(x - A[1]) for x in A]
convert_attribute(style, ::key"linestyle") = to_linestyle(style)
to_linestyle(::Nothing) = nothing
# add deprecation for old conversion
function convert_attribute(style::AbstractVector, ::key"linestyle")
@warn "Using a `Vector{<:Real}` as a linestyle attribute is deprecated. Wrap it in a `Linestyle`."
return to_linestyle(Linestyle(style))
end

"""
Linestyle(value::Vector{<:Real})
A type that can be used as value for the `linestyle` keyword argument
of plotting functions to arbitrarily customize the linestyle.
The `value` is a vector of positions where the line flips from being drawn or not
and vice versa. The values of `value` are in units of linewidth.
For example, with `value = [0.0, 4.0, 6.0, 9.5]`
you start drawing at 0, stop at 4 linewidths, start again at 6, stop at 9.5,
then repeat with 0 and 9.5 being treated as the same position.
"""
struct Linestyle
value::Vector{Float32}
end

to_linestyle(style::Linestyle) = Float32[x - style.value[1] for x in style.value]

# TODO only use NTuple{2, <: Real} and not any other container
const GapType = Union{Real, Symbol, Tuple, AbstractVector}

# A `Symbol` equal to `:dash`, `:dot`, `:dashdot`, `:dashdotdot`
convert_attribute(ls::Union{Symbol,AbstractString}, ::key"linestyle") = line_pattern(ls, :normal)
to_linestyle(ls::Union{Symbol, AbstractString}) = line_pattern(ls, :normal)

function convert_attribute(ls::Tuple{<:Union{Symbol,AbstractString},<:Any}, ::key"linestyle")
line_pattern(ls[1], ls[2])
function to_linestyle(ls::Tuple{<:Union{Symbol, AbstractString}, <: GapType})
return line_pattern(ls[1], ls[2])
end

function line_pattern(linestyle, gaps)
function line_pattern(linestyle::Symbol, gaps::GapType)
pattern = line_diff_pattern(linestyle, gaps)
isnothing(pattern) ? pattern : float.([0.0; cumsum(pattern)])
return isnothing(pattern) ? pattern : Float32[0.0; cumsum(pattern)]
end

"The linestyle patterns are inspired by the LaTeX package tikZ as seen here https://tex.stackexchange.com/questions/45275/tikz-get-values-for-predefined-dash-patterns."

function line_diff_pattern(ls::Symbol, gaps = :normal)
function line_diff_pattern(ls::Symbol, gaps::GapType = :normal)
if ls === :solid
nothing
return nothing
elseif ls === :dash
line_diff_pattern("-", gaps)
return line_diff_pattern("-", gaps)
elseif ls === :dot
line_diff_pattern(".", gaps)
return line_diff_pattern(".", gaps)
elseif ls === :dashdot
line_diff_pattern("-.", gaps)
return line_diff_pattern("-.", gaps)
elseif ls === :dashdotdot
line_diff_pattern("-..", gaps)
return line_diff_pattern("-..", gaps)
else
error(
"""
Expand All @@ -912,7 +939,7 @@ function line_diff_pattern(ls::Symbol, gaps = :normal)
end
end

function line_diff_pattern(ls_str::AbstractString, gaps = :normal)
function line_diff_pattern(ls_str::AbstractString, gaps::GapType = :normal)
dot = 1
dash = 3
check_line_pattern(ls_str)
Expand Down Expand Up @@ -947,24 +974,24 @@ function check_line_pattern(ls_str)
nothing
end

function convert_gaps(gaps)
error_msg = "You provided the gaps modifier $gaps when specifying the linestyle. The modifier must be `∈ ([:normal, :dense, :loose])`, a real number or a collection of two real numbers."
if gaps isa Symbol
gaps in [:normal, :dense, :loose] || throw(ArgumentError(error_msg))
dot_gaps = (normal = 2, dense = 1, loose = 4)
dash_gaps = (normal = 3, dense = 2, loose = 6)

dot_gap = getproperty(dot_gaps, gaps)
dash_gap = getproperty(dash_gaps, gaps)
elseif gaps isa Real
dot_gap = gaps
dash_gap = gaps
elseif length(gaps) == 2 && eltype(gaps) <: Real
dot_gap, dash_gap = gaps
else
throw(ArgumentError(error_msg))
end
(dot_gap = dot_gap, dash_gap = dash_gap)
function convert_gaps(gaps::GapType)
error_msg = "You provided the gaps modifier $gaps when specifying the linestyle. The modifier must be one of the symbols `:normal`, `:dense` or `:loose`, a real number or a tuple of two real numbers."
if gaps isa Symbol
gaps in [:normal, :dense, :loose] || throw(ArgumentError(error_msg))
dot_gaps = (normal = 2, dense = 1, loose = 4)
dash_gaps = (normal = 3, dense = 2, loose = 6)

dot_gap = getproperty(dot_gaps, gaps)
dash_gap = getproperty(dash_gaps, gaps)
elseif gaps isa Real
dot_gap = gaps
dash_gap = gaps
elseif length(gaps) == 2 && eltype(gaps) <: Real
dot_gap, dash_gap = gaps
else
throw(ArgumentError(error_msg))
end
return (dot_gap = dot_gap, dash_gap = dash_gap)
end

convert_attribute(c::Tuple{<: Number, <: Number}, ::key"position") = Point2f(c[1], c[2])
Expand Down

0 comments on commit fe17d4d

Please sign in to comment.