From f9473cc8bc9ddb2684f522644788e4c1d9d97071 Mon Sep 17 00:00:00 2001 From: Patrick Kofod Mogensen Date: Tue, 15 Mar 2016 16:20:12 +0100 Subject: [PATCH] Initial functionality added to PGFPlots backend. --- src/backends/pgfplots.jl | 190 +++++++++++++++++++++++++++++++++++++- src/backends/supported.jl | 61 ++++++------ 2 files changed, 217 insertions(+), 34 deletions(-) diff --git a/src/backends/pgfplots.jl b/src/backends/pgfplots.jl index 09e0f545..bc507b1d 100644 --- a/src/backends/pgfplots.jl +++ b/src/backends/pgfplots.jl @@ -1,4 +1,3 @@ - # https://github.com/sisl/PGFPlots.jl function _initialize_backend(::PGFPlotsBackend; kw...) @@ -10,6 +9,134 @@ function _initialize_backend(::PGFPlotsBackend; kw...) # TODO: other initialization end +_pgfplots_get_color(c) = "{rgb,1:red,$(float(c.r));green,$(float(c.g));blue,$(float(c.b))}" + +function _pgfplots_get_linestyle!(kwargs, plt) + linestyle = plt[:linestyle] + if linestyle == :dash + kwargs[:style] *= "dashed," + elseif linestyle == :dot + kwargs[:style] *= "dotted," + elseif linestyle == :dashdot + kwargs[:style] *= "dashdotted," + elseif linestyle == :dashdotdot + kwargs[:style] *= "dashdotdotted," + end + + kwargs[:style] *= (haskey(plt, :linewidth) && plt[:linewidth] != :auto) ? "line width = $(plt[:linewidth]) pt," : "line width = 1 pt," +end + + +function _pgfplots_get_marker!(kwargs, plt) + # Control marker shape + mark = plt[:markershape] + if mark in (:none,:n, :no) + kwargs[:style] *= "mark = none," + elseif mark in (:auto, :a) + kwargs[:style] *= "mark = *," + elseif mark in (:cross, :+, :plus) + kwargs[:style] *= "mark = +," + elseif mark in (:xcross ,:X, :x) + kwargs[:style] *= "mark = x," + elseif mark in (:utriangle, :^, :uptri, :uptriangle, :ut, :utri, + :dtriangle, :V, :downtri, :downtriangle, :dt ,:dtri, :v) + kwargs[:style] *= "mark = triangle*," + elseif mark in (:ellipse, :c, :circle) + kwargs[:style] *= "mark = o*," + elseif mark in (:rect ,:r, :sq, :square) + kwargs[:style] *= "mark = square*," + elseif mark in (:star5 ,:s, :star, :star1) + kwargs[:style] *= "mark = star," + elseif mark in (:star6,) + kwargs[:style] *= "mark = asterisk," + elseif mark in (:diamond, :d) + kwargs[:style] *= "mark = diamond*," + elseif mark in (:pentagon ,:p, :pent) + kwargs[:style] *= "mark = pentagon*," + end + + # Control marker size + kwargs[:style] *= "mark size = $(plt[:markersize]/2)," + + # Control marker colors and alphas + marker_fill = plt[:markercolor].c + α = plt[:markeralpha] == nothing ? 1.0 : plt[:markeralpha] + marker_stroke = plt[:markerstrokecolor].c + kwargs[:style] *= "mark options = {color="*_pgfplots_get_color(marker_stroke)*"," + kwargs[:style] *= mark in (:dtriangle, :V, :downtri, :downtriangle, :dt ,:dtri, :v) ? "rotate=180," : "" + kwargs[:style] *= "fill="*_pgfplots_get_color(marker_fill)*"," + kwargs[:style] *= "fill opacity = $α," + markerstrokestyle = plt[:markerstrokestyle] + if markerstrokestyle == :solid + kwargs[:style] *= "solid," + elseif markerstrokestyle == :dash + kwargs[:style] *= "dashed," + elseif markerstrokestyle == :dot + kwargs[:style] *= "dotted," + elseif markerstrokestyle == :dashdot + kwargs[:style] *= "dashdotted," + elseif markerstrokestyle == :dashdotdot + kwargs[:style] *= "dashdotdotted," + end + kwargs[:style] *= "}," +end + +function _pgfplots_get_series_color!(kwargs, plt) + color = plt[:seriescolor].c + α = plt[:seriesalpha] == nothing ? 1.0 : plt[:seriesalpha] + kwargs[:style] *= "color="*_pgfplots_get_color(color)*"," + kwargs[:style] *= "draw opacity = $α," +end + +function _pgfplots_get_plot_kwargs(plt) + kwargs = KW() + kwargs[:style] = "" + _pgfplots_get_linestyle!(kwargs, plt) + _pgfplots_get_marker!(kwargs, plt) + _pgfplots_get_series_color!(kwargs, plt) + kwargs +end + +function _pgfplots_axis(plt_series) + line_type = plt_series[:linetype] + plt_kwargs = _pgfplots_get_plot_kwargs(plt_series) + if line_type == :path + PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...) + elseif line_type == :path3d + PGFPlots.Linear3(plt_series[:x], plt_series[:y], plt_series[:z]; plt_kwargs...) + elseif line_type == :scatter + PGFPlots.Scatter(plt_series[:x], plt_series[:y]; plt_kwargs...) + elseif line_type == :steppre + plt_kwargs[:style] *= "const plot mark right," + PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...) + elseif line_type == :stepmid + plt_kwargs[:style] *= "const plot mark mid," + PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...) + elseif line_type == :steppost + plt_kwargs[:style] *= "const plot," + PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...) + elseif line_type == :hist + #TODO patch this in PGFPlots.jl instead; the problem is that PGFPlots will + # save _all_ data points in the figure which can be quite heavy + plt_hist = hist(plt_series[:y]) + plt_kwargs[:style] *= "ybar interval, mark = none" + PGFPlots.Linear(plt_hist[1][1:end-1]+plt_hist[1].step/2, plt_hist[2]; plt_kwargs...) + elseif line_type == :hist2d + PGFPlots.Histogram2(plt_series[:x], plt_series[:y]) + elseif line_type == :bar + plt_kwargs[:style] *= "ybar, mark = none" + PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...) + elseif line_type == :sticks || line_type == :ysticks + plt_kwargs[:style] *= "ycomb" + PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...) + elseif line_type == :xsticks + plt_kwargs[:style] *= "xcomb" + PGFPlots.Linear(plt_series[:x], plt_series[:y]; plt_kwargs...) + elseif line_type == :contour + PGFPlots.Contour(plt_series[:z].surf, plt_series[:x], plt_series[:y]) + end +end + # --------------------------------------------------------------------------- function _create_plot(pkg::PGFPlotsBackend, d::KW) @@ -78,16 +205,71 @@ end # ---------------------------------------------------------------- +function _pgfplots_get_axis_kwargs(d) + axisargs = KW() + axisargs[:style] = "{" + for arg in (:xlabel, :ylabel, :zlabel, :title) + axisargs[arg] = d[arg] + end + axisargs[:style] *= d[:xflip] == true ? "x dir=reverse," : "" + axisargs[:style] *= d[:yflip] == true ? "y dir=reverse," : "" + if d[:xscale] in (:log, :log2, :ln, :log10) + axisargs[:xmode] = "log" + if d[:xscale] == :log2 + axisargs[:style] *= "log basis x=2," + elseif d[:xscale] in (:log, :log10) + axisargs[:style] *= "log basis x=10," + end + end + if d[:yscale] in (:log, :log2, :ln, :log10) + axisargs[:ymode] = "log" + if d[:yscale] == :log2 + axisargs[:style] *= "log basis y=2," + elseif d[:yscale] in (:log, :log10) + axisargs[:style] *= "log basis x=10," + end + end + if d[:zscale] in (:log, :log2, :ln, :log10) + axisargs[:zmode] = "log" + if d[:zscale] == :log2 + axisargs[:style] *= "log basis z=2," + elseif d[:zscale] in (:log, :log10) + axisargs[:style] *= "log basis x=10," + end + end + axisargs[:style] *= "}," + + # Control background color + bg_color = d[:background_color].c + axisargs[:style] *= "axis background/.style={fill={rgb,1:red,$(float(bg_color.r));green,$(float(bg_color.g));blue,$(float(bg_color.b))},}" + + # Control x/y-limits + if d[:xlims] !== :auto + axisargs[:xmin] = d[:xlims][1] + axisargs[:xmax] = d[:xlims][2] + end + if d[:ylims] !== :auto + axisargs[:ymin] = d[:ylims][1] + axisargs[:ymax] = d[:ylims][2] + end + if d[:grid] == true + axisargs[:style] = "grid = major" + elseif d[:grid] == false + + end + axisargs +end # ---------------------------------------------------------------- ################# This is the important method to implement!!! ################# function _make_pgf_plot(plt::Plot{PGFPlotsBackend}) - # TODO: convert plt.plotargs and plt.seriesargs into PGFPlots calls - # TODO: return the PGFPlots object + os = [_pgfplots_axis(plt_series) for plt_series in plt.seriesargs] + axisargs =_pgfplots_get_axis_kwargs(plt.plotargs) + plt.o = PGFPlots.Axis([os...]; axisargs...) end -function Base.writemime(io::IO, mime::MIME"image/png", plt::AbstractPlot{PGFPlotsBackend}) +function Base.writemime(io::IO, mime::MIME"image/svg+xml", plt::AbstractPlot{PGFPlotsBackend}) plt.o = _make_pgf_plot(plt) writemime(io, mime, plt.o) end diff --git a/src/backends/supported.jl b/src/backends/supported.jl index 373e4e0e..705c04b2 100644 --- a/src/backends/supported.jl +++ b/src/backends/supported.jl @@ -681,7 +681,7 @@ subplotSupported(::GLVisualizeBackend) = false supportedArgs(::PGFPlotsBackend) = [ # :annotation, # :axis, - # :background_color, + :background_color, # :color_palette, # :fillrange, # :fillcolor, @@ -691,19 +691,19 @@ supportedArgs(::PGFPlotsBackend) = [ # :label, # :layout, # :legend, - # :seriescolor, :seriesalpha, - # :linecolor, - # :linestyle, - # :linetype, - # :linewidth, - # :linealpha, - # :markershape, - # :markercolor, - # :markersize, - # :markeralpha, + :seriescolor, :seriesalpha, + :linecolor, + :linestyle, + :linetype, + :linewidth, + :linealpha, + :markershape, + :markercolor, + :markersize, + :markeralpha, # :markerstrokewidth, - # :markerstrokecolor, - # :markerstrokestyle, + :markerstrokecolor, + :markerstrokestyle, # :n, # :bins, # :nc, @@ -712,32 +712,33 @@ supportedArgs(::PGFPlotsBackend) = [ # :smooth, # :show, # :size, - # :title, + :title, # :windowtitle, - # :x, - # :xlabel, - # :xlims, + :x, + :xlabel, + :xlims, # :xticks, - # :y, - # :ylabel, - # :ylims, + :y, + :ylabel, + :ylims, # :yrightlabel, # :yticks, - # :xscale, - # :yscale, - # :xflip, - # :yflip, - # :z, + :xscale, + :yscale, + :xflip, + :yflip, + :z, + :zscale, # :tickfont, # :guidefont, # :legendfont, - # :grid, + :grid, # :surface # :levels, ] supportedAxes(::PGFPlotsBackend) = [:auto, :left] -supportedTypes(::PGFPlotsBackend) = [:contour] #, :path, :scatter ,:steppre, :steppost, :sticks, :hist2d, :hexbin, :hist, :bar, :hline, :vline, :contour] -supportedStyles(::PGFPlotsBackend) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot] -supportedMarkers(::PGFPlotsBackend) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape) -supportedScales(::PGFPlotsBackend) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt] +supportedTypes(::PGFPlotsBackend) = [:path, :path3d, :scatter, :line, :steppre, :stepmid, :steppost, :hist, :bar, :hist2d, :sticks, :ysticks, :xsticks, :contour] # :hexbin, :hline, :vline,] +supportedStyles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] +supportedMarkers(::PGFPlotsBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape) +supportedScales(::PGFPlotsBackend) = [:identity, :log, :ln, :log2, :log10] # :asinh, :sqrt] subplotSupported(::PGFPlotsBackend) = false