<commit_before>abstract AbstractTrace
abstract AbstractLayout

type GenericTrace{T<:Associative{Symbol,Any}} <: AbstractTrace
    fields::T
end

function GenericTrace(kind::Union{AbstractString,Symbol},
                      fields=Dict{Symbol,Any}(); kwargs...)
    # use setindex! methods below to handle `_` substitution
    fields[:type] = kind
    gt = GenericTrace(fields)
    map(x->setindex!(gt, x[2], x[1]), kwargs)
    gt
end

const _layout_defaults = Dict{Symbol,Any}(:margin => Dict(:l=>50, :r=>50, :t=>60, :b=>50))

type Layout{T<:Associative{Symbol,Any}} <: AbstractLayout
    fields::T

    function Layout(fields; kwargs...)
        l = new(merge(_layout_defaults, fields))
        map(x->setindex!(l, x[2], x[1]), kwargs)
        l
    end
end

Layout{T<:Associative{Symbol,Any}}(fields::T=Dict{Symbol,Any}(); kwargs...) =
    Layout{T}(fields; kwargs...)

kind(gt::GenericTrace) = get(gt, :type, "scatter")
kind(l::Layout) = "layout"

# -------------------------------------------- #
# Specific types of trace or layout attributes #
# -------------------------------------------- #
abstract AbstractPlotlyAttribute

type PlotlyAttribute{T<:Associative{Symbol,Any}} <: AbstractPlotlyAttribute
    fields::T
end

function attr(fields=Dict{Symbol,Any}(); kwargs...)
    # use setindex! methods below to handle `_` substitution
    s = PlotlyAttribute(fields)
    for (k, v) in kwargs
        s[k] = v
    end
    s
end

abstract AbstractLayoutAttribute <: AbstractPlotlyAttribute
abstract AbstractShape <: AbstractLayoutAttribute

kind(::AbstractPlotlyAttribute) = "PlotlyAttribute"

# TODO: maybe loosen some day
typealias _Scalar Union{Base.Dates.Date,Number,AbstractString,Symbol}

# ------ #
# Shapes #
# ------ #

type Shape <: AbstractLayoutAttribute
    fields::Associative{Symbol}
end

function Shape(kind::AbstractString, fields=Dict{Symbol,Any}(); kwargs...)
    # use setindex! methods below to handle `_` substitution
    fields[:type] = kind
    s = Shape(fields)
    map(x->setindex!(s, x[2], x[1]), kwargs)
    s
end

# helper method needed below
_rep(x, n) = take(cycle(x), n)

# line, circle, and rect share same x0, x1, y0, y1 args. Define methods for
# them here
for t in [:line, :circle, :rect]
    str_t = string(t)
    @eval $t(d::Associative=Dict{Symbol,Any}(), ;kwargs...) =
        Shape($str_t, d; kwargs...)
    eval(Expr(:export, t))

    @eval function $(t)(x0::_Scalar, x1::_Scalar, y0::_Scalar, y1::_Scalar,
                        fields::Associative=Dict{Symbol,Any}(); kwargs...)
        $(t)(fields; x0=x0, x1=x1, y0=y0, y1=y1, kwargs...)
    end

    @eval function $(t)(x0::Union{AbstractVector,_Scalar},
                        x1::Union{AbstractVector,_Scalar},
                        y0::Union{AbstractVector,_Scalar},
                        y1::Union{AbstractVector,_Scalar},
                        fields::Associative=Dict{Symbol,Any}(); kwargs...)
        n = reduce(max, map(length, (x0, x1, y0, y1)))
        f(_x0, _x1, _y0, _y1) = $(t)(_x0, _x1, _y0, _y1, copy(fields); kwargs...)
        map(f, _rep(x0, n), _rep(x1, n), _rep(y0, n), _rep(y1, n))
    end
end

@doc "Draw a line through the points (x0, y0) and (x1, y2)" line

@doc """
Draw a circle from ((`x0`+`x1`)/2, (`y0`+`y1`)/2)) with radius
 (|(`x0`+`x1`)/2 - `x0`|, |(`y0`+`y1`)/2 -`y0`)|) """ circle

@doc """
Draw a rectangle linking (`x0`,`y0`), (`x1`,`y0`),
(`x1`,`y1`), (`x0`,`y1`), (`x0`,`y0`)""" rect


"Draw an arbitrary svg path"
path(p::AbstractString; kwargs...) = Shape("path"; path=p, kwargs...)

export path

# derived shapes

vline(x, ymin, ymax, fields::Associative=Dict{Symbol,Any}(); kwargs...) =
    line(x, x, ymin, ymax, fields; kwargs...)

"""
`vline(x, fields::Associative=Dict{Symbol,Any}(); kwargs...)`

Draw vertical lines at each point in `x` that span the height of the plot
"""
vline(x, fields::Associative=Dict{Symbol,Any}(); kwargs...) =
    vline(x, 0, 1, fields; xref="x", yref="paper")

hline(y, xmin, xmax, fields::Associative=Dict{Symbol,Any}(); kwargs...) =
    line(xmin, xmax, y, y, fields; kwargs...)

"""
`hline(y, fields::Associative=Dict{Symbol,Any}(); kwargs...)`

Draw horizontal lines at each point in `y` that span the width of the plot
"""
hline(y, fields::Associative=Dict{Symbol,Any}(); kwargs...) =
    hline(y, 0, 1, fields; xref="paper", yref="y")

# ---------------------------------------- #
# Implementation of getindex and setindex! #
# ---------------------------------------- #

typealias HasFields Union{GenericTrace,Layout,Shape,PlotlyAttribute}
typealias _LikeAssociative Union{PlotlyAttribute,Associative}

#= NOTE: Generate this list with the following code
using JSON, PlotlyJS
d = JSON.parsefile(Pkg.dir("PlotlyJS", "deps", "plotschema.json"))
d = PlotlyJS._symbol_dict(d)

nms = Set{Symbol}()
function add_to_names!(d::Associative)
    map(add_to_names!, keys(d))
    map(add_to_names!, values(d))
    nothing
end
add_to_names!(s::Symbol) = push!(nms, s)
add_to_names!(x) = nothing

add_to_names!(d[:schema][:layout][:layoutAttributes])
for (_, v) in d[:schema][:traces]
    add_to_names!(v)
end<commit_msg>BUG: propogate kwargs in hline(y, ...; ...) method<commit_after>abstract AbstractTrace
abstract AbstractLayout

type GenericTrace{T<:Associative{Symbol,Any}} <: AbstractTrace
    fields::T
end

function GenericTrace(kind::Union{AbstractString,Symbol},
                      fields=Dict{Symbol,Any}(); kwargs...)
    # use setindex! methods below to handle `_` substitution
    fields[:type] = kind
    gt = GenericTrace(fields)
    map(x->setindex!(gt, x[2], x[1]), kwargs)
    gt
end

const _layout_defaults = Dict{Symbol,Any}(:margin => Dict(:l=>50, :r=>50, :t=>60, :b=>50))

type Layout{T<:Associative{Symbol,Any}} <: AbstractLayout
    fields::T

    function Layout(fields; kwargs...)
        l = new(merge(_layout_defaults, fields))
        map(x->setindex!(l, x[2], x[1]), kwargs)
        l
    end
end

Layout{T<:Associative{Symbol,Any}}(fields::T=Dict{Symbol,Any}(); kwargs...) =
    Layout{T}(fields; kwargs...)

kind(gt::GenericTrace) = get(gt, :type, "scatter")
kind(l::Layout) = "layout"

# -------------------------------------------- #
# Specific types of trace or layout attributes #
# -------------------------------------------- #
abstract AbstractPlotlyAttribute

type PlotlyAttribute{T<:Associative{Symbol,Any}} <: AbstractPlotlyAttribute
    fields::T
end

function attr(fields=Dict{Symbol,Any}(); kwargs...)
    # use setindex! methods below to handle `_` substitution
    s = PlotlyAttribute(fields)
    for (k, v) in kwargs
        s[k] = v
    end
    s
end

abstract AbstractLayoutAttribute <: AbstractPlotlyAttribute
abstract AbstractShape <: AbstractLayoutAttribute

kind(::AbstractPlotlyAttribute) = "PlotlyAttribute"

# TODO: maybe loosen some day
typealias _Scalar Union{Base.Dates.Date,Number,AbstractString,Symbol}

# ------ #
# Shapes #
# ------ #

type Shape <: AbstractLayoutAttribute
    fields::Associative{Symbol}
end

function Shape(kind::AbstractString, fields=Dict{Symbol,Any}(); kwargs...)
    # use setindex! methods below to handle `_` substitution
    fields[:type] = kind
    s = Shape(fields)
    map(x->setindex!(s, x[2], x[1]), kwargs)
    s
end

# helper method needed below
_rep(x, n) = take(cycle(x), n)

# line, circle, and rect share same x0, x1, y0, y1 args. Define methods for
# them here
for t in [:line, :circle, :rect]
    str_t = string(t)
    @eval $t(d::Associative=Dict{Symbol,Any}(), ;kwargs...) =
        Shape($str_t, d; kwargs...)
    eval(Expr(:export, t))

    @eval function $(t)(x0::_Scalar, x1::_Scalar, y0::_Scalar, y1::_Scalar,
                        fields::Associative=Dict{Symbol,Any}(); kwargs...)
        $(t)(fields; x0=x0, x1=x1, y0=y0, y1=y1, kwargs...)
    end

    @eval function $(t)(x0::Union{AbstractVector,_Scalar},
                        x1::Union{AbstractVector,_Scalar},
                        y0::Union{AbstractVector,_Scalar},
                        y1::Union{AbstractVector,_Scalar},
                        fields::Associative=Dict{Symbol,Any}(); kwargs...)
        n = reduce(max, map(length, (x0, x1, y0, y1)))
        f(_x0, _x1, _y0, _y1) = $(t)(_x0, _x1, _y0, _y1, copy(fields); kwargs...)
        map(f, _rep(x0, n), _rep(x1, n), _rep(y0, n), _rep(y1, n))
    end
end

@doc "Draw a line through the points (x0, y0) and (x1, y2)" line

@doc """
Draw a circle from ((`x0`+`x1`)/2, (`y0`+`y1`)/2)) with radius
 (|(`x0`+`x1`)/2 - `x0`|, |(`y0`+`y1`)/2 -`y0`)|) """ circle

@doc """
Draw a rectangle linking (`x0`,`y0`), (`x1`,`y0`),
(`x1`,`y1`), (`x0`,`y1`), (`x0`,`y0`)""" rect


"Draw an arbitrary svg path"
path(p::AbstractString; kwargs...) = Shape("path"; path=p, kwargs...)

export path

# derived shapes

vline(x, ymin, ymax, fields::Associative=Dict{Symbol,Any}(); kwargs...) =
    line(x, x, ymin, ymax, fields; kwargs...)

"""
`vline(x, fields::Associative=Dict{Symbol,Any}(); kwargs...)`

Draw vertical lines at each point in `x` that span the height of the plot
"""
vline(x, fields::Associative=Dict{Symbol,Any}(); kwargs...) =
    vline(x, 0, 1, fields; xref="x", yref="paper")

hline(y, xmin, xmax, fields::Associative=Dict{Symbol,Any}(); kwargs...) =
    line(xmin, xmax, y, y, fields; kwargs...)

"""
`hline(y, fields::Associative=Dict{Symbol,Any}(); kwargs...)`

Draw horizontal lines at each point in `y` that span the width of the plot
"""
hline(y, fields::Associative=Dict{Symbol,Any}(); kwargs...) =
    hline(y, 0, 1, fields; xref="paper", yref="y", kwargs...)

# ---------------------------------------- #
# Implementation of getindex and setindex! #
# ---------------------------------------- #

typealias HasFields Union{GenericTrace,Layout,Shape,PlotlyAttribute}
typealias _LikeAssociative Union{PlotlyAttribute,Associative}

#= NOTE: Generate this list with the following code
using JSON, PlotlyJS
d = JSON.parsefile(Pkg.dir("PlotlyJS", "deps", "plotschema.json"))
d = PlotlyJS._symbol_dict(d)

nms = Set{Symbol}()
function add_to_names!(d::Associative)
    map(add_to_names!, keys(d))
    map(add_to_names!, values(d))
    nothing
end
add_to_names!(s::Symbol) = push!(nms, s)
add_to_names!(x) = nothing

add_to_names!(d[:schema][:layout][:layoutAttributes])
for (_, v) in d[:schema][:traces]
    add_to_names!(v)
end
{'fraction_non_alphanumeric': 0.20841468176493558, 'fraction_numerical': 0.016009371339320577, 'mean_word_length': 3.4083476764199654, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2810863', 'n_tokens_mistral': 3559, 'n_tokens_neox': 3511, 'n_words': 829}