diff --git a/docs/example_generation.jl b/docs/example_generation.jl index 8a0efd66..09f5b2a5 100644 --- a/docs/example_generation.jl +++ b/docs/example_generation.jl @@ -52,6 +52,11 @@ const examples = PlotExample[ PlotExample("Lots of line types", "Options: (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar) \nNote: some may not work with all backends", [:(plot(rand(20,4); linetypes=[:line, :step, :sticks, :dots], labels=["line","step","sticks","dots"]))]), + PlotExample("Lots of marker types", + "Options: (:none, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon) \nNote: some may not work with all backends", + [:(plot(repmat(collect(1:10)',10,1); markers=[:ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon], + labels=["ellipse", "rect", "diamond", "utriangle", "dtriangle", "cross", "xcross", "star1", "star2", "hexagon"], + linetype=:none, markersize=10))]), PlotExample("Bar", "x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)", [:(bar(randn(1000)))]), diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index f4424a68..35b90c42 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -24,23 +24,105 @@ pyplot!() = plotter!(:pyplot) # d # end + +# convert colorant to 4-tuple RGBA +getPyPlotColor(c::Colorant) = map(f->float(f(c)), (red, green, blue, alpha)) + +# get the style (solid, dashed, etc) +function getPyPlotLineStyle(linetype::Symbol, linestyle::Symbol) + linetype == :none && return " " + linestyle == :solid && return "-" + linestyle == :dash && return "--" + linestyle == :dot && return ":" + linestyle == :dashdot && return "-." + linestyle == :dashdotdot && return "-." + warn("Unknown linestyle $linestyle") + return "-" +end + +# get the marker shape +function getPyPlotMarker(marker::Symbol) + marker == :none && return " " + marker == :ellipse && return "o" + marker == :rect && return "s" + marker == :diamond && return "D" + marker == :utriangle && return "^" + marker == :dtriangle && return "v" + marker == :cross && return "x" + marker == :xcross && return "+" + marker == :star1 && return "*" + marker == :star2 && return "*" + marker == :hexagon && return "h" + warn("Unknown marker $marker") + return "o" +end + +# pass through +function getPyPlotMarker(marker::String) + @assert length(marker) == 1 + marker +end + +function getPyPlotDrawStyle(linetype::Symbol) + linetype == :step && "steps-post" + linetype == :stepinverted && "steps-pre" + return "default" +end + + function plot(pkg::PyPlotPackage; kw...) - # kw = adjustQwtKeywords(true; kw...) - # o = Qwt.plot(zeros(0,0); kw..., show=false) - plt = Plot(o, pkg, 0, kw, Dict[]) + # create the figure + d = Dict(kw) + w,h = map(px2inch, d[:size]) + bgcolor = getPyPlotColor(d[:background_color]) + @show w h + o = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = 96) + + plt = Plot(o, pkg, 0, d, Dict[]) plt end +# TODO: +# - 2-axis +# - bar +# - hist +# - fillto/area +# - heatmap +# - subplot +# title # string or symbol, title of the plot +# xlabel # string or symbol, label on the bottom (x) axis +# ylabel # string or symbol, label on the left (y) axis +# yrightlabel # string or symbol, label on the right (y) axis +# reg # true or false, add a regression line for each line +# pos # (Int,Int), move the enclosing window to this position +# windowtitle # string or symbol, set the title of the enclosing windowtitle +# screen # Integer, move enclosing window to this screen number (for multiscreen desktops) +# show # true or false, show the plot (in case you don't want the window to pop up right away) + function plot!(::PyPlotPackage, plt::Plot; kw...) - # kw = adjustQwtKeywords(false; kw...) - # Qwt.oplot(plt.o; kw...) - push!(plt.seriesargs, kw) + d = Dict(kw) + + lt = d[:linetype] + PyPlot.plot(d[:x], d[:y]; figure = plt.o, + color = getPyPlotColor(d[:color]), + linewidth = d[:width], + linestyle = getPyPlotLineStyle(lt, d[:linestyle]), + marker = getPyPlotMarker(d[:marker]), + markersize = d[:markersize], + markerfacecolor = getPyPlotColor(d[:markercolor]), + drawstyle = getPyPlotDrawStyle(lt), + label = d[:label], + ) + + if plt.initargs[:legend] + PyPlot.legend() + end + + push!(plt.seriesargs, d) plt end function Base.display(::PyPlotPackage, plt::Plot) - # Qwt.refresh(plt.o) - # Qwt.showwidget(plt.o) display(plt.o) end diff --git a/src/backends/qwt.jl b/src/backends/qwt.jl index 225d7708..cbb80374 100644 --- a/src/backends/qwt.jl +++ b/src/backends/qwt.jl @@ -25,16 +25,16 @@ function adjustQwtKeywords(iscreating::Bool; kw...) end function plot(pkg::QwtPackage; kw...) - kw = adjustQwtKeywords(true; kw...) - o = Qwt.plot(zeros(0,0); kw..., show=false) - plt = Plot(o, pkg, 0, kw, Dict[]) + d = adjustQwtKeywords(true; kw...) + o = Qwt.plot(zeros(0,0); d..., show=false) + plt = Plot(o, pkg, 0, d, Dict[]) plt end function plot!(::QwtPackage, plt::Plot; kw...) - kw = adjustQwtKeywords(false; kw...) - Qwt.oplot(plt.o; kw...) - push!(plt.seriesargs, kw) + d = adjustQwtKeywords(false; kw...) + Qwt.oplot(plt.o; d...) + push!(plt.seriesargs, d) plt end diff --git a/src/utils.jl b/src/utils.jl index 5a167a23..b7e1bddd 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -69,3 +69,15 @@ function barHack(; kw...) d end + +# Some conversion functions +# note: I borrowed these conversion constants from Compose.jl's Measure +const INCH_SCALAR = 25.4 +const PX_SCALAR = 1 / 3.78 +inch2px(inches::Real) = float(inches * INCH_SCALAR / PX_SCALAR) +px2inch(px::Real) = float(px * PX_SCALAR / INCH_SCALAR) +inch2mm(inches::Real) = float(inches * INCH_SCALAR) +mm2inch(mm::Real) = float(mm / INCH_SCALAR) +px2mm(px::Real) = float(px * PX_SCALAR) +mm2px(mm::Real) = float(px / PX_SCALAR) +