Plots.jl/src/backends/unicodeplots.jl
2015-10-19 14:11:22 -04:00

264 lines
6.7 KiB
Julia

# https://github.com/Evizero/UnicodePlots.jl
# immutable UnicodePlotsPackage <: PlottingPackage end
# export unicodeplots
# unicodeplots() = backend(:unicodeplots)
# -------------------------------
# # supportedArgs(::UnicodePlotsPackage) = setdiff(_allArgs, [:reg, :heatmap_c, :fill, :pos, :xlims, :ylims, :xticks, :yticks])
# supportedArgs(::UnicodePlotsPackage) = [
# # :annotation,
# # :args,
# # :axis,
# # :background_color,
# # :color,
# # :fill,
# # :foreground_color,
# :group,
# # :heatmap_c,
# # :kwargs,
# :label,
# # :layout,
# :legend,
# :linestyle,
# :linetype,
# # :linewidth,
# :markershape,
# # :markercolor,
# # :markersize,
# # :n,
# :nbins,
# # :nc,
# # :nr,
# # :pos,
# # :reg,
# # :ribbon,
# :show,
# :size,
# :title,
# :windowtitle,
# :x,
# :xlabel,
# :xlims,
# # :xticks,
# :y,
# :ylabel,
# :ylims,
# # :yrightlabel,
# # :yticks,
# # :xscale,
# # :yscale,
# # :xflip,
# # :yflip,
# # :z,
# ]
# supportedAxes(::UnicodePlotsPackage) = [:auto, :left]
# supportedTypes(::UnicodePlotsPackage) = [:none, :line, :path, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline]
# supportedStyles(::UnicodePlotsPackage) = [:auto, :solid]
# supportedMarkers(::UnicodePlotsPackage) = [:none, :auto, :ellipse]
# supportedScales(::UnicodePlotsPackage) = [:identity]
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
function rebuildUnicodePlot!(plt::Plot)
# figure out the plotting area xlim = [xmin, xmax] and ylim = [ymin, ymax]
sargs = plt.seriesargs
iargs = plt.initargs
# get the x/y limits
if get(iargs, :xlims, :auto) == :auto
xlim = [Inf, -Inf]
for d in sargs
expandLimits!(xlim, d[:x])
end
else
xmin, xmax = iargs[:xlims]
xlim = [xmin, xmax]
end
if get(iargs, :ylims, :auto) == :auto
ylim = [Inf, -Inf]
for d in sargs
expandLimits!(ylim, d[:y])
end
else
ymin, ymax = iargs[:ylims]
ylim = [ymin, ymax]
end
# we set x/y to have a single point, since we need to create the plot with some data.
# since this point is at the bottom left corner of the plot, it shouldn't actually be shown
x = Float64[xlim[1]]
y = Float64[ylim[1]]
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
width, height = iargs[:size]
o = UnicodePlots.createPlotWindow(x, y; width = width,
height = height,
title = iargs[:title],
# labels = iargs[:legend],
xlim = xlim,
ylim = ylim)
# set the axis labels
UnicodePlots.xlabel!(o, iargs[:xlabel])
UnicodePlots.ylabel!(o, iargs[:ylabel])
# now use the ! functions to add to the plot
for d in sargs
addUnicodeSeries!(o, d, iargs[:legend], xlim, ylim)
end
# save the object
plt.o = o
end
# add a single series
function addUnicodeSeries!(o, d::Dict, addlegend::Bool, xlim, ylim)
# get the function, or special handling for step/bar/hist
lt = d[:linetype]
# handle hline/vline separately
if lt in (:hline,:vline)
for yi in d[:y]
if lt == :hline
UnicodePlots.lineplot!(o, xlim, [yi,yi])
else
UnicodePlots.lineplot!(o, [yi,yi], ylim)
end
end
return
end
stepstyle = :post
if lt == :path
func = UnicodePlots.lineplot!
elseif lt == :scatter || d[:markershape] != :none
func = UnicodePlots.scatterplot!
elseif lt == :steppost
func = UnicodePlots.stairs!
elseif lt == :steppre
func = UnicodePlots.stairs!
stepstyle = :pre
else
error("Linestyle $lt not supported by UnicodePlots")
end
# get the series data and label
x, y = [collect(float(d[s])) for s in (:x, :y)]
label = addlegend ? d[:label] : ""
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = d[:color] in UnicodePlots.autoColors ? d[:color] : :auto
# add the series
func(o, x, y; color = color, name = label, style = stepstyle)
end
function handlePlotColors(::UnicodePlotsPackage, d::Dict)
# TODO: something special for unicodeplots, since it doesn't take kindly to people messing with its color palette
d[:color_palette] = [RGB(0,0,0)]
end
# -------------------------------
function plot(pkg::UnicodePlotsPackage; kw...)
plt = Plot(nothing, pkg, 0, Dict(kw), Dict[])
# do we want to give a new default size?
if !haskey(plt.initargs, :size) || plt.initargs[:size] == _plotDefaults[:size]
plt.initargs[:size] = (60,20)
end
plt
end
function plot!(::UnicodePlotsPackage, plt::Plot; kw...)
d = Dict(kw)
if d[:linetype] in (:sticks, :bar)
d = barHack(; d...)
elseif d[:linetype] == :hist
d = barHack(; histogramHack(; d...)...)
end
push!(plt.seriesargs, d)
plt
end
function updatePlotItems(plt::Plot{UnicodePlotsPackage}, d::Dict)
for k in (:title, :xlabel, :ylabel, :xlims, :ylims)
if haskey(d, k)
plt.initargs[k] = d[k]
end
end
end
# -------------------------------
# function savepng(::UnicodePlotsPackage, plt::PlottingObject, fn::@compat(AbstractString), args...)
# function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{UnicodePlotsPackage})
# since this is such a hack, it's only callable using `png`... should error during normal `writemime`
function png(plt::PlottingObject{UnicodePlotsPackage}, fn::@compat(AbstractString))
fn = addExtension(fn, "png")
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
@osx_only begin
# BEGIN HACK
# wait while the plot gets drawn
sleep(0.5)
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
run(`screencapture -R50,600,700,420 $fn`)
# # some other attempts:
# run(`screencapture -w $fn`)
# using PyCall
# @pyimport pyscreenshot as pss
# END HACK (phew)
return
end
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
end
# -------------------------------
# we don't do very much for subplots... just stack them vertically
function buildSubplotObject!(subplt::Subplot{UnicodePlotsPackage}, isbefore::Bool)
isbefore && return false
true
end
function Base.display(::PlotsDisplay, plt::Plot{UnicodePlotsPackage})
rebuildUnicodePlot!(plt)
show(plt.o)
end
function Base.display(::PlotsDisplay, subplt::Subplot{UnicodePlotsPackage})
for plt in subplt.plts
gui(plt)
end
end