Merge pull request #1818 from JuliaPlots/mkb/dev2
Deprecate glivisualize backend - replaces #1816
This commit is contained in:
commit
441954be35
2
NEWS.md
2
NEWS.md
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
## (current master)
|
## (current master)
|
||||||
- All new development should target Julia 1.x!
|
- deprecate GLVisualize
|
||||||
|
|
||||||
## 0.20.6
|
## 0.20.6
|
||||||
- fixes for PlotDocs.jl
|
- fixes for PlotDocs.jl
|
||||||
|
|||||||
@ -157,7 +157,7 @@ function pickDefaultBackend()
|
|||||||
# the ordering/inclusion of this package list is my semi-arbitrary guess at
|
# the ordering/inclusion of this package list is my semi-arbitrary guess at
|
||||||
# which one someone will want to use if they have the package installed...accounting for
|
# which one someone will want to use if they have the package installed...accounting for
|
||||||
# features, speed, and robustness
|
# features, speed, and robustness
|
||||||
# for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
|
# for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR")
|
||||||
# if pkgstr in keys(Pkg.installed())
|
# if pkgstr in keys(Pkg.installed())
|
||||||
# return backend(Symbol(lowercase(pkgstr)))
|
# return backend(Symbol(lowercase(pkgstr)))
|
||||||
# end
|
# end
|
||||||
@ -213,11 +213,11 @@ function backend(sym::Symbol)
|
|||||||
backend()
|
backend()
|
||||||
end
|
end
|
||||||
|
|
||||||
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse]
|
const _deprecated_backends = [:qwt, :winston, :bokeh, :gadfly, :immerse, :glvisualize]
|
||||||
|
|
||||||
function warn_on_deprecated_backend(bsym::Symbol)
|
function warn_on_deprecated_backend(bsym::Symbol)
|
||||||
if bsym in _deprecated_backends
|
if bsym in _deprecated_backends
|
||||||
@warn("Backend $bsym has been deprecated. It may not work as originally intended.")
|
@warn("Backend $bsym has been deprecated.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -268,17 +268,11 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# @init_backend Immerse
|
|
||||||
# @init_backend Gadfly
|
|
||||||
@init_backend PyPlot
|
@init_backend PyPlot
|
||||||
# @init_backend Qwt
|
|
||||||
@init_backend UnicodePlots
|
@init_backend UnicodePlots
|
||||||
# @init_backend Winston
|
|
||||||
# @init_backend Bokeh
|
|
||||||
@init_backend Plotly
|
@init_backend Plotly
|
||||||
@init_backend PlotlyJS
|
@init_backend PlotlyJS
|
||||||
@init_backend GR
|
@init_backend GR
|
||||||
@init_backend GLVisualize
|
|
||||||
@init_backend PGFPlots
|
@init_backend PGFPlots
|
||||||
@init_backend InspectDR
|
@init_backend InspectDR
|
||||||
@init_backend HDF5
|
@init_backend HDF5
|
||||||
@ -450,71 +444,6 @@ const _plotly_marker = [
|
|||||||
]
|
]
|
||||||
const _plotly_scale = [:identity, :log10]
|
const _plotly_scale = [:identity, :log10]
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
# glvisualize
|
|
||||||
|
|
||||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
|
||||||
@eval Main begin
|
|
||||||
import GLVisualize, GeometryTypes, Reactive, GLAbstraction, GLWindow, Contour
|
|
||||||
import GeometryTypes: Point2f0, Point3f0, Vec2f0, Vec3f0, GLNormalMesh, SimpleRectangle, Point, Vec
|
|
||||||
import FileIO, Images
|
|
||||||
export GLVisualize
|
|
||||||
import Reactive: Signal
|
|
||||||
import GLAbstraction: Style
|
|
||||||
import GLVisualize: visualize
|
|
||||||
import Plots.GL
|
|
||||||
import UnicodeFun
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
const _glvisualize_attr = merge_with_base_supported([
|
|
||||||
:annotations,
|
|
||||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
|
||||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
|
||||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
|
||||||
:label,
|
|
||||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
|
||||||
:markershape, :markercolor, :markersize, :markeralpha,
|
|
||||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
|
||||||
:fillrange, :fillcolor, :fillalpha,
|
|
||||||
:bins, :bar_width, :bar_edges, :bar_position,
|
|
||||||
:title, :title_location,
|
|
||||||
:window_title,
|
|
||||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
|
||||||
:titlefontsize, :titlefontcolor,
|
|
||||||
:legendfontsize, :legendfontcolor,
|
|
||||||
:tickfontsize,
|
|
||||||
:guidefontsize, :guidefontcolor,
|
|
||||||
:grid, :gridalpha, :gridstyle, :gridlinewidth,
|
|
||||||
:legend, :colorbar,
|
|
||||||
:marker_z,
|
|
||||||
:line_z,
|
|
||||||
:levels,
|
|
||||||
:ribbon, :quiver, :arrow,
|
|
||||||
:orientation,
|
|
||||||
:overwrite_figure,
|
|
||||||
#:polar,
|
|
||||||
:normalize, :weights,
|
|
||||||
:contours, :aspect_ratio,
|
|
||||||
:match_dimensions,
|
|
||||||
:clims,
|
|
||||||
:inset_subplots,
|
|
||||||
:dpi,
|
|
||||||
:hover,
|
|
||||||
:framestyle,
|
|
||||||
:tick_direction,
|
|
||||||
])
|
|
||||||
const _glvisualize_seriestype = [
|
|
||||||
:path, :shape, :straightline,
|
|
||||||
:scatter, :hexbin,
|
|
||||||
:bar, :boxplot,
|
|
||||||
:heatmap, :image, :volume,
|
|
||||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
|
||||||
]
|
|
||||||
const _glvisualize_style = [:auto, :solid, :dash, :dot, :dashdot]
|
|
||||||
const _glvisualize_marker = _allMarkers
|
|
||||||
const _glvisualize_scale = [:identity, :ln, :log2, :log10]
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# pgfplots
|
# pgfplots
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,208 +0,0 @@
|
|||||||
|
|
||||||
# https://github.com/bokeh/Bokeh.jl
|
|
||||||
|
|
||||||
|
|
||||||
supported_attrs(::BokehBackend) = merge_with_base_supported([
|
|
||||||
# :annotations,
|
|
||||||
# :axis,
|
|
||||||
# :background_color,
|
|
||||||
:linecolor,
|
|
||||||
# :color_palette,
|
|
||||||
# :fillrange,
|
|
||||||
# :fillcolor,
|
|
||||||
# :fillalpha,
|
|
||||||
# :foreground_color,
|
|
||||||
:group,
|
|
||||||
# :label,
|
|
||||||
# :layout,
|
|
||||||
# :legend,
|
|
||||||
:seriescolor, :seriesalpha,
|
|
||||||
:linestyle,
|
|
||||||
:seriestype,
|
|
||||||
:linewidth,
|
|
||||||
# :linealpha,
|
|
||||||
:markershape,
|
|
||||||
:markercolor,
|
|
||||||
:markersize,
|
|
||||||
# :markeralpha,
|
|
||||||
# :markerstrokewidth,
|
|
||||||
# :markerstrokecolor,
|
|
||||||
# :markerstrokestyle,
|
|
||||||
# :n,
|
|
||||||
# :bins,
|
|
||||||
# :nc,
|
|
||||||
# :nr,
|
|
||||||
# :pos,
|
|
||||||
# :smooth,
|
|
||||||
# :show,
|
|
||||||
:size,
|
|
||||||
:title,
|
|
||||||
# :window_title,
|
|
||||||
:x,
|
|
||||||
# :xguide,
|
|
||||||
# :xlims,
|
|
||||||
# :xticks,
|
|
||||||
:y,
|
|
||||||
# :yguide,
|
|
||||||
# :ylims,
|
|
||||||
# :yrightlabel,
|
|
||||||
# :yticks,
|
|
||||||
# :xscale,
|
|
||||||
# :yscale,
|
|
||||||
# :xflip,
|
|
||||||
# :yflip,
|
|
||||||
# :z,
|
|
||||||
# :tickfont,
|
|
||||||
# :guidefont,
|
|
||||||
# :legendfont,
|
|
||||||
# :grid,
|
|
||||||
# :surface,
|
|
||||||
# :levels,
|
|
||||||
])
|
|
||||||
supported_types(::BokehBackend) = [:path, :scatter]
|
|
||||||
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
|
||||||
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
|
||||||
supported_scales(::BokehBackend) = [:identity, :ln]
|
|
||||||
is_subplot_supported(::BokehBackend) = false
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function _initialize_backend(::BokehBackend; kw...)
|
|
||||||
@eval begin
|
|
||||||
@warn("Bokeh is no longer supported... many features will likely be broken.")
|
|
||||||
import Bokeh
|
|
||||||
export Bokeh
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
const _glyphtypes = KW(
|
|
||||||
:circle => :Circle,
|
|
||||||
:rect => :Square,
|
|
||||||
:diamond => :Diamond,
|
|
||||||
:utriangle => :Triangle,
|
|
||||||
:dtriangle => :InvertedTriangle,
|
|
||||||
# :pentagon =>
|
|
||||||
# :hexagon =>
|
|
||||||
# :heptagon =>
|
|
||||||
# :octagon =>
|
|
||||||
:cross => :Cross,
|
|
||||||
:xcross => :X,
|
|
||||||
:star5 => :Asterisk,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
function bokeh_glyph_type(plotattributes::KW)
|
|
||||||
st = plotattributes[:seriestype]
|
|
||||||
mt = plotattributes[:markershape]
|
|
||||||
if st == :scatter && mt == :none
|
|
||||||
mt = :circle
|
|
||||||
end
|
|
||||||
|
|
||||||
# if we have a marker, use that
|
|
||||||
if st == :scatter || mt != :none
|
|
||||||
return _glyphtypes[mt]
|
|
||||||
end
|
|
||||||
|
|
||||||
# otherwise return a line
|
|
||||||
return :Line
|
|
||||||
end
|
|
||||||
|
|
||||||
function get_stroke_vector(linestyle::Symbol)
|
|
||||||
dash = 12
|
|
||||||
dot = 3
|
|
||||||
gap = 2
|
|
||||||
linestyle == :solid && return Int[]
|
|
||||||
linestyle == :dash && return Int[dash, gap]
|
|
||||||
linestyle == :dot && return Int[dot, gap]
|
|
||||||
linestyle == :dashdot && return Int[dash, gap, dot, gap]
|
|
||||||
linestyle == :dashdotdot && return Int[dash, gap, dot, gap, dot, gap]
|
|
||||||
error("unsupported linestyle: ", linestyle)
|
|
||||||
end
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# function _create_plot(pkg::BokehBackend, plotattributes::KW)
|
|
||||||
function _create_backend_figure(plt::Plot{BokehBackend})
|
|
||||||
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
|
||||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
|
||||||
|
|
||||||
datacolumns = Bokeh.BokehDataSet[]
|
|
||||||
tools = Bokeh.tools()
|
|
||||||
filename = tempname() * ".html"
|
|
||||||
title = plt.attr[:title]
|
|
||||||
w, h = plt.attr[:size]
|
|
||||||
xaxis_type = plt.attr[:xscale] == :log10 ? :log : :auto
|
|
||||||
yaxis_type = plt.attr[:yscale] == :log10 ? :log : :auto
|
|
||||||
# legend = plt.attr[:legend] ? xxxx : nothing
|
|
||||||
legend = nothing
|
|
||||||
extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here
|
|
||||||
Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args)
|
|
||||||
|
|
||||||
# Plot(bplt, pkg, 0, plotattributes, KW[])
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# function _series_added(::BokehBackend, plt::Plot, plotattributes::KW)
|
|
||||||
function _series_added(plt::Plot{BokehBackend}, series::Series)
|
|
||||||
bdata = Dict{Symbol, Vector}(:x => collect(series.plotattributes[:x]), :y => collect(series.plotattributes[:y]))
|
|
||||||
|
|
||||||
glyph = Bokeh.Bokehjs.Glyph(
|
|
||||||
glyphtype = bokeh_glyph_type(plotattributes),
|
|
||||||
linecolor = webcolor(plotattributes[:linecolor]), # shape's stroke or line color
|
|
||||||
linewidth = plotattributes[:linewidth], # shape's stroke width or line width
|
|
||||||
fillcolor = webcolor(plotattributes[:markercolor]),
|
|
||||||
size = ceil(Int, plotattributes[:markersize] * 2.5), # magic number 2.5 to keep in same scale as other backends
|
|
||||||
dash = get_stroke_vector(plotattributes[:linestyle])
|
|
||||||
)
|
|
||||||
|
|
||||||
legend = nothing # TODO
|
|
||||||
push!(plt.o.datacolumns, Bokeh.BokehDataSet(bdata, glyph, legend))
|
|
||||||
|
|
||||||
# push!(plt.seriesargs, plotattributes)
|
|
||||||
# plt
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
|
||||||
function _update_plot_object(plt::Plot{BokehBackend}, plotattributes::KW)
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
# accessors for x/y data
|
|
||||||
|
|
||||||
# function getxy(plt::Plot{BokehBackend}, i::Int)
|
|
||||||
# series = plt.o.datacolumns[i].data
|
|
||||||
# series[:x], series[:y]
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# function setxy!(plt::Plot{BokehBackend}, xy::Tuple{X,Y}, i::Integer)
|
|
||||||
# series = plt.o.datacolumns[i].data
|
|
||||||
# series[:x], series[:y] = xy
|
|
||||||
# plt
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{BokehBackend})
|
|
||||||
# TODO: write a png to io
|
|
||||||
@warn("mime png not implemented")
|
|
||||||
end
|
|
||||||
|
|
||||||
function Base.display(::PlotsDisplay, plt::Plot{BokehBackend})
|
|
||||||
Bokeh.showplot(plt.o)
|
|
||||||
end
|
|
||||||
|
|
||||||
# function Base.display(::PlotsDisplay, plt::Subplot{BokehBackend})
|
|
||||||
# # TODO: display/show the subplot
|
|
||||||
# end
|
|
||||||
@ -1,744 +0,0 @@
|
|||||||
|
|
||||||
# https://github.com/dcjones/Gadfly.jl
|
|
||||||
|
|
||||||
|
|
||||||
supported_attrs(::GadflyBackend) = merge_with_base_supported([
|
|
||||||
:annotations,
|
|
||||||
:background_color, :foreground_color, :color_palette,
|
|
||||||
:group, :label, :seriestype,
|
|
||||||
:seriescolor, :seriesalpha,
|
|
||||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
|
||||||
:markershape, :markercolor, :markersize, :markeralpha,
|
|
||||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
|
||||||
:fillrange, :fillcolor, :fillalpha,
|
|
||||||
:bins, :n, :nc, :nr, :layout, :smooth,
|
|
||||||
:title, :window_title, :show, :size,
|
|
||||||
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
|
|
||||||
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
|
|
||||||
:z,
|
|
||||||
:tickfont, :guidefont, :legendfont,
|
|
||||||
:grid, :legend, :colorbar,
|
|
||||||
:marker_z, :levels,
|
|
||||||
:xerror, :yerror,
|
|
||||||
:ribbon, :quiver,
|
|
||||||
:orientation,
|
|
||||||
])
|
|
||||||
supported_types(::GadflyBackend) = [
|
|
||||||
:path,
|
|
||||||
:scatter, :hexbin,
|
|
||||||
:bar,
|
|
||||||
:contour, :shape
|
|
||||||
]
|
|
||||||
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
|
||||||
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
|
|
||||||
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
|
||||||
is_subplot_supported(::GadflyBackend) = true
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function _initialize_backend(::GadflyBackend; kw...)
|
|
||||||
@eval begin
|
|
||||||
import Gadfly, Compose
|
|
||||||
export Gadfly, Compose
|
|
||||||
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# immutable MissingVec <: AbstractVector{Float64} end
|
|
||||||
# Base.size(v::MissingVec) = (1,)
|
|
||||||
# Base.getindex(v::MissingVec, i::Integer) = 0.0
|
|
||||||
|
|
||||||
function createGadflyPlotObject(plotattributes::KW)
|
|
||||||
gplt = Gadfly.Plot()
|
|
||||||
gplt.mapping = Dict()
|
|
||||||
gplt.data_source = Gadfly.DataFrames.DataFrame()
|
|
||||||
# gplt.layers = gplt.layers[1:0]
|
|
||||||
gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());]
|
|
||||||
gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(plotattributes[:xguide]),
|
|
||||||
Gadfly.Guide.ylabel(plotattributes[:yguide]),
|
|
||||||
Gadfly.Guide.title(plotattributes[:title])]
|
|
||||||
gplt
|
|
||||||
end
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function getLineGeom(plotattributes::KW)
|
|
||||||
st = plotattributes[:seriestype]
|
|
||||||
xbins, ybins = maketuple(plotattributes[:bins])
|
|
||||||
if st == :hexb
|
|
||||||
Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins)
|
|
||||||
elseif st == :histogram2d
|
|
||||||
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
|
|
||||||
elseif st == :histogram
|
|
||||||
Gadfly.Geom.histogram(bincount = xbins,
|
|
||||||
orientation = isvertical(plotattributes) ? :vertical : :horizontal,
|
|
||||||
position = plotattributes[:bar_position] == :stack ? :stack : :dodge)
|
|
||||||
elseif st == :path
|
|
||||||
Gadfly.Geom.path
|
|
||||||
elseif st in (:bar, :sticks)
|
|
||||||
Gadfly.Geom.bar
|
|
||||||
elseif st == :steppost
|
|
||||||
Gadfly.Geom.step
|
|
||||||
elseif st == :steppre
|
|
||||||
Gadfly.Geom.step(direction = :vh)
|
|
||||||
elseif st == :hline
|
|
||||||
Gadfly.Geom.hline
|
|
||||||
elseif st == :vline
|
|
||||||
Gadfly.Geom.vline
|
|
||||||
elseif st == :contour
|
|
||||||
Gadfly.Geom.contour(levels = plotattributes[:levels])
|
|
||||||
# elseif st == :shape
|
|
||||||
# Gadfly.Geom.polygon(fill = true, preserve_order = true)
|
|
||||||
else
|
|
||||||
nothing
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function get_extra_theme_args(plotattributes::KW, k::Symbol)
|
|
||||||
# gracefully handles old Gadfly versions
|
|
||||||
extra_theme_args = KW()
|
|
||||||
try
|
|
||||||
extra_theme_args[:line_style] = Gadfly.get_stroke_vector(plotattributes[k])
|
|
||||||
catch err
|
|
||||||
if string(err) == "UndefVarError(:get_stroke_vector)"
|
|
||||||
Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?")
|
|
||||||
else
|
|
||||||
rethrow()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
extra_theme_args
|
|
||||||
end
|
|
||||||
|
|
||||||
function getGadflyLineTheme(plotattributes::KW)
|
|
||||||
st = plotattributes[:seriestype]
|
|
||||||
lc = convertColor(getColor(plotattributes[:linecolor]), plotattributes[:linealpha])
|
|
||||||
fc = convertColor(getColor(plotattributes[:fillcolor]), plotattributes[:fillalpha])
|
|
||||||
|
|
||||||
Gadfly.Theme(;
|
|
||||||
default_color = (st in (:histogram,:histogram2d,:hexbin,:bar,:sticks) ? fc : lc),
|
|
||||||
line_width = (st == :sticks ? 1 : plotattributes[:linewidth]) * Gadfly.px,
|
|
||||||
# line_style = Gadfly.get_stroke_vector(plotattributes[:linestyle]),
|
|
||||||
lowlight_color = x->RGB(fc), # fill/ribbon
|
|
||||||
lowlight_opacity = alpha(fc), # fill/ribbon
|
|
||||||
bar_highlight = RGB(lc), # bars
|
|
||||||
get_extra_theme_args(plotattributes, :linestyle)...
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# add a line as a new layer
|
|
||||||
function addGadflyLine!(plt::Plot, numlayers::Int, plotattributes::KW, geoms...)
|
|
||||||
gplt = getGadflyContext(plt)
|
|
||||||
gfargs = vcat(geoms..., getGadflyLineTheme(plotattributes))
|
|
||||||
kwargs = KW()
|
|
||||||
st = plotattributes[:seriestype]
|
|
||||||
|
|
||||||
# add a fill?
|
|
||||||
if plotattributes[:fillrange] != nothing && st != :contour
|
|
||||||
fillmin, fillmax = map(makevec, maketuple(plotattributes[:fillrange]))
|
|
||||||
nmin, nmax = length(fillmin), length(fillmax)
|
|
||||||
kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
|
|
||||||
kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(plotattributes[:y])]
|
|
||||||
push!(gfargs, Gadfly.Geom.ribbon)
|
|
||||||
end
|
|
||||||
|
|
||||||
if st in (:hline, :vline)
|
|
||||||
kwargs[st == :hline ? :yintercept : :xintercept] = plotattributes[:y]
|
|
||||||
|
|
||||||
else
|
|
||||||
if st == :sticks
|
|
||||||
w = 0.01 * mean(diff(plotattributes[:x]))
|
|
||||||
kwargs[:xmin] = plotattributes[:x] - w
|
|
||||||
kwargs[:xmax] = plotattributes[:x] + w
|
|
||||||
elseif st == :contour
|
|
||||||
kwargs[:z] = plotattributes[:z].surf
|
|
||||||
addGadflyContColorScale(plt, plotattributes[:linecolor])
|
|
||||||
end
|
|
||||||
|
|
||||||
kwargs[:x] = plotattributes[st == :histogram ? :y : :x]
|
|
||||||
kwargs[:y] = plotattributes[:y]
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# # add the layer
|
|
||||||
Gadfly.layer(gfargs...; order=numlayers, kwargs...)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
get_shape(sym::Symbol) = _shapes[sym]
|
|
||||||
get_shape(shape::Shape) = shape
|
|
||||||
|
|
||||||
# extract the underlying ShapeGeometry object(s)
|
|
||||||
getMarkerGeom(shapes::AVec) = gadflyshape(map(get_shape, shapes))
|
|
||||||
getMarkerGeom(other) = gadflyshape(get_shape(other))
|
|
||||||
|
|
||||||
# getMarkerGeom(shape::Shape) = gadflyshape(shape)
|
|
||||||
# getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape])
|
|
||||||
# getMarkerGeom(shapes::AVec) = gadflyshape(map(gadflyshape, shapes)) # map(getMarkerGeom, shapes)
|
|
||||||
function getMarkerGeom(plotattributes::KW)
|
|
||||||
if plotattributes[:seriestype] == :shape
|
|
||||||
Gadfly.Geom.polygon(fill = true, preserve_order = true)
|
|
||||||
else
|
|
||||||
getMarkerGeom(plotattributes[:markershape])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function getGadflyMarkerTheme(plotattributes::KW, attr::KW)
|
|
||||||
c = getColor(plotattributes[:markercolor])
|
|
||||||
α = plotattributes[:markeralpha]
|
|
||||||
if α != nothing
|
|
||||||
c = RGBA(RGB(c), α)
|
|
||||||
end
|
|
||||||
|
|
||||||
ms = plotattributes[:markersize]
|
|
||||||
ms = if typeof(ms) <: AVec
|
|
||||||
@warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))")
|
|
||||||
mean(ms) * Gadfly.px
|
|
||||||
else
|
|
||||||
ms * Gadfly.px
|
|
||||||
end
|
|
||||||
|
|
||||||
Gadfly.Theme(;
|
|
||||||
default_color = c,
|
|
||||||
default_point_size = ms,
|
|
||||||
discrete_highlight_color = c -> RGB(getColor(plotattributes[:markerstrokecolor])),
|
|
||||||
highlight_width = plotattributes[:markerstrokewidth] * Gadfly.px,
|
|
||||||
line_width = plotattributes[:markerstrokewidth] * Gadfly.px,
|
|
||||||
# get_extra_theme_args(plotattributes, :markerstrokestyle)...
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
function addGadflyContColorScale(plt::Plot{GadflyBackend}, c)
|
|
||||||
plt.attr[:colorbar] == :none && return
|
|
||||||
if !isa(c, ColorGradient)
|
|
||||||
c = default_gradient()
|
|
||||||
end
|
|
||||||
push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p))))
|
|
||||||
end
|
|
||||||
|
|
||||||
function addGadflyMarker!(plt::Plot, numlayers::Int, plotattributes::KW, attr::KW, geoms...)
|
|
||||||
gfargs = vcat(geoms..., getGadflyMarkerTheme(plotattributes, attr), getMarkerGeom(plotattributes))
|
|
||||||
kwargs = KW()
|
|
||||||
|
|
||||||
# handle continuous color scales for the markers
|
|
||||||
zcolor = plotattributes[:marker_z]
|
|
||||||
if zcolor != nothing && typeof(zcolor) <: AVec
|
|
||||||
kwargs[:color] = zcolor
|
|
||||||
addGadflyContColorScale(plt, plotattributes[:markercolor])
|
|
||||||
end
|
|
||||||
|
|
||||||
Gadfly.layer(gfargs...; x = plotattributes[:x], y = plotattributes[:y], order=numlayers, kwargs...)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function addToGadflyLegend(plt::Plot, plotattributes::KW)
|
|
||||||
if plt.attr[:legend] != :none && plotattributes[:label] != ""
|
|
||||||
gplt = getGadflyContext(plt)
|
|
||||||
|
|
||||||
# add the legend if needed
|
|
||||||
if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides)
|
|
||||||
pushfirst!(gplt.guides, Gadfly.Guide.manual_color_key("", AbstractString[], Color[]))
|
|
||||||
end
|
|
||||||
|
|
||||||
# now add the series to the legend
|
|
||||||
for guide in gplt.guides
|
|
||||||
if isa(guide, Gadfly.Guide.ManualColorKey)
|
|
||||||
# TODO: there's a BUG in gadfly if you pass in the same color more than once,
|
|
||||||
# since gadfly will call unique(colors), but doesn't also merge the rows that match
|
|
||||||
# Should ensure from this side that colors which are the same are merged together
|
|
||||||
|
|
||||||
c = getColor(plotattributes[plotattributes[:markershape] == :none ? :linecolor : :markercolor])
|
|
||||||
foundit = false
|
|
||||||
|
|
||||||
# extend the label if we found this color
|
|
||||||
for i in 1:length(guide.colors)
|
|
||||||
if RGB(c) == guide.colors[i]
|
|
||||||
guide.labels[i] *= ", " * plotattributes[:label]
|
|
||||||
foundit = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# didn't find the color, so add a new entry into the legend
|
|
||||||
if !foundit
|
|
||||||
push!(guide.labels, plotattributes[:label])
|
|
||||||
push!(guide.colors, c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : Any[]
|
|
||||||
getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing=float(smooth))]
|
|
||||||
|
|
||||||
|
|
||||||
function addGadflySeries!(plt::Plot, plotattributes::KW)
|
|
||||||
layers = Gadfly.Layer[]
|
|
||||||
gplt = getGadflyContext(plt)
|
|
||||||
|
|
||||||
# add a regression line?
|
|
||||||
# TODO: make more flexible
|
|
||||||
smooth = getGadflySmoothing(plotattributes[:smooth])
|
|
||||||
|
|
||||||
# lines
|
|
||||||
geom = getLineGeom(plotattributes)
|
|
||||||
if geom != nothing
|
|
||||||
prepend!(layers, addGadflyLine!(plt, length(gplt.layers), plotattributes, geom, smooth...))
|
|
||||||
smooth = Any[] # don't add a regression for markers too
|
|
||||||
end
|
|
||||||
|
|
||||||
# special handling for ohlc and scatter
|
|
||||||
st = plotattributes[:seriestype]
|
|
||||||
# if st == :ohlc
|
|
||||||
# error("Haven't re-implemented after refactoring")
|
|
||||||
if st in (:histogram2d, :hexbin) && (isa(plotattributes[:fillcolor], ColorGradient) || isa(plotattributes[:fillcolor], ColorFunction))
|
|
||||||
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(plotattributes[:fillcolor], p))))
|
|
||||||
elseif st == :scatter && plotattributes[:markershape] == :none
|
|
||||||
plotattributes[:markershape] = :circle
|
|
||||||
end
|
|
||||||
|
|
||||||
# markers
|
|
||||||
if plotattributes[:markershape] != :none || st == :shape
|
|
||||||
prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), plotattributes, plt.attr, smooth...))
|
|
||||||
end
|
|
||||||
|
|
||||||
st in (:histogram2d, :hexbin, :contour) || addToGadflyLegend(plt, plotattributes)
|
|
||||||
|
|
||||||
# now save the layers that apply to this series
|
|
||||||
plotattributes[:gadflylayers] = layers
|
|
||||||
prepend!(gplt.layers, layers)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# NOTE: I'm leaving this here and commented out just in case I want to implement again... it was hacky code to create multi-colored line segments
|
|
||||||
|
|
||||||
# # colorgroup
|
|
||||||
# z = plotattributes[:z]
|
|
||||||
|
|
||||||
# # handle line segments of different colors
|
|
||||||
# cscheme = plotattributes[:linecolor]
|
|
||||||
# if isa(cscheme, ColorVector)
|
|
||||||
# # create a color scale, and set the color group to the index of the color
|
|
||||||
# push!(gplt.scales, Gadfly.Scale.color_discrete_manual(cscheme.v...))
|
|
||||||
|
|
||||||
# # this is super weird, but... oh well... for some reason this creates n separate line segments...
|
|
||||||
# # create a list of vertices that go: [x1,x2,x2,x3,x3, ... ,xi,xi, ... xn,xn] (same for y)
|
|
||||||
# # then the vector passed to the "color" keyword should be a vector: [1,1,2,2,3,3,4,4, ..., i,i, ... , n,n]
|
|
||||||
# csindices = Int[mod1(i,length(cscheme.v)) for i in 1:length(plotattributes[:y])]
|
|
||||||
# cs = collect(repeat(csindices', 2, 1))[1:end-1]
|
|
||||||
# grp = collect(repeat((1:length(plotattributes[:y]))', 2, 1))[1:end-1]
|
|
||||||
# plotattributes[:x], plotattributes[:y] = map(createSegments, (plotattributes[:x], plotattributes[:y]))
|
|
||||||
# colorgroup = [(:linecolor, cs), (:group, grp)]
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function addGadflyTicksGuide(gplt, ticks, isx::Bool)
|
|
||||||
ticks == :auto && return
|
|
||||||
|
|
||||||
# remove the ticks?
|
|
||||||
if ticks in (:none, false, nothing)
|
|
||||||
return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
|
||||||
end
|
|
||||||
|
|
||||||
ttype = ticksType(ticks)
|
|
||||||
|
|
||||||
# just the values... put ticks here, but use standard labels
|
|
||||||
if ttype == :ticks
|
|
||||||
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
|
|
||||||
replaceType(gplt.guides, gtype(ticks = collect(ticks)))
|
|
||||||
|
|
||||||
# set the ticks and the labels
|
|
||||||
# Note: this is pretty convoluted, but I think it works. We set the ticks using Gadfly.Guide,
|
|
||||||
# and then set the label function (wraps a dict lookup) through a continuous Gadfly.Scale.
|
|
||||||
elseif ttype == :ticks_and_labels
|
|
||||||
gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks
|
|
||||||
replaceType(gplt.guides, gtype(ticks = collect(ticks[1])))
|
|
||||||
|
|
||||||
# # TODO add xtick_label function (given tick, return label??)
|
|
||||||
# # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing)
|
|
||||||
# filterGadflyScale(gplt, isx)
|
|
||||||
# gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete
|
|
||||||
# labelmap = Dict(zip(ticks...))
|
|
||||||
# labelfunc = val -> labelmap[val]
|
|
||||||
# push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc))
|
|
||||||
|
|
||||||
filterGadflyScale(gplt, isx)
|
|
||||||
gfunc = isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous
|
|
||||||
labelmap = Dict(zip(ticks...))
|
|
||||||
labelfunc = val -> labelmap[val]
|
|
||||||
push!(gplt.scales, gfunc(labels = labelfunc))
|
|
||||||
|
|
||||||
else
|
|
||||||
error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScale) && scale.vars[1] == (isx ? :x : :y)
|
|
||||||
filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(scale, isx), gplt.scales)
|
|
||||||
|
|
||||||
|
|
||||||
function getGadflyScaleFunction(plotattributes::KW, isx::Bool)
|
|
||||||
scalekey = isx ? :xscale : :yscale
|
|
||||||
hasScaleKey = haskey(plotattributes, scalekey)
|
|
||||||
if hasScaleKey
|
|
||||||
scale = plotattributes[scalekey]
|
|
||||||
scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey, log
|
|
||||||
scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey, log2
|
|
||||||
scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey, log10
|
|
||||||
scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey, asinh
|
|
||||||
scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey, sqrt
|
|
||||||
end
|
|
||||||
isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey, identity
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function addGadflyLimitsScale(gplt, plotattributes::KW, isx::Bool)
|
|
||||||
gfunc, hasScaleKey, func = getGadflyScaleFunction(plotattributes, isx)
|
|
||||||
|
|
||||||
# do we want to add min/max limits for the axis?
|
|
||||||
limsym = isx ? :xlims : :ylims
|
|
||||||
limargs = Any[]
|
|
||||||
|
|
||||||
# map :auto to nothing, otherwise add to limargs
|
|
||||||
lims = get(plotattributes, limsym, :auto)
|
|
||||||
if lims == :auto
|
|
||||||
lims = nothing
|
|
||||||
else
|
|
||||||
if limsType(lims) == :limits
|
|
||||||
push!(limargs, (:minvalue, min(lims...)))
|
|
||||||
push!(limargs, (:maxvalue, max(lims...)))
|
|
||||||
else
|
|
||||||
error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# replace any current scales with this one
|
|
||||||
if hasScaleKey || !isempty(limargs)
|
|
||||||
filterGadflyScale(gplt, isx)
|
|
||||||
push!(gplt.scales, gfunc(; limargs...))
|
|
||||||
end
|
|
||||||
|
|
||||||
lims, func
|
|
||||||
end
|
|
||||||
|
|
||||||
function updateGadflyAxisFlips(gplt, plotattributes::KW, xlims, ylims, xfunc, yfunc)
|
|
||||||
if isa(gplt.coord, Gadfly.Coord.Cartesian)
|
|
||||||
gplt.coord = Gadfly.Coord.cartesian(
|
|
||||||
gplt.coord.xvars,
|
|
||||||
gplt.coord.yvars;
|
|
||||||
xmin = xlims == nothing ? gplt.coord.xmin : xfunc(minimum(xlims)),
|
|
||||||
xmax = xlims == nothing ? gplt.coord.xmax : xfunc(maximum(xlims)),
|
|
||||||
ymin = ylims == nothing ? gplt.coord.ymin : yfunc(minimum(ylims)),
|
|
||||||
ymax = ylims == nothing ? gplt.coord.ymax : yfunc(maximum(ylims)),
|
|
||||||
xflip = get(plotattributes, :xflip, gplt.coord.xflip),
|
|
||||||
yflip = get(plotattributes, :yflip, gplt.coord.yflip),
|
|
||||||
fixed = gplt.coord.fixed,
|
|
||||||
aspect_ratio = gplt.coord.aspect_ratio,
|
|
||||||
raster = gplt.coord.raster
|
|
||||||
)
|
|
||||||
else
|
|
||||||
gplt.coord = Gadfly.Coord.Cartesian(
|
|
||||||
xflip = get(plotattributes, :xflip, false),
|
|
||||||
yflip = get(plotattributes, :yflip, false)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function findGuideAndSet(gplt, t::DataType, args...; kw...)
|
|
||||||
for (i,guide) in enumerate(gplt.guides)
|
|
||||||
if isa(guide, t)
|
|
||||||
gplt.guides[i] = t(args...; kw...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function updateGadflyGuides(plt::Plot, plotattributes::KW)
|
|
||||||
gplt = getGadflyContext(plt)
|
|
||||||
haskey(plotattributes, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(plotattributes[:title]))
|
|
||||||
haskey(plotattributes, :xguide) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(plotattributes[:xguide]))
|
|
||||||
haskey(plotattributes, :yguide) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(plotattributes[:yguide]))
|
|
||||||
|
|
||||||
xlims, xfunc = addGadflyLimitsScale(gplt, plotattributes, true)
|
|
||||||
ylims, yfunc = addGadflyLimitsScale(gplt, plotattributes, false)
|
|
||||||
|
|
||||||
ticks = get(plotattributes, :xticks, :auto)
|
|
||||||
if ticks == :none
|
|
||||||
_remove_axis(plt, true)
|
|
||||||
else
|
|
||||||
addGadflyTicksGuide(gplt, ticks, true)
|
|
||||||
end
|
|
||||||
ticks = get(plotattributes, :yticks, :auto)
|
|
||||||
if ticks == :none
|
|
||||||
_remove_axis(plt, false)
|
|
||||||
else
|
|
||||||
addGadflyTicksGuide(gplt, ticks, false)
|
|
||||||
end
|
|
||||||
|
|
||||||
updateGadflyAxisFlips(gplt, plotattributes, xlims, ylims, xfunc, yfunc)
|
|
||||||
end
|
|
||||||
|
|
||||||
function updateGadflyPlotTheme(plt::Plot, plotattributes::KW)
|
|
||||||
kwargs = KW()
|
|
||||||
|
|
||||||
# colors
|
|
||||||
insidecolor, gridcolor, textcolor, guidecolor, legendcolor =
|
|
||||||
map(s -> getColor(plotattributes[s]), (
|
|
||||||
:background_color_inside,
|
|
||||||
:foreground_color_grid,
|
|
||||||
:foreground_color_text,
|
|
||||||
:foreground_color_guide,
|
|
||||||
:foreground_color_legend
|
|
||||||
))
|
|
||||||
|
|
||||||
# # hide the legend?
|
|
||||||
leg = plotattributes[plotattributes[:legend] == :none ? :colorbar : :legend]
|
|
||||||
if leg != :best
|
|
||||||
kwargs[:key_position] = leg == :inside ? :right : leg
|
|
||||||
end
|
|
||||||
|
|
||||||
if !get(plotattributes, :grid, true)
|
|
||||||
kwargs[:grid_color] = gridcolor
|
|
||||||
end
|
|
||||||
|
|
||||||
# fonts
|
|
||||||
tfont, gfont, lfont = plotattributes[:tickfont], plotattributes[:guidefont], plotattributes[:legendfont]
|
|
||||||
|
|
||||||
getGadflyContext(plt).theme = Gadfly.Theme(;
|
|
||||||
background_color = insidecolor,
|
|
||||||
minor_label_color = textcolor,
|
|
||||||
minor_label_font = tfont.family,
|
|
||||||
minor_label_font_size = tfont.pointsize * Gadfly.pt,
|
|
||||||
major_label_color = guidecolor,
|
|
||||||
major_label_font = gfont.family,
|
|
||||||
major_label_font_size = gfont.pointsize * Gadfly.pt,
|
|
||||||
key_title_color = guidecolor,
|
|
||||||
key_title_font = gfont.family,
|
|
||||||
key_title_font_size = gfont.pointsize * Gadfly.pt,
|
|
||||||
key_label_color = legendcolor,
|
|
||||||
key_label_font = lfont.family,
|
|
||||||
key_label_font_size = lfont.pointsize * Gadfly.pt,
|
|
||||||
plot_padding = 1 * Gadfly.mm,
|
|
||||||
kwargs...
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function createGadflyAnnotationObject(x, y, val::AbstractString)
|
|
||||||
Gadfly.Guide.annotation(Compose.compose(
|
|
||||||
Compose.context(),
|
|
||||||
Compose.text(x, y, val)
|
|
||||||
))
|
|
||||||
end
|
|
||||||
|
|
||||||
function createGadflyAnnotationObject(x, y, txt::PlotText)
|
|
||||||
halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright))
|
|
||||||
valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom))
|
|
||||||
rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))])
|
|
||||||
Gadfly.Guide.annotation(Compose.compose(
|
|
||||||
Compose.context(),
|
|
||||||
Compose.text(x, y, txt.str, halign, valign, rotations...),
|
|
||||||
Compose.font(string(txt.font.family)),
|
|
||||||
Compose.fontsize(txt.font.pointsize * Gadfly.pt),
|
|
||||||
Compose.stroke(txt.font.color),
|
|
||||||
Compose.fill(txt.font.color)
|
|
||||||
))
|
|
||||||
end
|
|
||||||
|
|
||||||
function _add_annotations(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
|
||||||
for ann in anns
|
|
||||||
push!(plt.o.guides, createGadflyAnnotationObject(ann...))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# create a blank Gadfly.Plot object
|
|
||||||
# function _create_plot(pkg::GadflyBackend, plotattributes::KW)
|
|
||||||
# gplt = createGadflyPlotObject(plotattributes)
|
|
||||||
# Plot(gplt, pkg, 0, plotattributes, KW[])
|
|
||||||
# end
|
|
||||||
function _create_backend_figure(plt::Plot{GadflyBackend})
|
|
||||||
createGadflyPlotObject(plt.attr)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# plot one data series
|
|
||||||
# function _series_added(::GadflyBackend, plt::Plot, plotattributes::KW)
|
|
||||||
function _series_added(plt::Plot{GadflyBackend}, series::Series)
|
|
||||||
# first clear out the temporary layer
|
|
||||||
gplt = getGadflyContext(plt)
|
|
||||||
if gplt.layers[1].geom.tag == :remove
|
|
||||||
gplt.layers = gplt.layers[2:end]
|
|
||||||
end
|
|
||||||
|
|
||||||
addGadflySeries!(plt, series.plotattributes)
|
|
||||||
# push!(plt.seriesargs, plotattributes)
|
|
||||||
# plt
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function _update_plot_object(plt::Plot{GadflyBackend}, plotattributes::KW)
|
|
||||||
updateGadflyGuides(plt, plotattributes)
|
|
||||||
updateGadflyPlotTheme(plt, plotattributes)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
# accessors for x/y data
|
|
||||||
|
|
||||||
# TODO: need to save all the layer indices which apply to this series
|
|
||||||
function getGadflyMappings(plt::Plot, i::Integer)
|
|
||||||
@assert i > 0 && i <= plt.n
|
|
||||||
mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]]
|
|
||||||
end
|
|
||||||
|
|
||||||
function getxy(plt::Plot{GadflyBackend}, i::Integer)
|
|
||||||
mapping = getGadflyMappings(plt, i)[1]
|
|
||||||
mapping[:x], mapping[:y]
|
|
||||||
end
|
|
||||||
|
|
||||||
function setxy!(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
|
||||||
for mapping in getGadflyMappings(plt, i)
|
|
||||||
mapping[:x], mapping[:y] = xy
|
|
||||||
end
|
|
||||||
plt
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# # create the underlying object (each backend will do this differently)
|
|
||||||
# function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool)
|
|
||||||
# isbefore && return false # wait until after plotting to create the subplots
|
|
||||||
# subplt.o = nothing
|
|
||||||
# true
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool)
|
|
||||||
gplt = getGadflyContext(plt)
|
|
||||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
|
||||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
function _expand_limits(lims, plt::Plot{GadflyBackend}, isx::Bool)
|
|
||||||
for l in getGadflyContext(plt).layers
|
|
||||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
getGadflyContext(plt::Plot{GadflyBackend}) = plt.o
|
|
||||||
# getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(subplt)
|
|
||||||
|
|
||||||
# # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects
|
|
||||||
# function buildGadflySubplotContext(subplt::Subplot)
|
|
||||||
# rows = Any[]
|
|
||||||
# row = Any[]
|
|
||||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
|
||||||
#
|
|
||||||
# # add the Plot object to the row
|
|
||||||
# push!(row, getGadflyContext(subplt.plts[i]))
|
|
||||||
#
|
|
||||||
# # add the row
|
|
||||||
# if c == ncols(subplt.layout, r)
|
|
||||||
# push!(rows, Gadfly.hstack(row...))
|
|
||||||
# row = Any[]
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # stack the rows
|
|
||||||
# Gadfly.vstack(rows...)
|
|
||||||
# end
|
|
||||||
|
|
||||||
setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px)
|
|
||||||
setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
|
|
||||||
# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getattr(subplt, 1)[:size]...)
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function doshow(io::IO, func, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
|
|
||||||
gplt = getGadflyContext(plt)
|
|
||||||
setGadflyDisplaySize(plt)
|
|
||||||
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
|
|
||||||
end
|
|
||||||
|
|
||||||
getGadflyWriteFunc(::MIME"image/png") = Gadfly.PNG
|
|
||||||
getGadflyWriteFunc(::MIME"image/svg+xml") = Gadfly.SVG
|
|
||||||
# getGadflyWriteFunc(::MIME"text/html") = Gadfly.SVGJS
|
|
||||||
getGadflyWriteFunc(::MIME"application/pdf") = Gadfly.PDF
|
|
||||||
getGadflyWriteFunc(::MIME"application/postscript") = Gadfly.PS
|
|
||||||
getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
|
|
||||||
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
|
|
||||||
|
|
||||||
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
|
|
||||||
@eval function Base.show(io::IO, ::$mime, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
|
|
||||||
func = getGadflyWriteFunc($mime())
|
|
||||||
doshow(io, func, plt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend})
|
|
||||||
setGadflyDisplaySize(plt.attr[:size]...)
|
|
||||||
display(plt.o)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend})
|
|
||||||
# setGadflyDisplaySize(getattr(subplt,1)[:size]...)
|
|
||||||
# ctx = buildGadflySubplotContext(subplt)
|
|
||||||
#
|
|
||||||
# # taken from Gadfly since I couldn't figure out how to do it directly
|
|
||||||
#
|
|
||||||
# filename = string(Gadfly.tempname(), ".html")
|
|
||||||
# output = open(filename, "w")
|
|
||||||
#
|
|
||||||
# plot_output = IOBuffer()
|
|
||||||
# Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width,
|
|
||||||
# Compose.default_graphic_height, false), ctx)
|
|
||||||
# plotsvg = takebuf_string(plot_output)
|
|
||||||
#
|
|
||||||
# write(output,
|
|
||||||
# """
|
|
||||||
# <!DOCTYPE html>
|
|
||||||
# <html>
|
|
||||||
# <head>
|
|
||||||
# <title>Gadfly Plot</title>
|
|
||||||
# <meta charset="utf-8">
|
|
||||||
# </head>
|
|
||||||
# <body>
|
|
||||||
# <script charset="utf-8">
|
|
||||||
# $(readall(Compose.snapsvgjs))
|
|
||||||
# </script>
|
|
||||||
# <script charset="utf-8">
|
|
||||||
# $(readall(Gadfly.gadflyjs))
|
|
||||||
# </script>
|
|
||||||
# $(plotsvg)
|
|
||||||
# </body>
|
|
||||||
# </html>
|
|
||||||
# """)
|
|
||||||
# close(output)
|
|
||||||
# Gadfly.open_file(filename)
|
|
||||||
# end
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# Geometry which displays arbitrary shapes at given (x, y) positions.
|
|
||||||
# note: vertices is a list of shapes
|
|
||||||
struct ShapeGeometry <: Gadfly.GeometryElement
|
|
||||||
vertices::AbstractVector #{Tuple{Float64,Float64}}
|
|
||||||
tag::Symbol
|
|
||||||
|
|
||||||
function ShapeGeometry(shape; tag::Symbol=Gadfly.Geom.empty_tag)
|
|
||||||
new(shape, tag)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# TODO: add for PR
|
|
||||||
# const shape = ShapeGeometry
|
|
||||||
|
|
||||||
|
|
||||||
function Gadfly.element_aesthetics(::ShapeGeometry)
|
|
||||||
[:x, :y, :size, :color]
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Generate a form for a shape geometry.
|
|
||||||
#
|
|
||||||
# Args:
|
|
||||||
# geom: shape geometry.
|
|
||||||
# theme: the plot's theme.
|
|
||||||
# aes: aesthetics.
|
|
||||||
#
|
|
||||||
# Returns:
|
|
||||||
# A compose Form.
|
|
||||||
#
|
|
||||||
function Gadfly.render(geom::ShapeGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
|
|
||||||
|
|
||||||
# TODO: add for PR
|
|
||||||
# Gadfly.assert_aesthetics_defined("Geom.shape", aes, :x, :y)
|
|
||||||
# Gadfly.assert_aesthetics_equal_length("Geom.shape", aes,
|
|
||||||
# element_aesthetics(geom)...)
|
|
||||||
|
|
||||||
default_aes = Gadfly.Aesthetics()
|
|
||||||
default_aes.color = Gadfly.DataFrames.PooledDataArray(RGBA{Float32}[theme.default_color])
|
|
||||||
default_aes.size = Compose.Measure[theme.default_point_size]
|
|
||||||
aes = Gadfly.inherit(aes, default_aes)
|
|
||||||
|
|
||||||
lw_hover_scale = 10
|
|
||||||
lw_ratio = theme.line_width / aes.size[1]
|
|
||||||
|
|
||||||
aes_x, aes_y = Gadfly.concretize(aes.x, aes.y)
|
|
||||||
|
|
||||||
ctx = Compose.compose!(
|
|
||||||
Compose.context(),
|
|
||||||
make_polygon(geom, aes.x, aes.y, aes.size),
|
|
||||||
Compose.fill(aes.color),
|
|
||||||
Compose.linewidth(theme.highlight_width))
|
|
||||||
|
|
||||||
if aes.color_key_continuous != nothing && aes.color_key_continuous
|
|
||||||
Compose.compose!(ctx,
|
|
||||||
Compose.stroke(map(theme.continuous_highlight_color, aes.color)))
|
|
||||||
else
|
|
||||||
Compose.compose!(ctx,
|
|
||||||
Compose.stroke(map(theme.discrete_highlight_color, aes.color)),
|
|
||||||
Compose.svgclass([Gadfly.svg_color_class_from_label(Gadfly.escape_id(aes.color_label([c])[1]))
|
|
||||||
for c in aes.color]))
|
|
||||||
end
|
|
||||||
|
|
||||||
return Compose.compose!(Compose.context(order=4), Compose.svgclass("geometry"), ctx)
|
|
||||||
end
|
|
||||||
|
|
||||||
function gadflyshape(sv::Shape)
|
|
||||||
ShapeGeometry(Any[vertices(sv)])
|
|
||||||
end
|
|
||||||
|
|
||||||
function gadflyshape(sv::AVec{Shape})
|
|
||||||
ShapeGeometry(Any[vertices(s) for s in sv])
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# create a Compose context given a ShapeGeometry and the xs/ys/sizes
|
|
||||||
function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray, rs::AbstractArray)
|
|
||||||
n = max(length(xs), length(ys), length(rs))
|
|
||||||
T = Tuple{Compose.Measure, Compose.Measure}
|
|
||||||
polys = Array(Vector{T}, n)
|
|
||||||
for i in 1:n
|
|
||||||
x = Compose.x_measure(xs[mod1(i, length(xs))])
|
|
||||||
y = Compose.y_measure(ys[mod1(i, length(ys))])
|
|
||||||
r = rs[mod1(i, length(rs))]
|
|
||||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in _cycle(geom.vertices, i)]
|
|
||||||
end
|
|
||||||
Gadfly.polygon(polys, geom.tag)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------------------
|
|
||||||
@ -1,186 +0,0 @@
|
|||||||
|
|
||||||
# https://github.com/JuliaGraphics/Immerse.jl
|
|
||||||
|
|
||||||
supported_attrs(::ImmerseBackend) = supported_attrs(GadflyBackend())
|
|
||||||
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
|
|
||||||
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
|
|
||||||
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
|
|
||||||
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
|
|
||||||
is_subplot_supported(::ImmerseBackend) = true
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function _initialize_backend(::ImmerseBackend; kw...)
|
|
||||||
@eval begin
|
|
||||||
import Immerse, Gadfly, Compose, Gtk
|
|
||||||
export Immerse, Gadfly, Compose, Gtk
|
|
||||||
include(joinpath(dirname(@__FILE__), "gadfly_shapes.jl"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function createImmerseFigure(plotattributes::KW)
|
|
||||||
w,h = plotattributes[:size]
|
|
||||||
figidx = Immerse.figure(; name = plotattributes[:window_title], width = w, height = h)
|
|
||||||
Immerse.Figure(figidx)
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# create a blank Gadfly.Plot object
|
|
||||||
# function _create_plot(pkg::ImmerseBackend, plotattributes::KW)
|
|
||||||
# # create the underlying Gadfly.Plot object
|
|
||||||
# gplt = createGadflyPlotObject(plotattributes)
|
|
||||||
#
|
|
||||||
# # save both the Immerse.Figure and the Gadfly.Plot
|
|
||||||
# Plot((nothing,gplt), pkg, 0, plotattributes, KW[])
|
|
||||||
# end
|
|
||||||
function _create_backend_figure(plt::Plot{ImmerseBackend})
|
|
||||||
(nothing, createGadflyPlotObject(plt.attr))
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# # plot one data series
|
|
||||||
# function _series_added(::ImmerseBackend, plt::Plot, plotattributes::KW)
|
|
||||||
# addGadflySeries!(plt, plotattributes)
|
|
||||||
# push!(plt.seriesargs, plotattributes)
|
|
||||||
# plt
|
|
||||||
# end
|
|
||||||
|
|
||||||
function _series_added(plt::Plot{ImmerseBackend}, series::Series)
|
|
||||||
addGadflySeries!(plt, series.plotattributes)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function _update_plot_object(plt::Plot{ImmerseBackend}, plotattributes::KW)
|
|
||||||
updateGadflyGuides(plt, plotattributes)
|
|
||||||
updateGadflyPlotTheme(plt, plotattributes)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
function _add_annotations(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
|
||||||
for ann in anns
|
|
||||||
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
# accessors for x/y data
|
|
||||||
|
|
||||||
function getxy(plt::Plot{ImmerseBackend}, i::Integer)
|
|
||||||
mapping = getGadflyMappings(plt, i)[1]
|
|
||||||
mapping[:x], mapping[:y]
|
|
||||||
end
|
|
||||||
|
|
||||||
function setxy!(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
|
||||||
for mapping in getGadflyMappings(plt, i)
|
|
||||||
mapping[:x], mapping[:y] = xy
|
|
||||||
end
|
|
||||||
plt
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# function _create_subplot(subplt::Subplot{ImmerseBackend}, isbefore::Bool)
|
|
||||||
# return false
|
|
||||||
# # isbefore && return false
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# function showSubplotObject(subplt::Subplot{ImmerseBackend})
|
|
||||||
# # create the Gtk window with vertical box vsep
|
|
||||||
# plotattributes = getattr(subplt,1)
|
|
||||||
# w,h = plotattributes[:size]
|
|
||||||
# vsep = Gtk.GtkBoxLeaf(:v)
|
|
||||||
# win = Gtk.GtkWindowLeaf(vsep, plotattributes[:window_title], w, h)
|
|
||||||
#
|
|
||||||
# figindices = []
|
|
||||||
# row = Gtk.GtkBoxLeaf(:h)
|
|
||||||
# push!(vsep, row)
|
|
||||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
|
||||||
# plt = subplt.plts[i]
|
|
||||||
#
|
|
||||||
# # get the components... box is the main plot GtkBox, and canvas is the GtkCanvas where it's plotted
|
|
||||||
# box, toolbar, canvas = Immerse.createPlotGuiComponents()
|
|
||||||
#
|
|
||||||
# # add the plot's box to the row
|
|
||||||
# push!(row, box)
|
|
||||||
#
|
|
||||||
# # create the figure and store the index returned for destruction later
|
|
||||||
# figidx = Immerse.figure(canvas)
|
|
||||||
# push!(figindices, figidx)
|
|
||||||
#
|
|
||||||
# fig = Immerse.figure(figidx)
|
|
||||||
# plt.o = (fig, plt.o[2])
|
|
||||||
#
|
|
||||||
# # add the row
|
|
||||||
# if c == ncols(subplt.layout, r)
|
|
||||||
# row = Gtk.GtkBoxLeaf(:h)
|
|
||||||
# push!(vsep, row)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # destructor... clean up plots
|
|
||||||
# Gtk.on_signal_destroy((x...) -> ([Immerse.dropfig(Immerse._display,i) for i in figindices]; subplt.o = nothing), win)
|
|
||||||
#
|
|
||||||
# subplt.o = win
|
|
||||||
# true
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
function _remove_axis(plt::Plot{ImmerseBackend}, isx::Bool)
|
|
||||||
gplt = getGadflyContext(plt)
|
|
||||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false)
|
|
||||||
addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
function _expand_limits(lims, plt::Plot{ImmerseBackend}, isx::Bool)
|
|
||||||
for l in getGadflyContext(plt).layers
|
|
||||||
_expand_limits(lims, l.mapping[isx ? :x : :y])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
getGadflyContext(plt::Plot{ImmerseBackend}) = plt.o[2]
|
|
||||||
# getGadflyContext(subplt::Subplot{ImmerseBackend}) = buildGadflySubplotContext(subplt)
|
|
||||||
|
|
||||||
|
|
||||||
function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend})
|
|
||||||
|
|
||||||
fig, gplt = plt.o
|
|
||||||
if fig == nothing
|
|
||||||
fig = createImmerseFigure(plt.attr)
|
|
||||||
Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas)
|
|
||||||
plt.o = (fig, gplt)
|
|
||||||
end
|
|
||||||
|
|
||||||
Immerse.figure(fig.figno; displayfig = false)
|
|
||||||
display(gplt)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# function Base.display(::PlotsDisplay, subplt::Subplot{ImmerseBackend})
|
|
||||||
#
|
|
||||||
# # if we haven't created the window yet, do it
|
|
||||||
# if subplt.o == nothing
|
|
||||||
# showSubplotObject(subplt)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # display the plots by creating a fresh Immerse.Figure object from the GtkCanvas and Gadfly.Plot
|
|
||||||
# for plt in subplt.plts
|
|
||||||
# fig, gplt = plt.o
|
|
||||||
# Immerse.figure(fig.figno; displayfig = false)
|
|
||||||
# display(gplt)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# # o is the window... show it
|
|
||||||
# showall(subplt.o)
|
|
||||||
# end
|
|
||||||
@ -1,308 +0,0 @@
|
|||||||
|
|
||||||
# https://github.com/tbreloff/Qwt.jl
|
|
||||||
|
|
||||||
|
|
||||||
supported_attrs(::QwtBackend) = merge_with_base_supported([
|
|
||||||
:annotations,
|
|
||||||
:linecolor,
|
|
||||||
:fillrange,
|
|
||||||
:fillcolor,
|
|
||||||
:label,
|
|
||||||
:legend,
|
|
||||||
:seriescolor, :seriesalpha,
|
|
||||||
:linestyle,
|
|
||||||
:linewidth,
|
|
||||||
:markershape,
|
|
||||||
:markercolor,
|
|
||||||
:markersize,
|
|
||||||
:bins,
|
|
||||||
:pos,
|
|
||||||
:title,
|
|
||||||
:window_title,
|
|
||||||
:guide, :lims, :ticks, :scale,
|
|
||||||
])
|
|
||||||
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
|
|
||||||
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
|
||||||
supported_scales(::QwtBackend) = [:identity, :log10]
|
|
||||||
is_subplot_supported(::QwtBackend) = true
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function _initialize_backend(::QwtBackend; kw...)
|
|
||||||
@eval begin
|
|
||||||
@warn("Qwt is no longer supported... many features will likely be broken.")
|
|
||||||
import Qwt
|
|
||||||
export Qwt
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# -------------------------------
|
|
||||||
|
|
||||||
const _qwtAliases = KW(
|
|
||||||
:bins => :heatmap_n,
|
|
||||||
:fillrange => :fillto,
|
|
||||||
:linewidth => :width,
|
|
||||||
:markershape => :marker,
|
|
||||||
:hexbin => :heatmap,
|
|
||||||
:path => :line,
|
|
||||||
:steppost => :step,
|
|
||||||
:steppre => :stepinverted,
|
|
||||||
:star5 => :star1,
|
|
||||||
:star8 => :star2,
|
|
||||||
)
|
|
||||||
|
|
||||||
function fixcolors(plotattributes::KW)
|
|
||||||
for (k,v) in plotattributes
|
|
||||||
if typeof(v) <: ColorScheme
|
|
||||||
plotattributes[k] = getColor(v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function replaceQwtAliases(plotattributes, s)
|
|
||||||
if haskey(_qwtAliases, plotattributes[s])
|
|
||||||
plotattributes[s] = _qwtAliases[plotattributes[s]]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
|
|
||||||
plotattributes = KW(kw)
|
|
||||||
st = plotattributes[:seriestype]
|
|
||||||
if st == :scatter
|
|
||||||
plotattributes[:seriestype] = :none
|
|
||||||
if plotattributes[:markershape] == :none
|
|
||||||
plotattributes[:markershape] = :circle
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif st in (:hline, :vline)
|
|
||||||
addLineMarker(plt, plotattributes)
|
|
||||||
plotattributes[:seriestype] = :none
|
|
||||||
plotattributes[:markershape] = :circle
|
|
||||||
plotattributes[:markersize] = 1
|
|
||||||
if st == :vline
|
|
||||||
plotattributes[:x], plotattributes[:y] = plotattributes[:y], plotattributes[:x]
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif !iscreating && st == :bar
|
|
||||||
plotattributes = barHack(; kw...)
|
|
||||||
elseif !iscreating && st == :histogram
|
|
||||||
plotattributes = barHack(; histogramHack(; kw...)...)
|
|
||||||
end
|
|
||||||
|
|
||||||
replaceQwtAliases(plotattributes, :seriestype)
|
|
||||||
replaceQwtAliases(plotattributes, :markershape)
|
|
||||||
|
|
||||||
for k in keys(plotattributes)
|
|
||||||
if haskey(_qwtAliases, k)
|
|
||||||
plotattributes[_qwtAliases[k]] = plotattributes[k]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
plotattributes[:x] = collect(plotattributes[:x])
|
|
||||||
plotattributes[:y] = collect(plotattributes[:y])
|
|
||||||
|
|
||||||
plotattributes
|
|
||||||
end
|
|
||||||
|
|
||||||
# function _create_plot(pkg::QwtBackend, plotattributes::KW)
|
|
||||||
function _create_backend_figure(plt::Plot{QwtBackend})
|
|
||||||
fixcolors(plt.attr)
|
|
||||||
dumpdict(plt.attr,"\n\n!!! plot")
|
|
||||||
o = Qwt.plot(zeros(0,0); plt.attr..., show=false)
|
|
||||||
# plt = Plot(o, pkg, 0, plotattributes, KW[])
|
|
||||||
# plt
|
|
||||||
end
|
|
||||||
|
|
||||||
# function _series_added(::QwtBackend, plt::Plot, plotattributes::KW)
|
|
||||||
function _series_added(plt::Plot{QwtBackend}, series::Series)
|
|
||||||
plotattributes = adjustQwtKeywords(plt, false; series.plotattributes...)
|
|
||||||
fixcolors(plotattributes)
|
|
||||||
dumpdict(plotattributes,"\n\n!!! plot!")
|
|
||||||
Qwt.oplot(plt.o; plotattributes...)
|
|
||||||
# push!(plt.seriesargs, plotattributes)
|
|
||||||
# plt
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
function updateLimsAndTicks(plt::Plot{QwtBackend}, plotattributes::KW, isx::Bool)
|
|
||||||
lims = get(plotattributes, isx ? :xlims : :ylims, nothing)
|
|
||||||
ticks = get(plotattributes, isx ? :xticks : :yticks, nothing)
|
|
||||||
w = plt.o.widget
|
|
||||||
axisid = Qwt.QWT.QwtPlot[isx ? :xBottom : :yLeft]
|
|
||||||
|
|
||||||
if typeof(lims) <: Union{Tuple,AVec} && length(lims) == 2
|
|
||||||
if isx
|
|
||||||
plt.o.autoscale_x = false
|
|
||||||
else
|
|
||||||
plt.o.autoscale_y = false
|
|
||||||
end
|
|
||||||
w[:setAxisScale](axisid, lims...)
|
|
||||||
end
|
|
||||||
|
|
||||||
if typeof(ticks) <: AbstractRange
|
|
||||||
if isx
|
|
||||||
plt.o.autoscale_x = false
|
|
||||||
else
|
|
||||||
plt.o.autoscale_y = false
|
|
||||||
end
|
|
||||||
w[:setAxisScale](axisid, float(minimum(ticks)), float(maximum(ticks)), float(step(ticks)))
|
|
||||||
elseif !(ticks in (nothing, :none, :auto))
|
|
||||||
@warn("Only Range types are supported for Qwt xticks/yticks. typeof(ticks)=$(typeof(ticks))")
|
|
||||||
end
|
|
||||||
|
|
||||||
# change the scale
|
|
||||||
scalesym = isx ? :xscale : :yscale
|
|
||||||
if haskey(plotattributes, scalesym)
|
|
||||||
scaletype = plotattributes[scalesym]
|
|
||||||
scaletype == :identity && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLinearScaleEngine())
|
|
||||||
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
|
|
||||||
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
|
|
||||||
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
|
|
||||||
scaletype in supported_scales() || @warn("Unsupported scale type: ", scaletype)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function _update_plot_object(plt::Plot{QwtBackend}, plotattributes::KW)
|
|
||||||
haskey(plotattributes, :title) && Qwt.title(plt.o, plotattributes[:title])
|
|
||||||
haskey(plotattributes, :xguide) && Qwt.xlabel(plt.o, plotattributes[:xguide])
|
|
||||||
haskey(plotattributes, :yguide) && Qwt.ylabel(plt.o, plotattributes[:yguide])
|
|
||||||
updateLimsAndTicks(plt, plotattributes, true)
|
|
||||||
updateLimsAndTicks(plt, plotattributes, false)
|
|
||||||
end
|
|
||||||
|
|
||||||
function _update_plot_pos_size(plt::AbstractPlot{QwtBackend}, plotattributes::KW)
|
|
||||||
haskey(plotattributes, :size) && Qwt.resizewidget(plt.o, plotattributes[:size]...)
|
|
||||||
haskey(plotattributes, :pos) && Qwt.movewidget(plt.o, plotattributes[:pos]...)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
# curve.setPen(Qt.QPen(Qt.QColor(color), linewidth, self.getLineStyle(linestyle)))
|
|
||||||
function addLineMarker(plt::Plot{QwtBackend}, plotattributes::KW)
|
|
||||||
for yi in plotattributes[:y]
|
|
||||||
marker = Qwt.QWT.QwtPlotMarker()
|
|
||||||
ishorizontal = (plotattributes[:seriestype] == :hline)
|
|
||||||
marker[:setLineStyle](ishorizontal ? 1 : 2)
|
|
||||||
marker[ishorizontal ? :setYValue : :setXValue](yi)
|
|
||||||
qcolor = Qwt.convertRGBToQColor(getColor(plotattributes[:linecolor]))
|
|
||||||
linestyle = plt.o.widget[:getLineStyle](string(plotattributes[:linestyle]))
|
|
||||||
marker[:setLinePen](Qwt.QT.QPen(qcolor, plotattributes[:linewidth], linestyle))
|
|
||||||
marker[:attach](plt.o.widget)
|
|
||||||
end
|
|
||||||
|
|
||||||
# marker[:setValue](x, y)
|
|
||||||
# marker[:setLabel](Qwt.QWT.QwtText(val))
|
|
||||||
# marker[:attach](plt.o.widget)
|
|
||||||
end
|
|
||||||
|
|
||||||
function createQwtAnnotation(plt::Plot, x, y, val::PlotText)
|
|
||||||
marker = Qwt.QWT.QwtPlotMarker()
|
|
||||||
marker[:setValue](x, y)
|
|
||||||
qwttext = Qwt.QWT.QwtText(val.str)
|
|
||||||
qwttext[:setFont](Qwt.QT.QFont(val.font.family, val.font.pointsize))
|
|
||||||
qwttext[:setColor](Qwt.convertRGBToQColor(getColor(val.font.color)))
|
|
||||||
marker[:setLabel](qwttext)
|
|
||||||
marker[:attach](plt.o.widget)
|
|
||||||
end
|
|
||||||
|
|
||||||
function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
|
|
||||||
marker = Qwt.QWT.QwtPlotMarker()
|
|
||||||
marker[:setValue](x, y)
|
|
||||||
marker[:setLabel](Qwt.QWT.QwtText(val))
|
|
||||||
marker[:attach](plt.o.widget)
|
|
||||||
end
|
|
||||||
|
|
||||||
function _add_annotations(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
|
||||||
for ann in anns
|
|
||||||
createQwtAnnotation(plt, ann...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
# accessors for x/y data
|
|
||||||
|
|
||||||
function getxy(plt::Plot{QwtBackend}, i::Int)
|
|
||||||
series = plt.o.lines[i]
|
|
||||||
series.x, series.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function setxy!(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
|
|
||||||
series = plt.o.lines[i]
|
|
||||||
series.x, series.y = xy
|
|
||||||
plt
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------
|
|
||||||
|
|
||||||
# -------------------------------
|
|
||||||
|
|
||||||
# # create the underlying object (each backend will do this differently)
|
|
||||||
# function _create_subplot(subplt::Subplot{QwtBackend}, isbefore::Bool)
|
|
||||||
# isbefore && return false
|
|
||||||
# i = 0
|
|
||||||
# rows = Any[]
|
|
||||||
# row = Any[]
|
|
||||||
# for (i,(r,c)) in enumerate(subplt.layout)
|
|
||||||
# push!(row, subplt.plts[i].o)
|
|
||||||
# if c == ncols(subplt.layout, r)
|
|
||||||
# push!(rows, Qwt.hsplitter(row...))
|
|
||||||
# row = Any[]
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# # for rowcnt in subplt.layout.rowcounts
|
|
||||||
# # push!(rows, Qwt.hsplitter([plt.o for plt in subplt.plts[(1:rowcnt) + i]]...))
|
|
||||||
# # i += rowcnt
|
|
||||||
# # end
|
|
||||||
# subplt.o = Qwt.vsplitter(rows...)
|
|
||||||
# # Qwt.resizewidget(subplt.o, getattr(subplt,1)[:size]...)
|
|
||||||
# # Qwt.moveToLastScreen(subplt.o) # hack so it goes to my center monitor... sorry
|
|
||||||
# true
|
|
||||||
# end
|
|
||||||
|
|
||||||
function _expand_limits(lims, plt::Plot{QwtBackend}, isx::Bool)
|
|
||||||
for series in plt.o.lines
|
|
||||||
_expand_limits(lims, isx ? series.x : series.y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function _remove_axis(plt::Plot{QwtBackend}, isx::Bool)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
function Base.show(io::IO, ::MIME"image/png", plt::Plot{QwtBackend})
|
|
||||||
Qwt.refresh(plt.o)
|
|
||||||
Qwt.savepng(plt.o, "/tmp/dfskjdhfkh.png")
|
|
||||||
write(io, readall("/tmp/dfskjdhfkh.png"))
|
|
||||||
end
|
|
||||||
|
|
||||||
# function Base.show(io::IO, ::MIME"image/png", subplt::Subplot{QwtBackend})
|
|
||||||
# for plt in subplt.plts
|
|
||||||
# Qwt.refresh(plt.o)
|
|
||||||
# end
|
|
||||||
# Qwt.savepng(subplt.o, "/tmp/dfskjdhfkh.png")
|
|
||||||
# write(io, readall("/tmp/dfskjdhfkh.png"))
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
function Base.display(::PlotsDisplay, plt::Plot{QwtBackend})
|
|
||||||
Qwt.refresh(plt.o)
|
|
||||||
Qwt.showwidget(plt.o)
|
|
||||||
end
|
|
||||||
|
|
||||||
# function Base.display(::PlotsDisplay, subplt::Subplot{QwtBackend})
|
|
||||||
# for plt in subplt.plts
|
|
||||||
# Qwt.refresh(plt.o)
|
|
||||||
# end
|
|
||||||
# Qwt.showwidget(subplt.o)
|
|
||||||
# end
|
|
||||||
@ -1,272 +0,0 @@
|
|||||||
|
|
||||||
# https://github.com/nolta/Winston.jl
|
|
||||||
|
|
||||||
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
|
|
||||||
|
|
||||||
supported_attrs(::WinstonBackend) = merge_with_base_supported([
|
|
||||||
:annotations,
|
|
||||||
:linecolor,
|
|
||||||
:fillrange,
|
|
||||||
:fillcolor,
|
|
||||||
:label,
|
|
||||||
:legend,
|
|
||||||
:seriescolor, :seriesalpha,
|
|
||||||
:linestyle,
|
|
||||||
:linewidth,
|
|
||||||
:markershape,
|
|
||||||
:markercolor,
|
|
||||||
:markersize,
|
|
||||||
:bins,
|
|
||||||
:title,
|
|
||||||
:window_title,
|
|
||||||
:guide, :lims, :scale,
|
|
||||||
])
|
|
||||||
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
|
|
||||||
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
|
||||||
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
|
||||||
supported_scales(::WinstonBackend) = [:identity, :log10]
|
|
||||||
is_subplot_supported(::WinstonBackend) = false
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function _initialize_backend(::WinstonBackend; kw...)
|
|
||||||
@eval begin
|
|
||||||
# ENV["WINSTON_OUTPUT"] = "gtk"
|
|
||||||
@warn("Winston is no longer supported... many features will likely be broken.")
|
|
||||||
import Winston, Gtk
|
|
||||||
export Winston, Gtk
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
## dictionaries for conversion of Plots.jl names to Winston ones.
|
|
||||||
const winston_linestyle = KW(:solid=>"solid",
|
|
||||||
:dash=>"dash",
|
|
||||||
:dot=>"dotted",
|
|
||||||
:dashdot=>"dotdashed"
|
|
||||||
)
|
|
||||||
|
|
||||||
const winston_marker = KW(:none=>".",
|
|
||||||
:rect => "square",
|
|
||||||
:circle=>"circle",
|
|
||||||
:diamond=>"diamond",
|
|
||||||
:utriangle=>"triangle",
|
|
||||||
:dtriangle=>"down-triangle",
|
|
||||||
:cross => "plus",
|
|
||||||
:xcross => "cross",
|
|
||||||
:star5 => "asterisk"
|
|
||||||
)
|
|
||||||
|
|
||||||
function _before_update(plt::Plot{WinstonBackend})
|
|
||||||
Winston.ghf(plt.o)
|
|
||||||
end
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function _create_backend_figure(plt::Plot{WinstonBackend})
|
|
||||||
Winston.FramedPlot(
|
|
||||||
title = plt.attr[:title],
|
|
||||||
xlabel = plt.attr[:xguide],
|
|
||||||
ylabel = plt.attr[:yguide]
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
copy_remove(plotattributes::KW, s::Symbol) = delete!(copy(plotattributes), s)
|
|
||||||
|
|
||||||
function addRegressionLineWinston(plotattributes::KW, wplt)
|
|
||||||
xs, ys = regressionXY(plotattributes[:x], plotattributes[:y])
|
|
||||||
Winston.add(wplt, Winston.Curve(xs, ys, kind="dotted"))
|
|
||||||
end
|
|
||||||
|
|
||||||
function getWinstonItems(plt::Plot)
|
|
||||||
if isa(plt.o, Winston.FramedPlot)
|
|
||||||
wplt = plt.o
|
|
||||||
window, canvas = nothing, nothing
|
|
||||||
else
|
|
||||||
window, canvas, wplt = plt.o
|
|
||||||
end
|
|
||||||
window, canvas, wplt
|
|
||||||
end
|
|
||||||
|
|
||||||
function _series_added(plt::Plot{WinstonBackend}, series::Series)
|
|
||||||
plotattributes = series.plotattributes
|
|
||||||
window, canvas, wplt = getWinstonItems(plt)
|
|
||||||
|
|
||||||
# until we call it normally, do the hack
|
|
||||||
if plotattributes[:seriestype] == :bar
|
|
||||||
plotattributes = barHack(;plotattributes...)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
e = KW()
|
|
||||||
e[:color] = getColor(plotattributes[:linecolor])
|
|
||||||
e[:linewidth] = plotattributes[:linewidth]
|
|
||||||
e[:kind] = winston_linestyle[plotattributes[:linestyle]]
|
|
||||||
e[:symbolkind] = winston_marker[plotattributes[:markershape]]
|
|
||||||
# markercolor # same choices as `color`, or :match will set the color to be the same as `color`
|
|
||||||
e[:symbolsize] = plotattributes[:markersize] / 5
|
|
||||||
|
|
||||||
# pos # (Int,Int), move the enclosing window to this position
|
|
||||||
# screen # Integer, move enclosing window to this screen number (for multiscreen desktops)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## lintype :path, :step, :stepinverted, :sticks, :dots, :none, :histogram2d, :hexbin, :histogram, :bar
|
|
||||||
if plotattributes[:seriestype] == :none
|
|
||||||
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
|
|
||||||
|
|
||||||
elseif plotattributes[:seriestype] == :path
|
|
||||||
x, y = plotattributes[:x], plotattributes[:y]
|
|
||||||
Winston.add(wplt, Winston.Curve(x, y; e...))
|
|
||||||
|
|
||||||
fillrange = plotattributes[:fillrange]
|
|
||||||
if fillrange != nothing
|
|
||||||
if isa(fillrange, AbstractVector)
|
|
||||||
y2 = fillrange
|
|
||||||
else
|
|
||||||
y2 = Float64[fillrange for yi in y]
|
|
||||||
end
|
|
||||||
Winston.add(wplt, Winston.FillBetween(x, y, x, y2, fillcolor=getColor(plotattributes[:fillcolor])))
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif plotattributes[:seriestype] == :scatter
|
|
||||||
if plotattributes[:markershape] == :none
|
|
||||||
plotattributes[:markershape] = :circle
|
|
||||||
end
|
|
||||||
|
|
||||||
# elseif plotattributes[:seriestype] == :step
|
|
||||||
# fn = Winston.XXX
|
|
||||||
|
|
||||||
# elseif plotattributes[:seriestype] == :stepinverted
|
|
||||||
# fn = Winston.XXX
|
|
||||||
|
|
||||||
elseif plotattributes[:seriestype] == :sticks
|
|
||||||
Winston.add(wplt, Winston.Stems(plotattributes[:x], plotattributes[:y]; e...))
|
|
||||||
|
|
||||||
# elseif plotattributes[:seriestype] == :dots
|
|
||||||
# fn = Winston.XXX
|
|
||||||
|
|
||||||
# elseif plotattributes[:seriestype] == :histogram2d
|
|
||||||
# fn = Winston.XXX
|
|
||||||
|
|
||||||
# elseif plotattributes[:seriestype] == :hexbin
|
|
||||||
# fn = Winston.XXX
|
|
||||||
|
|
||||||
elseif plotattributes[:seriestype] == :histogram
|
|
||||||
hst = hist(plotattributes[:y], plotattributes[:bins])
|
|
||||||
Winston.add(wplt, Winston.Histogram(hst...; copy_remove(e, :bins)...))
|
|
||||||
|
|
||||||
# elseif plotattributes[:seriestype] == :bar
|
|
||||||
# # fn = Winston.XXX
|
|
||||||
|
|
||||||
else
|
|
||||||
error("seriestype $(plotattributes[:seriestype]) not supported by Winston.")
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# markershape
|
|
||||||
if plotattributes[:markershape] != :none
|
|
||||||
Winston.add(wplt, Winston.Points(plotattributes[:x], plotattributes[:y]; copy_remove(e, :kind)..., color=getColor(plotattributes[:markercolor])))
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# optionally add a regression line
|
|
||||||
plotattributes[:smooth] && plotattributes[:seriestype] != :histogram && addRegressionLineWinston(plotattributes, wplt)
|
|
||||||
|
|
||||||
# push!(plt.seriesargs, plotattributes)
|
|
||||||
# plt
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
const _winstonNames = KW(
|
|
||||||
:xlims => :xrange,
|
|
||||||
:ylims => :yrange,
|
|
||||||
:xscale => :xlog,
|
|
||||||
:yscale => :ylog,
|
|
||||||
)
|
|
||||||
|
|
||||||
function _update_plot_object(plt::Plot{WinstonBackend}, plotattributes::KW)
|
|
||||||
window, canvas, wplt = getWinstonItems(plt)
|
|
||||||
for k in (:xguide, :yguide, :title, :xlims, :ylims)
|
|
||||||
if haskey(plotattributes, k)
|
|
||||||
Winston.setattr(wplt, string(get(_winstonNames, k, k)), plotattributes[k])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for k in (:xscale, :yscale)
|
|
||||||
if haskey(plotattributes, k)
|
|
||||||
islogscale = plotattributes[k] == :log10
|
|
||||||
Winston.setattr(wplt, (k == :xscale ? :xlog : :ylog), islogscale)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::AbstractString)
|
|
||||||
Winston.text(x, y, val)
|
|
||||||
end
|
|
||||||
|
|
||||||
function _add_annotations(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
|
|
||||||
for ann in anns
|
|
||||||
createWinstonAnnotationObject(plt, ann...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
# function _create_subplot(subplt::Subplot{WinstonBackend}, isbefore::Bool)
|
|
||||||
# # TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
|
|
||||||
# end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
|
||||||
|
|
||||||
function addWinstonLegend(plt::Plot, wplt)
|
|
||||||
if plt.attr[:legend] != :none
|
|
||||||
Winston.legend(wplt, [sd[:label] for sd in plt.seriesargs])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Base.show(io::IO, ::MIME"image/png", plt::AbstractPlot{WinstonBackend})
|
|
||||||
window, canvas, wplt = getWinstonItems(plt)
|
|
||||||
addWinstonLegend(plt, wplt)
|
|
||||||
show(io, "image/png", wplt)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function Base.display(::PlotsDisplay, plt::Plot{WinstonBackend})
|
|
||||||
|
|
||||||
window, canvas, wplt = getWinstonItems(plt)
|
|
||||||
|
|
||||||
if window == nothing
|
|
||||||
if Winston.output_surface != :gtk
|
|
||||||
error("Gtk is the only supported display for Winston in Plots. Set `output_surface = gtk` in src/Winston.ini")
|
|
||||||
end
|
|
||||||
# initialize window
|
|
||||||
w,h = plt.attr[:size]
|
|
||||||
canvas = Gtk.GtkCanvasLeaf()
|
|
||||||
window = Gtk.GtkWindowLeaf(canvas, plt.attr[:window_title], w, h)
|
|
||||||
plt.o = (window, canvas, wplt)
|
|
||||||
end
|
|
||||||
|
|
||||||
addWinstonLegend(plt, wplt)
|
|
||||||
|
|
||||||
Winston.display(canvas, wplt)
|
|
||||||
Gtk.showall(window)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# function Base.display(::PlotsDisplay, subplt::Subplot{WinstonBackend})
|
|
||||||
# # TODO: display/show the Subplot object
|
|
||||||
# end
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,415 +0,0 @@
|
|||||||
|
|
||||||
abstract type ColorScheme end
|
|
||||||
|
|
||||||
Base.getindex(scheme::ColorScheme, i::Integer) = getColor(scheme, i)
|
|
||||||
|
|
||||||
export
|
|
||||||
cgrad
|
|
||||||
|
|
||||||
cgrad() = default_gradient()
|
|
||||||
|
|
||||||
function cgrad(arg, values = nothing; alpha = nothing, scale = :identity)
|
|
||||||
colors = ColorGradient(arg, alpha=alpha).colors
|
|
||||||
values = if values != nothing
|
|
||||||
values
|
|
||||||
elseif scale in (:log, :log10)
|
|
||||||
log10(range(1, stop=10, length=30))
|
|
||||||
elseif scale == :log2
|
|
||||||
log2(range(1, stop=2, length=30))
|
|
||||||
elseif scale == :ln
|
|
||||||
log(range(1, stop=pi, length=30))
|
|
||||||
elseif scale in (:exp, :exp10)
|
|
||||||
(exp10(range(0, stop=1, length=30)) - 1) / 9
|
|
||||||
else
|
|
||||||
range(0, stop=1, length=length(colors))
|
|
||||||
end
|
|
||||||
ColorGradient(colors, values)
|
|
||||||
end
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
getColor(scheme::ColorScheme) = getColor(scheme, 1)
|
|
||||||
getColorVector(scheme::ColorScheme) = [getColor(scheme)]
|
|
||||||
|
|
||||||
colorscheme(scheme::ColorScheme) = scheme
|
|
||||||
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
|
|
||||||
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
|
|
||||||
colorscheme(s::Symbol, vals::AVec{T}; kw...) where {T<:Real} = ColorGradient(s, vals; kw...)
|
|
||||||
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
|
|
||||||
colorscheme(cs::AVec{T}; kw...) where {T<:Colorant} = ColorGradient(cs; kw...)
|
|
||||||
colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
|
|
||||||
colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
|
|
||||||
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
|
|
||||||
colorscheme(c::Colorant; kw...) = ColorWrapper(c; kw...)
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
convertColor(c::AbstractString) = parse(Colorant, c)
|
|
||||||
convertColor(c::Symbol) = parse(Colorant, string(c))
|
|
||||||
convertColor(c::Colorant) = c
|
|
||||||
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
|
|
||||||
convertColor(c::ColorScheme) = c
|
|
||||||
convertColor(v::Nothing) = RGBA(0,0,0,0)
|
|
||||||
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
|
|
||||||
|
|
||||||
function convertColor(c, α::Real)
|
|
||||||
c = convertColor(c)
|
|
||||||
RGBA(RGB(getColor(c)), α)
|
|
||||||
end
|
|
||||||
convertColor(cs::AVec, α::Real) = map(c -> convertColor(c, α), cs)
|
|
||||||
convertColor(c, α::Nothing) = convertColor(c)
|
|
||||||
|
|
||||||
# backup... try to convert
|
|
||||||
getColor(c) = convertColor(c)
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
function darken(c, v=0.1)
|
|
||||||
rgba = convert(RGBA, c)
|
|
||||||
r = max(0, min(rgba.r - v, 1))
|
|
||||||
g = max(0, min(rgba.g - v, 1))
|
|
||||||
b = max(0, min(rgba.b - v, 1))
|
|
||||||
RGBA(r,g,b,rgba.alpha)
|
|
||||||
end
|
|
||||||
function lighten(c, v=0.3)
|
|
||||||
darken(c, -v)
|
|
||||||
end
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
const _rainbowColors = [colorant"purple", colorant"blue", colorant"green", colorant"orange", colorant"red"]
|
|
||||||
const _testColors = [colorant"darkblue", colorant"blueviolet", colorant"darkcyan",colorant"green",
|
|
||||||
darken(colorant"yellow",0.3), colorant"orange", darken(colorant"red",0.2)]
|
|
||||||
|
|
||||||
const _gradients = KW(
|
|
||||||
:blues => [colorant"lightblue", colorant"darkblue"],
|
|
||||||
:reds => [colorant"lightpink", colorant"darkred"],
|
|
||||||
:greens => [colorant"lightgreen", colorant"darkgreen"],
|
|
||||||
:redsblues => [colorant"darkred", RGB(0.8,0.85,0.8), colorant"darkblue"],
|
|
||||||
:bluesreds => [colorant"darkblue", RGB(0.8,0.85,0.8), colorant"darkred"],
|
|
||||||
:heat => [colorant"lightyellow", colorant"orange", colorant"darkred"],
|
|
||||||
:grays => [RGB(.95,.95,.95),RGB(.05,.05,.05)],
|
|
||||||
:rainbow => _rainbowColors,
|
|
||||||
:lightrainbow => map(lighten, _rainbowColors),
|
|
||||||
:darkrainbow => map(darken, _rainbowColors),
|
|
||||||
:darktest => _testColors,
|
|
||||||
:lighttest => map(c -> lighten(c, 0.3), _testColors),
|
|
||||||
)
|
|
||||||
|
|
||||||
function register_gradient_colors(name::Symbol, colors::AVec{C}) where C<:Colorant
|
|
||||||
_gradients[name] = colors
|
|
||||||
end
|
|
||||||
|
|
||||||
include("color_gradients.jl")
|
|
||||||
|
|
||||||
default_gradient() = ColorGradient(:inferno)
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
|
|
||||||
struct ColorGradient <: ColorScheme
|
|
||||||
colors::Vector
|
|
||||||
values::Vector
|
|
||||||
|
|
||||||
function ColorGradient(cs::AVec, vals::AVec{S} = range(0, stop=1, length=length(cs)); alpha = nothing) where S<:Real
|
|
||||||
if length(cs) == length(vals)
|
|
||||||
return new(convertColor(cs,alpha), collect(vals))
|
|
||||||
end
|
|
||||||
|
|
||||||
# # otherwise interpolate evenly between the minval and maxval
|
|
||||||
# minval, maxval = minimum(vals), maximum(vals)
|
|
||||||
# vs = Float64[interpolate(minval, maxval, w) for w in range(0, stop = 1, length = length(cs))]
|
|
||||||
# new(convertColor(cs,alpha), vs)
|
|
||||||
|
|
||||||
# interpolate the colors for each value
|
|
||||||
vals = merge(range(0, stop=1, length=length(cs)), vals)
|
|
||||||
grad = ColorGradient(cs)
|
|
||||||
cs = [getColorZ(grad, z) for z in range(0, stop=1, length=length(vals))]
|
|
||||||
new(convertColor(cs, alpha), vals)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Base.getindex(cs::ColorGradient, i::Integer) = getColor(cs, i)
|
|
||||||
Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
|
|
||||||
|
|
||||||
|
|
||||||
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values
|
|
||||||
function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
|
|
||||||
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
|
|
||||||
cs = _gradients[s]
|
|
||||||
if vals == 0:0
|
|
||||||
vals = range(0, stop=1, length=length(cs))
|
|
||||||
end
|
|
||||||
ColorGradient(cs, vals; kw...)
|
|
||||||
end
|
|
||||||
|
|
||||||
# function ColorGradient{T<:Real}(cs::AVec, vals::AVec{T} = range(0, stop = 1, length = length(cs)); kw...)
|
|
||||||
# ColorGradient(map(convertColor, cs), vals; kw...)
|
|
||||||
# end
|
|
||||||
|
|
||||||
function ColorGradient(grad::ColorGradient; alpha = nothing)
|
|
||||||
ColorGradient(convertColor(grad.colors, alpha), grad.values)
|
|
||||||
end
|
|
||||||
|
|
||||||
# anything else just gets the default gradient
|
|
||||||
function ColorGradient(cw; alpha=nothing)
|
|
||||||
ColorGradient(default_gradient(), alpha=alpha)
|
|
||||||
end
|
|
||||||
|
|
||||||
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
|
|
||||||
|
|
||||||
function getColorZ(gradient::ColorGradient, z::Real)
|
|
||||||
cs = gradient.colors
|
|
||||||
vs = gradient.values
|
|
||||||
n = length(cs)
|
|
||||||
@assert n > 0 && n == length(vs)
|
|
||||||
|
|
||||||
# can we just return the first color?
|
|
||||||
if z <= vs[1] || n == 1
|
|
||||||
return cs[1]
|
|
||||||
end
|
|
||||||
|
|
||||||
# find the bounding colors and interpolate
|
|
||||||
for i in 2:n
|
|
||||||
if z <= vs[i]
|
|
||||||
return interpolate_rgb(cs[i-1], cs[i], (z - vs[i-1]) / (vs[i] - vs[i-1]))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# if we get here, return the last color
|
|
||||||
cs[end]
|
|
||||||
end
|
|
||||||
|
|
||||||
getColorVector(gradient::ColorGradient) = gradient.colors
|
|
||||||
|
|
||||||
# for 0.3
|
|
||||||
Colors.RGBA(c::Colorant) = RGBA(red(c), green(c), blue(c), alpha(c))
|
|
||||||
Colors.RGB(c::Colorant) = RGB(red(c), green(c), blue(c))
|
|
||||||
|
|
||||||
function interpolate_rgb(c1::Colorant, c2::Colorant, w::Real)
|
|
||||||
rgb1 = RGBA(c1)
|
|
||||||
rgb2 = RGBA(c2)
|
|
||||||
r = interpolate(rgb1.r, rgb2.r, w)
|
|
||||||
g = interpolate(rgb1.g, rgb2.g, w)
|
|
||||||
b = interpolate(rgb1.b, rgb2.b, w)
|
|
||||||
a = interpolate(rgb1.alpha, rgb2.alpha, w)
|
|
||||||
RGBA(r, g, b, a)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function interpolate(v1::Real, v2::Real, w::Real)
|
|
||||||
(1-w) * v1 + w * v2
|
|
||||||
end
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
"Wraps a function, taking an index and returning a Colorant"
|
|
||||||
struct ColorFunction <: ColorScheme
|
|
||||||
f::Function
|
|
||||||
end
|
|
||||||
|
|
||||||
getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
"Wraps a function, taking an z-value and returning a Colorant"
|
|
||||||
struct ColorZFunction <: ColorScheme
|
|
||||||
f::Function
|
|
||||||
end
|
|
||||||
|
|
||||||
getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
"Wraps a vector of colors... may be vector of Symbol/String/Colorant"
|
|
||||||
struct ColorVector <: ColorScheme
|
|
||||||
v::Vector{Colorant}
|
|
||||||
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
|
|
||||||
end
|
|
||||||
|
|
||||||
getColor(scheme::ColorVector, idx::Int) = convertColor(scheme.v[mod1(idx, length(scheme.v))])
|
|
||||||
getColorVector(scheme::ColorVector) = scheme.v
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
"Wraps a single color"
|
|
||||||
struct ColorWrapper <: ColorScheme
|
|
||||||
c::RGBA
|
|
||||||
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
|
|
||||||
end
|
|
||||||
|
|
||||||
ColorWrapper(s::Symbol; alpha = nothing) = ColorWrapper(convertColor(parse(Colorant, s), alpha))
|
|
||||||
|
|
||||||
getColor(scheme::ColorWrapper, idx::Int) = scheme.c
|
|
||||||
getColorZ(scheme::ColorWrapper, z::Real) = scheme.c
|
|
||||||
convertColor(c::ColorWrapper, α::Nothing) = c.c
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
isbackgrounddark(bgcolor::Color) = Lab(bgcolor).l < 0.5
|
|
||||||
|
|
||||||
# move closer to lighter/darker depending on background value
|
|
||||||
function adjustAway(val, bgval, vmin=0., vmax=100.)
|
|
||||||
if bgval < 0.5 * (vmax+vmin)
|
|
||||||
tmp = max(val, bgval)
|
|
||||||
return 0.5 * (tmp + max(tmp, vmax))
|
|
||||||
else
|
|
||||||
tmp = min(val, bgval)
|
|
||||||
return 0.5 * (tmp + min(tmp, vmin))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# borrowed from http://stackoverflow.com/a/1855903:
|
|
||||||
lightnessLevel(c::Colorant) = 0.299 * red(c) + 0.587 * green(c) + 0.114 * blue(c)
|
|
||||||
|
|
||||||
isdark(c::Colorant) = lightnessLevel(c) < 0.5
|
|
||||||
islight(c::Colorant) = !isdark(c)
|
|
||||||
|
|
||||||
function convertHexToRGB(h::Unsigned)
|
|
||||||
mask = 0x0000FF
|
|
||||||
RGB([(x & mask) / 0xFF for x in (h >> 16, h >> 8, h)]...)
|
|
||||||
end
|
|
||||||
|
|
||||||
# note: I found this list of hex values in a comment by Tatarize here: http://stackoverflow.com/a/12224359
|
|
||||||
const _masterColorList = [
|
|
||||||
0xFFFFFF, 0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0x01FFFE, 0xFFA6FE, 0xFFDB66, 0x006401, 0x010067,
|
|
||||||
0x95003A, 0x007DB5, 0xFF00F6, 0xFFEEE8, 0x774D00, 0x90FB92, 0x0076FF, 0xD5FF00, 0xFF937E, 0x6A826C,
|
|
||||||
0xFF029D, 0xFE8900, 0x7A4782, 0x7E2DD2, 0x85A900, 0xFF0056, 0xA42400, 0x00AE7E, 0x683D3B, 0xBDC6FF,
|
|
||||||
0x263400, 0xBDD393, 0x00B917, 0x9E008E, 0x001544, 0xC28C9F, 0xFF74A3, 0x01D0FF, 0x004754, 0xE56FFE,
|
|
||||||
0x788231, 0x0E4CA1, 0x91D0CB, 0xBE9970, 0x968AE8, 0xBB8800, 0x43002C, 0xDEFF74, 0x00FFC6, 0xFFE502,
|
|
||||||
0x620E00, 0x008F9C, 0x98FF52, 0x7544B1, 0xB500FF, 0x00FF78, 0xFF6E41, 0x005F39, 0x6B6882, 0x5FAD4E,
|
|
||||||
0xA75740, 0xA5FFD2, 0xFFB167, 0x009BFF, 0xE85EBE
|
|
||||||
]
|
|
||||||
const _allColors = map(convertHexToRGB, _masterColorList)
|
|
||||||
const _darkColors = filter(isdark, _allColors)
|
|
||||||
const _lightColors = filter(islight, _allColors)
|
|
||||||
const _sortedColorsForDarkBackground = vcat(_lightColors, reverse(_darkColors[2:end]))
|
|
||||||
const _sortedColorsForLightBackground = vcat(_darkColors, reverse(_lightColors[2:end]))
|
|
||||||
|
|
||||||
const _defaultNumColors = 17
|
|
||||||
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
|
|
||||||
# Methods to automatically generate gradients for color selection based on
|
|
||||||
# background color and a short list of seed colors
|
|
||||||
|
|
||||||
# here are some magic constants that could be changed if you really want
|
|
||||||
const _lightness_darkbg = [80.0]
|
|
||||||
const _lightness_lightbg = [60.0]
|
|
||||||
const _lch_c_const = [60]
|
|
||||||
|
|
||||||
function adjust_lch(color, l, c)
|
|
||||||
lch = convert(LCHab, color)
|
|
||||||
convert(RGB, LCHab(l, c, lch.h))
|
|
||||||
end
|
|
||||||
|
|
||||||
function lightness_from_background(bgcolor)
|
|
||||||
bglight = convert(LCHab, bgcolor).l
|
|
||||||
bglight < 50.0 ? _lightness_darkbg[1] : _lightness_lightbg[1]
|
|
||||||
end
|
|
||||||
|
|
||||||
function gradient_from_list(cs)
|
|
||||||
zvalues = Plots.get_zvalues(length(cs))
|
|
||||||
indices = sortperm(zvalues)
|
|
||||||
sorted_colors = map(RGBA, cs[indices])
|
|
||||||
sorted_zvalues = zvalues[indices]
|
|
||||||
ColorGradient(sorted_colors, sorted_zvalues)
|
|
||||||
end
|
|
||||||
|
|
||||||
function generate_colorgradient(bgcolor = colorant"white";
|
|
||||||
color_bases = color_bases=[colorant"steelblue",colorant"orangered"],
|
|
||||||
lightness = lightness_from_background(bgcolor),
|
|
||||||
chroma = _lch_c_const[1],
|
|
||||||
n = _defaultNumColors)
|
|
||||||
seed_colors = vcat(bgcolor, map(c -> adjust_lch(c, lightness, chroma), color_bases))
|
|
||||||
colors = distinguishable_colors(n,
|
|
||||||
seed_colors,
|
|
||||||
lchoices=Float64[lightness],
|
|
||||||
cchoices=Float64[chroma],
|
|
||||||
hchoices=range(0, stop=340, length=20)
|
|
||||||
)[2:end]
|
|
||||||
gradient_from_list(colors)
|
|
||||||
end
|
|
||||||
|
|
||||||
function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer)
|
|
||||||
grad = if palette == :auto
|
|
||||||
generate_colorgradient(bgcolor)
|
|
||||||
else
|
|
||||||
ColorGradient(palette)
|
|
||||||
end
|
|
||||||
zrng = get_zvalues(numcolors)
|
|
||||||
RGBA[getColorZ(grad, z) for z in zrng]
|
|
||||||
end
|
|
||||||
|
|
||||||
function get_color_palette(palette::Vector{C},
|
|
||||||
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) where C<:Colorant
|
|
||||||
palette
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function getpctrange(n::Int)
|
|
||||||
n > 0 || error()
|
|
||||||
n == 1 && return zeros(1)
|
|
||||||
zs = [0.0, 1.0]
|
|
||||||
for i in 3:n
|
|
||||||
sorted = sort(zs)
|
|
||||||
diffs = diff(sorted)
|
|
||||||
widestj = 0
|
|
||||||
widest = 0.0
|
|
||||||
for (j,d) in enumerate(diffs)
|
|
||||||
if d > widest
|
|
||||||
widest = d
|
|
||||||
widestj = j
|
|
||||||
end
|
|
||||||
end
|
|
||||||
push!(zs, sorted[widestj] + 0.5 * diffs[widestj])
|
|
||||||
end
|
|
||||||
zs
|
|
||||||
end
|
|
||||||
|
|
||||||
function get_zvalues(n::Int)
|
|
||||||
offsets = getpctrange(ceil(Int,n/4)+1)/4
|
|
||||||
offsets = vcat(offsets[1], offsets[3:end])
|
|
||||||
zvalues = Float64[]
|
|
||||||
for offset in offsets
|
|
||||||
append!(zvalues, offset + [0.0, 0.5, 0.25, 0.75])
|
|
||||||
end
|
|
||||||
vcat(zvalues[1], 1.0, zvalues[2:n-1])
|
|
||||||
end
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
make255(x) = round(Int, 255 * x)
|
|
||||||
|
|
||||||
function webcolor(c::Color)
|
|
||||||
@sprintf("rgb(%d, %d, %d)", [make255(f(c)) for f in [red,green,blue]]...)
|
|
||||||
end
|
|
||||||
function webcolor(c::TransparentColor)
|
|
||||||
@sprintf("rgba(%d, %d, %d, %1.3f)", [make255(f(c)) for f in [red,green,blue]]..., alpha(c))
|
|
||||||
end
|
|
||||||
webcolor(cs::ColorScheme) = webcolor(getColor(cs))
|
|
||||||
webcolor(c) = webcolor(convertColor(c))
|
|
||||||
webcolor(c, α) = webcolor(convertColor(getColor(c), α))
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# 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 ColorScheme
|
|
||||||
colorscheme(c)
|
|
||||||
end
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
# TODO:
|
|
||||||
"""
|
|
||||||
- load Contours.jl similar to DataFrames
|
|
||||||
- method to build grid from x/y/z vectors
|
|
||||||
- method to wrap contours creation
|
|
||||||
- method to plot contours as custom shapes (TODO: create Stroke and Fill types and add markerstroke/markerfill args)
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# # ----------------------------------------------------------
|
|
||||||
# # ----------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
# immutable Vertex
|
|
||||||
# x::Float64
|
|
||||||
# y::Float64
|
|
||||||
# z::Float64
|
|
||||||
# end
|
|
||||||
|
|
||||||
# immutable Edge
|
|
||||||
# v::Vertex
|
|
||||||
# u::Vertex
|
|
||||||
# end
|
|
||||||
|
|
||||||
# # ----------------------------------------------------------
|
|
||||||
|
|
||||||
# # one rectangle's z-values and the center vertex
|
|
||||||
# # z is ordered: topleft, topright, bottomright, bottomleft
|
|
||||||
# immutable GridRect
|
|
||||||
# z::Vector{Float64}
|
|
||||||
# center::Vertex
|
|
||||||
# data::Vector{Vertex}
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# type Grid
|
|
||||||
# xs::Vector{Float64}
|
|
||||||
# ys::Vector{Float64}
|
|
||||||
# rects::Matrix{GridRect}
|
|
||||||
# end
|
|
||||||
|
|
||||||
# function splitDataEvenly(v::AbstractVector{Float64}, n::Int)
|
|
||||||
# vs = sort(v)
|
|
||||||
|
|
||||||
# end
|
|
||||||
|
|
||||||
# # the goal here is to create the vertical and horizontal partitions
|
|
||||||
# # which define the grid, so that the data is somewhat evenly split
|
|
||||||
# function bucketData(x, y, z)
|
|
||||||
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
# function buildGrid(x, y, z)
|
|
||||||
# # create
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
const FuncOrFuncs = Union{Function, AVec{Function}}
|
|
||||||
|
|
||||||
all3D(plotattributes::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(plotattributes, :seriestype, :none))
|
|
||||||
|
|
||||||
# missing
|
|
||||||
convertToAnyVector(v::Nothing, plotattributes::KW) = Any[nothing], nothing
|
|
||||||
|
|
||||||
# fixed number of blank series
|
|
||||||
convertToAnyVector(n::Integer, plotattributes::KW) = Any[zeros(0) for i in 1:n], nothing
|
|
||||||
|
|
||||||
# numeric vector
|
|
||||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:Number} = Any[v], nothing
|
|
||||||
|
|
||||||
# string vector
|
|
||||||
convertToAnyVector(v::AVec{T}, plotattributes::KW) where {T<:AbstractString} = Any[v], nothing
|
|
||||||
|
|
||||||
function convertToAnyVector(v::AMat, plotattributes::KW)
|
|
||||||
if all3D(plotattributes)
|
|
||||||
Any[Surface(v)]
|
|
||||||
else
|
|
||||||
Any[v[:,i] for i in 1:size(v,2)]
|
|
||||||
end, nothing
|
|
||||||
end
|
|
||||||
|
|
||||||
# function
|
|
||||||
convertToAnyVector(f::Function, plotattributes::KW) = Any[f], nothing
|
|
||||||
|
|
||||||
# surface
|
|
||||||
convertToAnyVector(s::Surface, plotattributes::KW) = Any[s], nothing
|
|
||||||
|
|
||||||
# # vector of OHLC
|
|
||||||
# convertToAnyVector(v::AVec{OHLC}, plotattributes::KW) = Any[v], nothing
|
|
||||||
|
|
||||||
# dates
|
|
||||||
convertToAnyVector(dts::AVec{D}, plotattributes::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
|
|
||||||
|
|
||||||
# list of things (maybe other vectors, functions, or something else)
|
|
||||||
function convertToAnyVector(v::AVec, plotattributes::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, plotattributes)[1] for vi in v]...), nothing
|
|
||||||
# Any[vi for vi in v], nothing
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
convertToAnyVector(t::Tuple, plotattributes::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::Nothing, y::Nothing, z) = 1:size(z,1)
|
|
||||||
compute_x(x::Nothing, 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::Nothing, y::Nothing, 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::Nothing) = 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::Nothing, y::FuncOrFuncs, z) = error("If you want to plot the function `$y`, you need to define the x values!")
|
|
||||||
compute_xyz(x::Nothing, y::Nothing, z::FuncOrFuncs) = error("If you want to plot the function `$z`, you need to define x and y values!")
|
|
||||||
compute_xyz(x::Nothing, y::Nothing, z::Nothing) = error("x/y/z are all nothing!")
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
|
||||||
@ -19,7 +19,6 @@ function __init__()
|
|||||||
pushdisplay(PlotsDisplay())
|
pushdisplay(PlotsDisplay())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@require GLVisualize = "4086de5b-f4b6-55f3-abb0-b8c73827585f" include(joinpath(@__DIR__, "backends", "glvisualize.jl"))
|
|
||||||
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl"))
|
@require HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" include(joinpath(@__DIR__, "backends", "hdf5.jl"))
|
||||||
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl"))
|
@require InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d" include(joinpath(@__DIR__, "backends", "inspectdr.jl"))
|
||||||
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl"))
|
@require PGFPlots = "3b7a836e-365b-5785-a47d-02c71176b4aa" include(joinpath(@__DIR__, "backends", "pgfplots.jl"))
|
||||||
|
|||||||
@ -156,7 +156,6 @@ end
|
|||||||
const _best_html_output_type = KW(
|
const _best_html_output_type = KW(
|
||||||
:pyplot => :png,
|
:pyplot => :png,
|
||||||
:unicodeplots => :txt,
|
:unicodeplots => :txt,
|
||||||
:glvisualize => :png,
|
|
||||||
:plotlyjs => :html,
|
:plotlyjs => :html,
|
||||||
:plotly => :html
|
:plotly => :html
|
||||||
)
|
)
|
||||||
|
|||||||
@ -738,7 +738,7 @@ function with(f::Function, args...; kw...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# # TODO: generalize this strategy to allow args as much as possible
|
# # TODO: generalize this strategy to allow args as much as possible
|
||||||
# # as in: with(:gadfly, :scatter, :legend, :grid) do; ...; end
|
# # as in: with(:gr, :scatter, :legend, :grid) do; ...; end
|
||||||
# # TODO: can we generalize this enough to also do something similar in the plot commands??
|
# # TODO: can we generalize this enough to also do something similar in the plot commands??
|
||||||
|
|
||||||
# k = :seriestype
|
# k = :seriestype
|
||||||
|
|||||||
@ -87,16 +87,6 @@ end
|
|||||||
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], tol=img_tol)
|
# # @static Sys.islinux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], tol=img_tol)
|
||||||
# end
|
# end
|
||||||
|
|
||||||
|
|
||||||
# @testset "Immerse" begin
|
|
||||||
# @test immerse() == Plots.ImmerseBackend()
|
|
||||||
# @test backend() == Plots.ImmerseBackend()
|
|
||||||
#
|
|
||||||
# # as long as we can plot anything without error, it should be the same as Gadfly
|
|
||||||
# image_comparison_facts(:immerse, only=[1], tol=img_tol)
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
# @testset "PlotlyJS" begin
|
# @testset "PlotlyJS" begin
|
||||||
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
# @test plotlyjs() == Plots.PlotlyJSBackend()
|
||||||
# @test backend() == Plots.PlotlyJSBackend()
|
# @test backend() == Plots.PlotlyJSBackend()
|
||||||
@ -106,19 +96,6 @@ end
|
|||||||
# end
|
# end
|
||||||
|
|
||||||
|
|
||||||
# @testset "Gadfly" begin
|
|
||||||
# @test gadfly() == Plots.GadflyBackend()
|
|
||||||
# @test backend() == Plots.GadflyBackend()
|
|
||||||
#
|
|
||||||
# @test typeof(plot(1:10)) == Plots.Plot{Plots.GadflyBackend}
|
|
||||||
# @test plot(Int[1,2,3], rand(3)) == not(nothing)
|
|
||||||
# @test plot(sort(rand(10)), rand(Int, 10, 3)) == not(nothing)
|
|
||||||
# @test plot!(rand(10,3), rand(10,3)) == not(nothing)
|
|
||||||
#
|
|
||||||
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], tol=img_tol)
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@testset "Axes" begin
|
@testset "Axes" begin
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user