Plots.jl/src/backends/pgfplots.jl
2016-04-27 10:05:48 +02:00

288 lines
9.9 KiB
Julia
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# https://github.com/sisl/PGFPlots.jl
function _initialize_backend(::PGFPlotsBackend; kw...)
@eval begin
import PGFPlots
export PGFPlots
# TODO: other initialization that needs to be eval-ed
end
# 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)
# TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
# TODO: initialize the plot... title, xlabel, bgcolor, etc
Plot(nothing, pkg, 0, d, KW[])
end
function _add_series(::PGFPlotsBackend, plt::Plot, d::KW)
# TODO: add one series to the underlying package
push!(plt.seriesargs, d)
plt
end
function _add_annotations{X,Y,V}(plt::Plot{PGFPlotsBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
# set or add to the annotation_list
if haskey(plt.plotargs, :annotation_list)
append!(plt.plotargs[:annotation_list], anns)
else
plt.plotargs[:annotation_list] = anns
end
end
# ----------------------------------------------------------------
function _before_update_plot(plt::Plot{PGFPlotsBackend})
end
# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{PGFPlotsBackend}, d::KW)
end
function _update_plot_pos_size(plt::AbstractPlot{PGFPlotsBackend}, d::KW)
end
# ----------------------------------------------------------------
# accessors for x/y data
# function getxy(plt::Plot{PGFPlotsBackend}, i::Int)
# d = plt.seriesargs[i]
# d[:x], d[:y]
# end
#
# function setxy!{X,Y}(plt::Plot{PGFPlotsBackend}, xy::Tuple{X,Y}, i::Integer)
# d = plt.seriesargs[i]
# d[:x], d[:y] = xy
# plt
# end
# ----------------------------------------------------------------
function _create_subplot(subplt::Subplot{PGFPlotsBackend}, isbefore::Bool)
# TODO: build the underlying Subplot object. this is where you might layout the panes within a GUI window, for example
true
end
function _expand_limits(lims, plt::Plot{PGFPlotsBackend}, isx::Bool)
# TODO: call expand limits for each plot data
end
function _remove_axis(plt::Plot{PGFPlotsBackend}, isx::Bool)
# TODO: if plot is inner subplot, might need to remove ticks or axis labels
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})
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/svg+xml", plt::AbstractPlot{PGFPlotsBackend})
plt.o = _make_pgf_plot(plt)
writemime(io, mime, plt.o)
end
# function Base.writemime(io::IO, ::MIME"text/html", plt::AbstractPlot{PGFPlotsBackend})
# end
function Base.display(::PlotsDisplay, plt::AbstractPlot{PGFPlotsBackend})
plt.o = _make_pgf_plot(plt)
display(plt.o)
end
# function Base.display(::PlotsDisplay, plt::Subplot{PGFPlotsBackend})
# # TODO: display/show the subplot
# end