diff --git a/README.md b/README.md index 88166b4c..d4d33944 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,14 @@ First, clone the package, and get any plotting packages you need: ``` Pkg.clone("https://github.com/JuliaPlot/Plots.jl.git") -Pkg.clone("https://github.com/tbreloff/Qwt.jl.git") # requires pyqt and pyqwt -Pkg.add("Gadfly") # might also need to Pkg.checkout("Gadfly") and maybe Colors/Compose... I had trouble with it +Pkg.clone("https://github.com/tbreloff/Qwt.jl.git") # [optional] requires pyqt and pyqwt +Pkg.add("Gadfly") # [optional] might also need to Pkg.checkout("Gadfly") + # and maybe Colors/Compose... I had trouble with it ``` -Now load it in: +Load it in. The underlying plotting backends are not imported until `plotter()` is called (which happens +on your first call to `plot`). This means that you don't need any backends to be installed when you call `using Plots`. +For now, the default backend is Qwt. ``` using Plots @@ -23,8 +26,7 @@ using Plots Do a plot in Qwt, then save a png: ``` -plotter!(:qwt) -plot(1:10) +plot(rand(10,2); marker = :rect) savepng(ans, Plots.IMG_DIR * "qwt1.png") ``` @@ -36,9 +38,9 @@ which saves: Do a plot in Gadfly, then save a png: ``` -plotter!(:gadfly) -plot(1:10) -savepng(ans, Plots.IMG_DIR * "gadfly1.png", 6Gadfly.inch, 4Gadfly.inch) +plotter!(:gadfly) # switches the backend to Gadfly +plot(rand(10,2); marker = :rect) +savepng(ans, Plots.IMG_DIR * "gadfly1.png", 6 * Gadfly.inch, 4 * Gadfly.inch) ``` which saves: @@ -46,23 +48,10 @@ which saves: ![gadfly_plt](img/gadfly1.png) -Note that you do not need all underlying packages to use this. I use Requires.jl to -perform lazy loading of the modules, so there's no initialization until you call `plotter!()`. -This has an added benefit that you can call `using Plots` and it should return quickly... -no more waiting for a plotting package to load when you don't even use it. :) -``` -julia> tic(); using Plots; toc(); -elapsed time: 0.356158445 seconds +# plot and plotter! interface (WIP) -julia> tic(); using Gadfly; toc(); -WARNING: using Gadfly.Plots in module Main conflicts with an existing identifier. -elapsed time: 3.1334697 seconds -``` - -# plot and plotter! (proposal) - -The main plot command. You must call `plotter!(:ModuleName)` to set the current plotting environment first. +The main plot command. Call `plotter!(:module)` to set the current plotting backend. Commands are converted into the relevant plotting commands for that package: ``` @@ -102,7 +91,7 @@ Here are some various args to supply, and the implicit mapping (AVec == Abstract plot(df::DataFrame, columns; kw...) # one line per column, but on a subset of column names ``` -You can swap out `plot` for `subplot`. Each line will go into a separate plot. Use the layout keyword: +[TODO] You can swap out `plot` for `subplot`. Each line will go into a separate plot. Use the layout keyword: ``` y = rand(100,3) @@ -112,12 +101,17 @@ You can swap out `plot` for `subplot`. Each line will go into a separate plot. # and the others will share the second row ``` -Other potential shorthands: +Shorthands: ``` - hist(args..., kw...) - scatter(args..., kw...) - heatmap(args..., kw...) + scatter(args...; kw...) = plot(args...; kw..., linetype = :none, marker = :rect) + scatter!(args...; kw...) = plot!(args...; kw..., linetype = :none, marker = :rect) + bar(args...; kw...) = plot(args...; kw..., linetype = :bar) + bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar) + histogram(args...; kw...) = plot(args...; kw..., linetype = :hist) + histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist) + heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap) + heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap) ``` Some keyword arguments you can set: @@ -127,11 +121,14 @@ Some keyword arguments you can set: color # can be a string ("red") or a symbol (:red) or a ColorsTypes.jl Colorant (RGB(1,0,0)) or :auto (which lets the package pick) label # string or symbol, applies to that line, may go in a legend width # width of a line - linetype # :line, :step, :stepinverted, :sticks, :dots, :none, :heatmap + linetype # :line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hexbin, :hist, :bar linestyle # :solid, :dash, :dot, :dashdot, :dashdotdot marker # :none, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon - markercolor # same choices as `color` + markercolor # same choices as `color`, or :match will set the color to be the same as `color` markersize # size of the marker + nbins # number of bins for heatmap/hexbin and histograms + heatmap_c # color cutoffs for Qwt heatmaps + fillto # fillto value for area plots 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 @@ -150,12 +147,15 @@ If you don't include a keyword argument, these are the defaults: axis = :left color = :auto label = automatically generated (y1, y2, ...., or y1 (R), y2 (R) for the right axis) - width = 2 + width = 1 linetype = :line linestype = :solid marker = :none - markercolor = :auto - markersize = 5 + markercolor = :match + markersize = 3 + nbins = 100 + heatmap_c = (0.15, 0.5) + fillto = nothing title = "" xlabel = "" ylabel = "" @@ -177,20 +177,20 @@ When plotting multiple lines, you can give every line the same trait by using th # TODO -- [ ] Plot vectors/matrices +- [x] Plot vectors/matrices/functions - [ ] Plot DataFrames - [ ] Subplots -- [ ] Histograms +- [x] Histograms - [ ] 3D plotting - [ ] Scenes/Drawing - [ ] Graphs - [ ] Interactivity (GUIs) -- [ ] Gadfly.jl +- [x] Gadfly.jl - [ ] PyPlot.jl - [ ] Winston.jl - [ ] Gaston.jl - [ ] GLPlot.jl -- [ ] Qwt.jl +- [x] Qwt.jl - [ ] Bokeh.jl - [ ] Plotly.jl - [ ] GoogleCharts.jl diff --git a/img/gadfly1.png b/img/gadfly1.png index b40b4e7f..ce1560ac 100644 Binary files a/img/gadfly1.png and b/img/gadfly1.png differ diff --git a/img/qwt1.png b/img/qwt1.png index a9601dc9..eed769db 100644 Binary files a/img/qwt1.png and b/img/qwt1.png differ diff --git a/src/Plots.jl b/src/Plots.jl index 68e90801..316d3813 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -10,7 +10,7 @@ export plotDefault, scatter, bar, - hist, + histogram, heatmap, plotter!, @@ -19,7 +19,7 @@ export plotDefault!, scatter!, bar!, - hist!, + histogram!, heatmap!, savepng @@ -77,14 +77,14 @@ include("plot.jl") # const LINE_TYPES = (:line, :step, :stepinverted, :sticks, :dots, :none, :heatmap, :hist, :bar) -scatter(args...; kw...) = plot(args...; kw..., linetype = :dots) -scatter!(args...; kw...) = plot!(args...; kw..., linetype = :dots) -bar(args...; kw...) = plot(args...; kw..., linetype = :bar) -bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar) -hist(args...; kw...) = plot(args...; kw..., linetype = :hist) -hist!(args...; kw...) = plot!(args...; kw..., linetype = :hist) -heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap) -heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap) +scatter(args...; kw...) = plot(args...; kw..., linetype = :none, marker = :rect) +scatter!(args...; kw...) = plot!(args...; kw..., linetype = :none, marker = :rect) +bar(args...; kw...) = plot(args...; kw..., linetype = :bar) +bar!(args...; kw...) = plot!(args...; kw..., linetype = :bar) +histogram(args...; kw...) = plot(args...; kw..., linetype = :hist) +histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist) +heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap) +heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap) # --------------------------------------------------------- diff --git a/src/gadfly.jl b/src/gadfly.jl index 77f0bea2..2a9836f1 100644 --- a/src/gadfly.jl +++ b/src/gadfly.jl @@ -28,6 +28,7 @@ function getGeomFromLineType(linetype::Symbol) linetype == :bar && return Gadfly.Geom.bar linetype == :step && return Gadfly.Geom.step linetype == :hist && return Gadfly.Geom.hist + linetype == :none && return Gadfly.Geom.point # change this? are we usually pairing no line with scatterplots? error("linetype $linetype not currently supported with Gadfly") end @@ -59,7 +60,6 @@ function plot!(::GadflyPackage, plt::Plot; kw...) gfargs = [] # add the Geoms - println(d) append!(gfargs, getGeoms(d[:linetype], d[:marker], d[:nbins])) # set color, line width, and point size diff --git a/src/plot.jl b/src/plot.jl index ef38cd83..448b2702 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -1,14 +1,14 @@ doc""" -The main plot command. You must call `plotter!(:ModuleName)` to set the current plotting environment first. +The main plot command. Call `plotter!(:module)` to set the current plotting backend. Commands are converted into the relevant plotting commands for that package: ``` plotter!(:gadfly) - plot(1:10) # this calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)` + plot(1:10) # this effectively calls `y = 1:10; Gadfly.plot(x=1:length(y), y=y)` plotter!(:qwt) - plot(1:10) # this calls `Qwt.plot(1:10)` + plot(1:10) # this effectively calls `Qwt.plot(1:10)` ``` Use `plot` to create a new plot object, and `plot!` to add to an existing one: @@ -19,39 +19,8 @@ Use `plot` to create a new plot object, and `plot!` to add to an existing one: plot!(plotobj, args...; kw...) # adds to the plot `plotobj` ``` -Now that you know which plot object you're updating (new, current, or other), I'll leave it off for simplicity. -Here are some various args to supply, and the implicit mapping (AVec == AbstractVector and AMat == AbstractMatrix): - -``` - plot(y::AVec; kw...) # one line... x = 1:length(y) - plot(x::AVec, y::AVec; kw...) # one line (will assert length(x) == length(y)) - plot(y::AMat; kw...) # multiple lines (one per column of x), all sharing x = 1:size(y,1) - plot(x::AVec, y::AMat; kw...) # multiple lines (one per column of x), all sharing x (will assert length(x) == size(y,1)) - plot(x::AMat, y::AMat; kw...) # multiple lines (one per column of x/y... will assert size(x) == size(y)) - plot(x::AVec, f::Function; kw...) # one line, y = f(x) - plot(x::AMat, f::Function; kw...) # multiple lines, yᵢⱼ = f(xᵢⱼ) - plot(x::AVec, fs::AVec{Function}; kw...) # multiple lines, yᵢⱼ = fⱼ(xᵢ) - plot(y::AVec{AVec}; kw...) # multiple lines, each with x = 1:length(y[i]) - plot(x::AVec, y::AVec{AVec}; kw...) # multiple lines, will assert length(x) == length(y[i]) - plot(x::AVec{AVec}, y::AVec{AVec}; kw...) # multiple lines, will assert length(x[i]) == length(y[i]) - plot(n::Integer; kw...) # n lines, all empty (for updating plots) - - # TODO: how do we handle NA values in dataframes? - plot(df::DataFrame; kw...) # one line per DataFrame column, labels == names(df) - plot(df::DataFrame, columns; kw...) # one line per column, but on a subset of column names -``` - - TODO: DataFrames - -You can swap out `plot` for `subplot`. Each line will go into a separate plot. Use the layout keyword: - -``` - y = rand(100,3) - subplot(y; layout=(2,2), kw...) # creates 3 lines going into 3 separate plots, laid out on a 2x2 grid (last row is filled with plot #3) - subplot(y; layout=(1,3), kw...) # again 3 plots, all in the same row - subplot(y; layout=[1,[2,3]]) # pass a nested Array to fully specify the layout. here the first plot will take up the first row, - # and the others will share the second row -``` +There are lots of ways to pass in data... just try it and it will likely work as expected. +When you pass in matrices, it splits by columns. See the documentation for more info. Some keyword arguments you can set: @@ -65,6 +34,9 @@ Some keyword arguments you can set: marker # :none, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon markercolor # same choices as `color` markersize # size of the marker + nbins # number of bins for heatmap/hexbin and histograms + heatmap_c # color cutoffs for Qwt heatmaps + fillto # fillto value for area plots 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 @@ -77,30 +49,6 @@ Some keyword arguments you can set: show # true or false, show the plot (in case you don't want the window to pop up right away) ``` -If you don't include a keyword argument, these are the defaults: - -``` - axis = :left - color = :auto - label = automatically generated (y1, y2, ...., or y1 (R), y2 (R) for the right axis) - width = 2 - linetype = :line - linestype = :solid - marker = :none - markercolor = :auto - markersize = 5 - title = "" - xlabel = "" - ylabel = "" - yrightlabel = "" - reg = false - size = (800,600) - pos = (0,0) - windowtitle = "" - screen = 1 - show = true -``` - When plotting multiple lines, you can give every line the same trait by using the singular, or add an "s" to pluralize. (yes I know it's not gramatically correct, but it's easy to use and implement) diff --git a/src/plotter.jl b/src/plotter.jl index be7895fb..4672c383 100644 --- a/src/plotter.jl +++ b/src/plotter.jl @@ -11,25 +11,22 @@ const AVAILABLE_PACKAGES = [:qwt, :gadfly] const INITIALIZED_PACKAGES = Set{Symbol}() type CurrentPackage - # pkg::Nullable{PlottingPackage} sym::Symbol pkg::PlottingPackage end -# const CURRENT_PACKAGE = CurrentPackage(Nullable{PlottingPackage}()) const CURRENT_PACKAGE = CurrentPackage(:qwt, QwtPackage()) doc""" -Returns the current plotting package name. Initializes package on first use. +Returns the current plotting package name. Initializes package on first call. """ function plotter() - # if isnull(CURRENT_PACKAGE.pkg) - # error("Must choose a plotter. Example: `plotter!(:qwt)`") - # end + currentPackageSymbol = CURRENT_PACKAGE.sym if !(currentPackageSymbol in INITIALIZED_PACKAGES) # initialize + print("Initializing package: $CURRENT_PACKAGE... ") if currentPackageSymbol == :qwt @eval import Qwt elseif currentPackageSymbol == :gadfly @@ -38,11 +35,9 @@ function plotter() error("Unknown plotter $currentPackageSymbol. Choose from: $AVAILABLE_PACKAGES") end push!(INITIALIZED_PACKAGES, currentPackageSymbol) - # plotter!(CURRENT_PACKAGE.sym) + println("done.") end - # get(CURRENT_PACKAGE.pkg) - println("Current package: $CURRENT_PACKAGE") CURRENT_PACKAGE.pkg end @@ -51,34 +46,18 @@ Set the plot backend. Choose from: :qwt, :gadfly """ function plotter!(modname) + # set the PlottingPackage if modname == :qwt - # if !(modname in INITIALIZED_PACKAGES) - # # qwt() - # @eval import Qwt - # push!(INITIALIZED_PACKAGES, modname) - # end - # global Qwt = Main.Qwt - # CURRENT_PACKAGE.sym = modname - # CURRENT_PACKAGE.pkg = Nullable(QwtPackage()) CURRENT_PACKAGE.pkg = QwtPackage() - # return - elseif modname == :gadfly - # if !(modname in INITIALIZED_PACKAGES) - # # gadfly() - # @eval import Gadfly - # push!(INITIALIZED_PACKAGES, modname) - # end - # global Gadfly = Main.Gadfly - # CURRENT_PACKAGE.sym = modname - # CURRENT_PACKAGE.pkg = Nullable(GadflyPackage()) CURRENT_PACKAGE.pkg = GadflyPackage() - # return - else error("Unknown plotter $modname. Choose from: $AVAILABLE_PACKAGES") end + # update the symbol CURRENT_PACKAGE.sym = modname + + # return the package CURRENT_PACKAGE.pkg end