From 4d99b37defea9305ca21f34ee56d0822ccb5d05a Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 7 Jul 2016 14:40:09 -0400 Subject: [PATCH] working on colors overhaul; fix for rationals in plotly; closes #382 --- src/Plots.jl | 24 ++-- src/args.jl | 94 +++++++++++++- src/backends/glvisualize.jl | 4 +- src/backends/gr.jl | 62 +++++----- src/backends/plotly.jl | 51 ++++---- src/backends/pyplot.jl | 59 +++++---- src/{ => deprecated}/color_gradients.jl | 0 src/{ => deprecated}/colors.jl | 0 src/{ => deprecated}/contours.jl | 0 src/{ => deprecated}/series_args.jl | 0 src/recipes.jl | 4 +- src/{series_new.jl => series.jl} | 157 ++++++++++++++---------- 12 files changed, 288 insertions(+), 167 deletions(-) rename src/{ => deprecated}/color_gradients.jl (100%) rename src/{ => deprecated}/colors.jl (100%) rename src/{ => deprecated}/contours.jl (100%) rename src/{ => deprecated}/series_args.jl (100%) rename src/{series_new.jl => series.jl} (73%) diff --git a/src/Plots.jl b/src/Plots.jl index acda8aab..4ccea9af 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -10,7 +10,7 @@ using Reexport using FixedSizeArrays @reexport using RecipesBase using Base.Meta -# using PlotUtils +using PlotUtils export AbstractPlot, @@ -81,15 +81,15 @@ export arrow, Segments, - colorscheme, - ColorScheme, - ColorGradient, - ColorVector, - ColorWrapper, - ColorFunction, - ColorZFunction, - getColor, - getColorZ, + # colorscheme, + # ColorScheme, + # ColorGradient, + # ColorVector, + # ColorWrapper, + # ColorFunction, + # ColorZFunction, + # getColor, + # getColorZ, debugplots, @@ -132,15 +132,13 @@ export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h include("types.jl") include("utils.jl") -include("colors.jl") include("components.jl") include("axes.jl") include("backends.jl") include("args.jl") include("themes.jl") include("plot.jl") -include("series_args.jl") -include("series_new.jl") +include("series.jl") include("layouts.jl") include("subplots.jl") include("recipes.jl") diff --git a/src/args.jl b/src/args.jl index 503a2a5b..fa0d939c 100644 --- a/src/args.jl +++ b/src/args.jl @@ -498,7 +498,8 @@ function handleColors!(d::KW, arg, csym::Symbol) if arg == :auto d[csym] = :auto else - c = colorscheme(arg) + # c = colorscheme(arg) + c = plot_color(arg, nothing) d[csym] = c end return true @@ -943,13 +944,13 @@ function _update_plot_args(plt::Plot, d_in::KW) end # handle colors - bg = convertColor(plt.attr[:background_color]) + bg = plot_color(plt.attr[:background_color]) fg = plt.attr[:foreground_color] if fg == :auto fg = isdark(bg) ? colorant"white" : colorant"black" end plt.attr[:background_color] = bg - plt.attr[:foreground_color] = convertColor(fg) + plt.attr[:foreground_color] = plot_color(fg) # color_or_match!(plt.attr, :background_color_outside, bg) color_or_nothing!(plt.attr, :background_color_outside) end @@ -977,7 +978,7 @@ function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW, subplot_index::I # background colors # bg = color_or_match!(sp.attr, :background_color_subplot, plt.attr[:background_color]) color_or_nothing!(sp.attr, :background_color_subplot) - bg = convertColor(sp[:background_color_subplot]) + bg = plot_color(sp[:background_color_subplot]) sp.attr[:color_palette] = get_color_palette(sp.attr[:color_palette], bg, 30) color_or_nothing!(sp.attr, :background_color_legend) color_or_nothing!(sp.attr, :background_color_inside) @@ -1044,7 +1045,92 @@ function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW, subplot_index::I end end +# ----------------------------------------------------------------------------- function has_black_border_for_default(st::Symbol) like_histogram(st) || st in (:hexbin, :bar) end + + +# converts a symbol or string into a colorant (Colors.RGB), and assigns a color automatically +function getSeriesRGBColor(c, α, sp::Subplot, n::Int) + + if c == :auto + c = autopick(sp[:color_palette], n) + end + + # # c should now be a subtype of AbstractPlotColor + # colorscheme(c) + plot_color(c, α) +end + + +function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int) + pkg = plt.backend + globalIndex = d[:series_plotindex] + + # add default values to our dictionary, being careful not to delete what we just added! + for (k,v) in _series_defaults + slice_arg!(d, d, k, v, commandIndex, remove_pair = false) + end + + # this is how many series belong to this subplot + plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list) + if get(d, :primary, true) + plotIndex += 1 + end + + aliasesAndAutopick(d, :linestyle, _styleAliases, supported_styles(pkg), plotIndex) + aliasesAndAutopick(d, :markershape, _markerAliases, supported_markers(pkg), plotIndex) + + # update alphas + for asym in (:linealpha, :markeralpha, :fillalpha) + if d[asym] == nothing + d[asym] = d[:seriesalpha] + end + end + if d[:markerstrokealpha] == nothing + d[:markerstrokealpha] = d[:markeralpha] + end + + # update series color + d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], d[:seriesalpha], sp, plotIndex) + + # update other colors + for s in (:line, :marker, :fill) + csym, asym = Symbol(s,:color), Symbol(s,:alpha) + d[csym] = if d[csym] == :match + if has_black_border_for_default(d[:seriestype]) && csym == :line + plot_color(:black, d[asym]) + else + d[:seriescolor] + end + else + getSeriesRGBColor(d[csym], d[asym], sp, plotIndex) + end + end + + # update markerstrokecolor + d[:markerstrokecolor] = if d[:markerstrokecolor] == :match + sp[:foreground_color_subplot] + else + getSeriesRGBColor(d[:markerstrokecolor], d[:markerstrokealpha], sp, plotIndex) + end + + # scatter plots don't have a line, but must have a shape + if d[:seriestype] in (:scatter, :scatter3d) + d[:linewidth] = 0 + if d[:markershape] == :none + d[:markershape] = :circle + end + end + + # set label + label = d[:label] + label = (label == "AUTO" ? "y$globalIndex" : label) + d[:label] = label + + _replace_linewidth(d) + d +end + diff --git a/src/backends/glvisualize.jl b/src/backends/glvisualize.jl index 94bb358b..55749ec4 100644 --- a/src/backends/glvisualize.jl +++ b/src/backends/glvisualize.jl @@ -44,8 +44,8 @@ function _initialize_backend(::GLVisualizeBackend; kw...) import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0 export GLVisualize - # TODO: remove this when PlotUtils is registered - import PlotUtils + # # TODO: remove this when PlotUtils is registered + # import PlotUtils end end diff --git a/src/backends/gr.jl b/src/backends/gr.jl index f1210577..e69df3d2 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -107,17 +107,15 @@ const gr_font_family = Dict( # -------------------------------------------------------------------------------------- -function gr_getcolorind(v, a =nothing) - c = getColor(v) - idx = convert(Int, GR.inqcolorfromrgb(c.r, c.g, c.b)) - GR.settransparency(float(a==nothing ? alpha(c) : a)) - idx +function gr_getcolorind(c) + GR.settransparency(float(alpha(c))) + convert(Int, GR.inqcolorfromrgb(red(c), green(c), blue(c))) end -gr_set_linecolor(c, a=nothing) = GR.setlinecolorind(gr_getcolorind(c, a)) -gr_set_fillcolor(c, a=nothing) = GR.setfillcolorind(gr_getcolorind(c, a)) -gr_set_markercolor(c, a=nothing) = GR.setmarkercolorind(gr_getcolorind(c, a)) -gr_set_textcolor(c, a=nothing) = GR.settextcolorind(gr_getcolorind(c, a)) +gr_set_linecolor(c) = GR.setlinecolorind(gr_getcolorind(c)) +gr_set_fillcolor(c) = GR.setfillcolorind(gr_getcolorind(c)) +gr_set_markercolor(c) = GR.setmarkercolorind(gr_getcolorind(c)) +gr_set_textcolor(c) = GR.settextcolorind(gr_getcolorind(c)) # -------------------------------------------------------------------------------------- @@ -282,12 +280,14 @@ function gr_draw_markers(d::KW, x, y, msize, mz) cfuncind = isa(shape, Shape) ? GR.setfillcolorind : GR.setmarkercolorind # draw a filled in shape, slightly bigger, to estimate a stroke - cfunc(d[:markerstrokecolor], d[:markerstrokealpha]) - gr_draw_marker(x[i], y[i], msi*1.2, shape, ) + if d[:markerstrokewidth] > 0 + cfunc(cycle(d[:markerstrokecolor], i)) #, d[:markerstrokealpha]) + gr_draw_marker(x[i], y[i], msi + d[:markerstrokewidth], shape) + end # draw the shape if mz == nothing - cfunc(d[:markercolor], d[:markeralpha]) + cfunc(cycle(d[:markercolor], i)) #, d[:markeralpha]) else # pick a color from the pre-loaded gradient ci = round(Int, 1000 + cycle(mz, i) * 255) @@ -311,16 +311,16 @@ end # --------------------------------------------------------- -function gr_set_line(w, style, c, a) +function gr_set_line(w, style, c) #, a) GR.setlinetype(gr_linetype[style]) GR.setlinewidth(w) - gr_set_linecolor(c, a) + gr_set_linecolor(c) #, a) end -function gr_set_fill(c, a) - gr_set_fillcolor(c, a) +function gr_set_fill(c) #, a) + gr_set_fillcolor(c) #, a) GR.setfillintstyle(GR.INTSTYLE_SOLID) end @@ -404,12 +404,12 @@ gr_view_ydiff() = viewport_plotarea[4] - viewport_plotarea[3] # -------------------------------------------------------------------------------------- -function gr_set_gradient(c, a) - grad = isa(c, ColorGradient) ? c : default_gradient() - grad = ColorGradient(grad, alpha=a) +function gr_set_gradient(c) #, a) + grad = isa(c, ColorGradient) ? c : cgrad() + # grad = ColorGradient(grad, alpha=a) for (i,z) in enumerate(linspace(0, 1, 256)) - c = getColorZ(grad, z) - GR.setcolorrep(999+i, red(c), green(c), blue(c)) + c = grad[z] + GR.setcolorrep(999+i, red(c), green(c), blue(c), alpha(c)) end grad end @@ -464,7 +464,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) viewport_plotarea[:] = gr_viewport_from_bbox(plotarea(sp), w, h, viewport_canvas) # fill in the plot area background - bg = getColor(sp[:background_color_inside]) + bg = plot_color(sp[:background_color_inside]) gr_fill_viewport(viewport_plotarea, bg) # reduced from before... set some flags based on the series in this subplot @@ -618,7 +618,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # update the current stored gradient if st in (:contour, :surface, :wireframe, :heatmap) - gr_set_gradient(d[:fillcolor], d[:fillalpha]) + gr_set_gradient(d[:fillcolor]) #, d[:fillalpha]) elseif d[:marker_z] != nothing d[:markercolor] = gr_set_gradient(d[:markercolor], d[:markeralpha]) end @@ -653,7 +653,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # do area fill if frng != nothing - gr_set_fillcolor(d[:fillcolor], d[:fillalpha]) + gr_set_fillcolor(d[:fillcolor]) #, d[:fillalpha]) GR.setfillintstyle(GR.INTSTYLE_SOLID) frng = isa(frng, Number) ? Float64[frng] : frng nx, ny, nf = length(x), length(y), length(frng) @@ -669,7 +669,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # draw the line(s) if st == :path - gr_set_line(d[:linewidth], d[:linestyle], d[:linecolor], d[:linealpha]) + gr_set_line(d[:linewidth], d[:linestyle], d[:linecolor]) #, d[:linealpha]) gr_polyline(x, y) end end @@ -723,7 +723,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # draw path if st == :path3d if length(x) > 1 - gr_set_line(d[:linewidth], d[:linestyle], d[:linecolor], d[:linealpha]) + gr_set_line(d[:linewidth], d[:linestyle], d[:linecolor]) #, d[:linealpha]) GR.polyline3d(x, y, z) end end @@ -784,11 +784,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) elseif st == :shape # draw the interior - gr_set_fill(d[:fillcolor], d[:fillalpha]) + gr_set_fill(d[:fillcolor]) #, d[:fillalpha]) gr_polyline(d[:x], d[:y], GR.fillarea) # draw the shapes - gr_set_line(d[:linewidth], :solid, d[:linecolor], d[:linealpha]) + gr_set_line(d[:linewidth], :solid, d[:linecolor]) #, d[:linealpha]) gr_polyline(d[:x], d[:y]) @@ -847,11 +847,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) should_add_to_legend(series) || continue d = series.d st = d[:seriestype] - gr_set_line(d[:linewidth], d[:linestyle], d[:linecolor], d[:linealpha]) + gr_set_line(d[:linewidth], d[:linestyle], d[:linecolor]) #, d[:linealpha]) if st == :path GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos]) elseif st == :shape - gr_set_fill(d[:fillcolor], d[:fillalpha]) + gr_set_fill(d[:fillcolor]) #, d[:fillalpha]) l, r = xpos-0.07, xpos-0.01 b, t = ypos-0.4dy, ypos+0.4dy x = [l, r, r, l, l] @@ -865,7 +865,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # if shape != :none #st == :scatter || d[:markershape] != :none # msize = 10 # for xoff in [0.06,0.02] - # gr_set_markercolor(d[:markerstrokecolor], d[:markerstrokealpha]) + # gr_set_markercolor(d[:markerstrokecolor]) #, d[:markerstrokealpha]) # gr_draw_marker(xpos-xoff, ypos, msize*1.1, shape) # gr_set_markercolor(d[:markercolor], d[:markeralpha]) # gr_draw_marker(xpos-xoff, ypos, msize, shape) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index cf2ac4c7..0fad9fcb 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -88,7 +88,7 @@ function plotly_font(font::Font, color = font.color) KW( :family => font.family, :size => round(Int, font.pointsize*1.4), - :color => webcolor(color), + :color => rgba_string(color), ) end @@ -126,7 +126,7 @@ end # # :ay => -40, # :ax => 10xdiff / dist, # :ay => -10ydiff / dist, -# :arrowcolor => webcolor(d[:linecolor], d[:linealpha]), +# :arrowcolor => rgba_string(d[:linecolor]), # :xref => "x", # :yref => "y", # :arrowsize => 10a.headwidth, @@ -175,8 +175,8 @@ function plotly_axis(axis::Axis, sp::Subplot) ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide]) ax[:type] = plotly_scale(axis[:scale]) ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text]) - ax[:tickcolor] = webcolor(axis[:foreground_color_border]) - ax[:linecolor] = webcolor(axis[:foreground_color_border]) + ax[:tickcolor] = rgba_string(axis[:foreground_color_border]) + ax[:linecolor] = rgba_string(axis[:foreground_color_border]) # lims lims = axis[:lims] @@ -214,7 +214,7 @@ function plotly_layout(plt::Plot) w, h = plt[:size] d_out[:width], d_out[:height] = w, h - d_out[:paper_bgcolor] = webcolor(plt[:background_color_outside]) + d_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside]) d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>20) d_out[:annotations] = KW[] @@ -239,7 +239,7 @@ function plotly_layout(plt::Plot) push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], titlefont))) end - d_out[:plot_bgcolor] = webcolor(sp[:background_color_inside]) + d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside]) # TODO: x/y axis tick values/labels @@ -259,8 +259,8 @@ function plotly_layout(plt::Plot) d_out[:showlegend] = sp[:legend] != :none if sp[:legend] != :none d_out[:legend] = KW( - :bgcolor => webcolor(sp[:background_color_legend]), - :bordercolor => webcolor(sp[:foreground_color_legend]), + :bgcolor => rgba_string(sp[:background_color_legend]), + :bordercolor => rgba_string(sp[:foreground_color_legend]), :font => plotly_font(sp[:legendfont], sp[:foreground_color_legend]), ) end @@ -299,7 +299,7 @@ end function plotly_colorscale(grad::ColorGradient, alpha = nothing) - [[grad.values[i], webcolor(grad.colors[i], alpha)] for i in 1:length(grad.colors)] + [[grad.values[i], rgba_string(grad.colors[i], alpha)] for i in 1:length(grad.colors)] end plotly_colorscale(c, alpha = nothing) = plotly_colorscale(default_gradient(), alpha) @@ -330,6 +330,9 @@ function plotly_close_shapes(x, y) nanvcat(xs), nanvcat(ys) end +plotly_data(v) = collect(v) +plotly_data{R<:Rational}(v::AbstractArray{R}) = float(v) + # get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict) function plotly_series(plt::Plot, series::Series) d = series.d @@ -342,7 +345,7 @@ function plotly_series(plt::Plot, series::Series) d_out[:yaxis] = "y$spidx" d_out[:showlegend] = should_add_to_legend(series) - x, y = collect(d[:x]), collect(d[:y]) + x, y = plotly_data(d[:x]), plotly_data(d[:y]) d_out[:name] = d[:label] st = d[:seriestype] isscatter = st in (:scatter, :scatter3d, :scattergl) @@ -360,7 +363,7 @@ function plotly_series(plt::Plot, series::Series) end if d[:fillrange] == true || d[:fillrange] == 0 d_out[:fill] = "tozeroy" - d_out[:fillcolor] = webcolor(d[:fillcolor], d[:fillalpha]) + d_out[:fillcolor] = rgba_string(d[:fillcolor]) elseif !(d[:fillrange] in (false, nothing)) warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(d[:fillrange])") end @@ -374,10 +377,10 @@ function plotly_series(plt::Plot, series::Series) # @show map(length, (x,y,d_out[:x],d_out[:y])) # @show d_out[:x] d_out[:y] d_out[:fill] = "tozeroy" - d_out[:fillcolor] = webcolor(d[:fillcolor], d[:fillalpha]) + d_out[:fillcolor] = rgba_string(d[:fillcolor]) if d[:markerstrokewidth] > 0 d_out[:line] = KW( - :color => webcolor(d[:linecolor], d[:linealpha]), + :color => rgba_string(d[:linecolor]), :width => d[:linewidth], :dash => string(d[:linestyle]), ) @@ -400,7 +403,7 @@ function plotly_series(plt::Plot, series::Series) # end # d_out[:nbinsx] = xbins # d_out[:nbinsy] = ybins - # d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) + # d_out[:colorscale] = plotly_colorscale(d[:fillcolor]) # elseif st in (:histogram, :density) # d_out[:type] = "histogram" @@ -414,7 +417,7 @@ function plotly_series(plt::Plot, series::Series) elseif st == :heatmap d_out[:type] = "heatmap" d_out[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false) - d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) + d_out[:colorscale] = plotly_colorscale(d[:fillcolor]) elseif st == :contour d_out[:type] = "contour" @@ -422,12 +425,12 @@ function plotly_series(plt::Plot, series::Series) # d_out[:showscale] = d[:colorbar] != :none d_out[:ncontours] = d[:levels] d_out[:contours] = KW(:coloring => d[:fillrange] != nothing ? "fill" : "lines") - d_out[:colorscale] = plotly_colorscale(d[:linecolor], d[:linealpha]) + d_out[:colorscale] = plotly_colorscale(d[:linecolor]) elseif st in (:surface, :wireframe) d_out[:type] = "surface" d_out[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false) - d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) + d_out[:colorscale] = plotly_colorscale(d[:fillcolor]) elseif st == :pie d_out[:type] = "pie" @@ -443,7 +446,7 @@ function plotly_series(plt::Plot, series::Series) hasline ? "lines" : "none" end d_out[:x], d_out[:y] = x, y - d_out[:z] = collect(d[:z]) + d_out[:z] = plotly_data(d[:z]) else warn("Plotly: seriestype $st isn't supported.") @@ -454,11 +457,11 @@ function plotly_series(plt::Plot, series::Series) if hasmarker d_out[:marker] = KW( :symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])), - :opacity => d[:markeralpha], + # :opacity => d[:markeralpha], :size => 2 * d[:markersize], - :color => webcolor(d[:markercolor], d[:markeralpha]), + :color => rgba_string(d[:markercolor]), :line => KW( - :color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]), + :color => rgba_string(d[:markerstrokecolor]), :width => d[:markerstrokewidth], ), ) @@ -466,18 +469,18 @@ function plotly_series(plt::Plot, series::Series) # gotta hack this (for now?) since plotly can't handle rgba values inside the gradient if d[:marker_z] != nothing # d_out[:marker][:color] = d[:marker_z] - # d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor], d[:markeralpha]) + # d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor]) # d_out[:showscale] = true grad = ColorGradient(d[:markercolor], alpha=d[:markeralpha]) zmin, zmax = extrema(d[:marker_z]) - d_out[:marker][:color] = [webcolor(getColorZ(grad, (zi - zmin) / (zmax - zmin))) for zi in d[:marker_z]] + d_out[:marker][:color] = [rgba_string(getColorZ(grad, (zi - zmin) / (zmax - zmin))) for zi in d[:marker_z]] end end # add "line" if hasline d_out[:line] = KW( - :color => webcolor(d[:linecolor], d[:linealpha]), + :color => rgba_string(d[:linecolor]), :width => d[:linewidth], :shape => if st == :steppre "vh" diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 02bb55b5..42ca4229 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -78,26 +78,37 @@ end # -------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------- -# convert colorant to 4-tuple RGBA -py_color(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha)) -py_color(cvec::ColorVector, α=nothing) = map(py_color, convertColor(cvec, α).v) -py_color(grad::ColorGradient, α=nothing) = map(c -> py_color(c, α), grad.colors) -py_color(scheme::ColorScheme, α=nothing) = py_color(convertColor(getColor(scheme), α)) -py_color(vec::AVec, α=nothing) = map(c->py_color(c,α), vec) -py_color(c, α=nothing) = py_color(convertColor(c, α)) +# # convert colorant to 4-tuple RGBA +# py_color(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha)) +# py_color(cvec::ColorVector, α=nothing) = map(py_color, convertColor(cvec, α).v) +# py_color(grad::ColorGradient, α=nothing) = map(c -> py_color(c, α), grad.colors) +# py_color(scheme::ColorScheme, α=nothing) = py_color(convertColor(getColor(scheme), α)) +# py_color(vec::AVec, α=nothing) = map(c->py_color(c,α), vec) +# py_color(c, α=nothing) = py_color(convertColor(c, α)) -function py_colormap(c::ColorGradient, α=nothing) - pyvals = [(v, py_color(getColorZ(c, v), α)) for v in c.values] - pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals) +# function py_colormap(c::ColorGradient, α=nothing) +# pyvals = [(v, py_color(getColorZ(c, v), α)) for v in c.values] +# pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals) +# end + +# # convert vectors and ColorVectors to standard ColorGradients +# # TODO: move this logic to colors.jl and keep a barebones wrapper for pyplot +# py_colormap(cv::ColorVector, α=nothing) = py_colormap(ColorGradient(cv.v), α) +# py_colormap(v::AVec, α=nothing) = py_colormap(ColorGradient(v), α) + +# # anything else just gets a bluesred gradient +# py_colormap(c, α=nothing) = py_colormap(default_gradient(), α) + +py_color(c::Colorant) = (red(c), green(c), blue(c), alpha(c)) +py_color(cs::AVec) = map(py_color, cs) +py_color(grad::ColorGradient) = py_color(grad.colors) + +function py_colormap(grad::ColorGradient) + pyvals = [(z, py_color(c[z])) for z in c.values] + pycolors.LinearSegmentedColormap[:from_list]("tmp", pyvals) end +py_colormap(c) = py_colormap(cgrad()) -# convert vectors and ColorVectors to standard ColorGradients -# TODO: move this logic to colors.jl and keep a barebones wrapper for pyplot -py_colormap(cv::ColorVector, α=nothing) = py_colormap(ColorGradient(cv.v), α) -py_colormap(v::AVec, α=nothing) = py_colormap(ColorGradient(v), α) - -# anything else just gets a bluesred gradient -py_colormap(c, α=nothing) = py_colormap(default_gradient(), α) function py_shading(c, z, α=nothing) cmap = py_colormap(c, α) @@ -247,14 +258,14 @@ function py_color_fix(c, x) end end -py_linecolor(d::KW) = py_color(d[:linecolor], d[:linealpha]) -py_markercolor(d::KW) = py_color(d[:markercolor], d[:markeralpha]) -py_markerstrokecolor(d::KW) = py_color(d[:markerstrokecolor], d[:markerstrokealpha]) -py_fillcolor(d::KW) = py_color(d[:fillcolor], d[:fillalpha]) +py_linecolor(d::KW) = py_color(d[:linecolor]) #, d[:linealpha]) +py_markercolor(d::KW) = py_color(d[:markercolor]) #, d[:markeralpha]) +py_markerstrokecolor(d::KW) = py_color(d[:markerstrokecolor]) #, d[:markerstrokealpha]) +py_fillcolor(d::KW) = py_color(d[:fillcolor]) #, d[:fillalpha]) -py_linecolormap(d::KW) = py_colormap(d[:linecolor], d[:linealpha]) -py_markercolormap(d::KW) = py_colormap(d[:markercolor], d[:markeralpha]) -py_fillcolormap(d::KW) = py_colormap(d[:fillcolor], d[:fillalpha]) +py_linecolormap(d::KW) = py_colormap(d[:linecolor]) #, d[:linealpha]) +py_markercolormap(d::KW) = py_colormap(d[:markercolor]) #, d[:markeralpha]) +py_fillcolormap(d::KW) = py_colormap(d[:fillcolor]) #, d[:fillalpha]) # --------------------------------------------------------------------------- diff --git a/src/color_gradients.jl b/src/deprecated/color_gradients.jl similarity index 100% rename from src/color_gradients.jl rename to src/deprecated/color_gradients.jl diff --git a/src/colors.jl b/src/deprecated/colors.jl similarity index 100% rename from src/colors.jl rename to src/deprecated/colors.jl diff --git a/src/contours.jl b/src/deprecated/contours.jl similarity index 100% rename from src/contours.jl rename to src/deprecated/contours.jl diff --git a/src/series_args.jl b/src/deprecated/series_args.jl similarity index 100% rename from src/series_args.jl rename to src/deprecated/series_args.jl diff --git a/src/recipes.jl b/src/recipes.jl index 8379c39a..9544d916 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -382,7 +382,7 @@ end end if lz != nothing line_z := newlz - linecolor := (isa(d[:linecolor], ColorGradient) ? d[:linecolor] : default_gradient()) + linecolor := (isa(d[:linecolor], ColorGradient) ? d[:linecolor] : cgrad()) end # Plots.DD(d) () @@ -405,7 +405,6 @@ end axis = d[:subplot][isvertical(d) ? :xaxis : :yaxis] bw = d[:bar_width] hw = if bw == nothing - # 0.5mean(diff(x)) 0.5mean(diff([discrete_value!(axis, xi)[1] for xi=x])) else Float64[0.5cycle(bw,i) for i=1:length(x)] @@ -420,7 +419,6 @@ end # create the bar shapes by adding x/y segments xseg, yseg = Segments(), Segments() for i=1:ny - # ci = x[i] center = discrete_value!(axis, x[i])[1] hwi = cycle(hw,i) yi = y[i] diff --git a/src/series_new.jl b/src/series.jl similarity index 73% rename from src/series_new.jl rename to src/series.jl index b0f26ffb..aa80af1a 100644 --- a/src/series_new.jl +++ b/src/series.jl @@ -1,81 +1,106 @@ -# we are going to build recipes to do the processing and splitting of the args - -function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int) - pkg = plt.backend - globalIndex = d[:series_plotindex] +# create a new "build_series_args" which converts all inputs into xs = Any[xitems], ys = Any[yitems]. +# Special handling for: no args, xmin/xmax, parametric, dataframes +# Then once inputs have been converted, build the series args, map functions, etc. +# This should cut down on boilerplate code and allow more focused dispatch on type +# note: returns meta information... mainly for use with automatic labeling from DataFrames for now - # add default values to our dictionary, being careful not to delete what we just added! - for (k,v) in _series_defaults - slice_arg!(d, d, k, v, commandIndex, remove_pair = false) - end +typealias FuncOrFuncs @compat(Union{Function, AVec{Function}}) - # this is how many series belong to this subplot - plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list) - if get(d, :primary, true) - plotIndex += 1 - end +all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none)) - aliasesAndAutopick(d, :linestyle, _styleAliases, supported_styles(pkg), plotIndex) - aliasesAndAutopick(d, :markershape, _markerAliases, supported_markers(pkg), plotIndex) +# missing +convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing - # update color - d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], sp, plotIndex) +# fixed number of blank series +convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing - # update colors - for csym in (:linecolor, :markercolor, :fillcolor) - d[csym] = if d[csym] == :match - if has_black_border_for_default(d[:seriestype]) && csym == :linecolor - :black - else - d[:seriescolor] - end - else - getSeriesRGBColor(d[csym], sp, plotIndex) - end - end +# numeric vector +convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing - # update markerstrokecolor - c = d[:markerstrokecolor] - c = if c == :match - sp[:foreground_color_subplot] +# string vector +convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing + +function convertToAnyVector(v::AMat, d::KW) + if all3D(d) + Any[Surface(v)] else - getSeriesRGBColor(c, sp, plotIndex) - end - d[:markerstrokecolor] = c - - # update alphas - for asym in (:linealpha, :markeralpha, :fillalpha) - if d[asym] == nothing - d[asym] = d[:seriesalpha] - end - end - if d[:markerstrokealpha] == nothing - d[:markerstrokealpha] = d[:markeralpha] - end - - # scatter plots don't have a line, but must have a shape - if d[:seriestype] in (:scatter, :scatter3d) - d[:linewidth] = 0 - if d[:markershape] == :none - d[:markershape] = :circle - end - end - - # set label - label = d[:label] - label = (label == "AUTO" ? "y$globalIndex" : label) - d[:label] = label - - _replace_linewidth(d) - d + Any[v[:,i] for i in 1:size(v,2)] + end, nothing end -# ------------------------------------------------------------------- -# ------------------------------------------------------------------- +# function +convertToAnyVector(f::Function, d::KW) = Any[f], nothing -# instead of process_inputs: +# surface +convertToAnyVector(s::Surface, d::KW) = Any[s], nothing + +# # vector of OHLC +# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing + +# dates +convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing + +# list of things (maybe other vectors, functions, or something else) +function convertToAnyVector(v::AVec, d::KW) + if all(x -> typeof(x) <: Number, v) + # all real numbers wrap the whole vector as one item + Any[convert(Vector{Float64}, v)], nothing + else + # something else... treat each element as an item + vcat(Any[convertToAnyVector(vi, d)[1] for vi in v]...), nothing + # Any[vi for vi in v], nothing + end +end + +convertToAnyVector(t::Tuple, d::KW) = Any[t], nothing + + +function convertToAnyVector(args...) + error("In convertToAnyVector, could not handle the argument types: $(map(typeof, args[1:end-1]))") +end + +# -------------------------------------------------------------------- + +# TODO: can we avoid the copy here? one error that crops up is that mapping functions over the same array +# result in that array being shared. push!, etc will add too many items to that array + +compute_x(x::Void, y::Void, z) = 1:size(z,1) +compute_x(x::Void, y, z) = 1:size(y,1) +compute_x(x::Function, y, z) = map(x, y) +compute_x(x, y, z) = copy(x) + +# compute_y(x::Void, y::Function, z) = error() +compute_y(x::Void, y::Void, z) = 1:size(z,2) +compute_y(x, y::Function, z) = map(y, x) +compute_y(x, y, z) = copy(y) + +compute_z(x, y, z::Function) = map(z, x, y) +compute_z(x, y, z::AbstractMatrix) = Surface(z) +compute_z(x, y, z::Void) = nothing +compute_z(x, y, z) = copy(z) + +nobigs(v::AVec{BigFloat}) = map(Float64, v) +nobigs(v::AVec{BigInt}) = map(Int64, v) +nobigs(v) = v + +@noinline function compute_xyz(x, y, z) + x = compute_x(x,y,z) + y = compute_y(x,y,z) + z = compute_z(x,y,z) + nobigs(x), nobigs(y), nobigs(z) +end + +# not allowed +compute_xyz(x::Void, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!") +compute_xyz(x::Void, y::Void, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!") +compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!") + +# -------------------------------------------------------------------- + + +# we are going to build recipes to do the processing and splitting of the args # ensure we dispatch to the slicer immutable SliceIt end