From 224b2b7323af63613f0dff68895c891564cdd051 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 22 Sep 2015 16:30:40 -0400 Subject: [PATCH] various fixes; readme --- README.md | 6 +++- docs/example_generation.jl | 22 ++++++------- docs/gadfly_examples.md | 32 +++++++++---------- src/Plots.jl | 1 + src/backends/gadfly.jl | 60 ++++++++++++++++++++++++++++++----- src/backends/gadfly_shapes.jl | 10 ++++-- src/plot.jl | 3 ++ src/types.jl | 11 ++++++- 8 files changed, 105 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 123d1894..9d717cbc 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ There are many ways to pass in data to the plot functions... some examples: - Vectors of Vectors - Functions - Vectors of Functions -- (TODO) DataFrames with column symbols +- DataFrames with column symbols (initialize with `dataframes!()`) In general, you can pass in a `y` only, or an `x` and `y`, both of whatever type(s) you want, and Plots will slice up the data as needed. For matrices, data is split by columns. For functions, data is mapped. For DataFrames (TODO), a Symbol/Symbols in place of x/y will map to @@ -118,6 +118,7 @@ plot(rand(10), sin) # same... y = sin(x) plot([sin,cos], 0:0.1:π) # plot 2 series, sin(x) and cos(x) plot([sin,cos], 0, π) # plot sin and cos on the range [0, π] plot(1:10, Any[rand(10), sin]) # plot 2 series, y = rand(10) for the first, y = sin(x) for the second... x = 1:10 for both +plot(dataset("Ecdat", "Airline"), :Cost) # plot from a DataFrame ``` With `subplot`, create multiple plots at once, with flexible layout options: @@ -177,6 +178,7 @@ Keyword | Default | Type | Aliases `:ribbon` | `nothing` | Series | `:r`, `:ribbons` `:width` | `1` | Series | `:linewidth`, `:w`, `:widths` `:background_color` | `RGB{U8}(1.0,1.0,1.0)` | Plot | `:background`, `:bg`, `:bg_color`, `:bgcolor` +`:foreground_color` | `auto` | Plot | `:fg`, `:fg_color`, `:fgcolor`, `:foreground` `:legend` | `true` | Plot | `:leg` `:show` | `false` | Plot | `:display` `:size` | `(800,600)` | Plot | `:windowsize`, `:wsize` @@ -253,6 +255,8 @@ plot(rand(100,4); color = [:red, RGB(0,0,1)], # lines 1 and 3 are red, lines __Tip__: Not all features are supported for each backend, but you can see what's supported by calling the functions: `supportedAxes()`, `supportedTypes()`, `supportedStyles()`, `supportedMarkers()`, `subplotSupported()` +__Tip__: Call `gui()` to display the plot in a window. Interactivity depends on backend. Showing at the REPL implicitly calls this. + ## TODO features: - [x] Plot vectors/matrices/functions diff --git a/docs/example_generation.jl b/docs/example_generation.jl index 4a7a91ce..f4b84c4c 100644 --- a/docs/example_generation.jl +++ b/docs/example_generation.jl @@ -21,7 +21,7 @@ end const examples = PlotExample[ PlotExample("Lines", "A simple line plot of the 3 columns.", - [:(plot(rand(100,3)))]), + [:(plot(rand(50,5), w=3))]), PlotExample("Functions", "Plot multiple functions. You can also put the function first.", [:(plot(0:0.01:4π, [sin,cos]))]), @@ -30,13 +30,13 @@ const examples = PlotExample[ [:(plot([sin,cos], 0, 4π))]), PlotExample("", "Or make a parametric plot (i.e. plot: (fx(u), fy(u))) with plot(fx, fy, umin, umax).", - [:(plot(sin, x->sin(2x), 0, 2π, legend=false))]), + [:(plot(sin, x->sin(2x), 0, 2π, legend=false, fillto=0))]), PlotExample("Global", "Change the guides/background without a separate call.", [:(plot(rand(10); title="TITLE", xlabel="XLABEL", ylabel="YLABEL", background_color = RGB(0.2,0.2,0.2)))]), PlotExample("Two-axis", "Use the `axis` or `axiss` arguments.\n\nNote: Currently only supported with Qwt and PyPlot", - [:(plot(Vector[randn(100), randn(100)*100]; axiss = [:left,:right], ylabel="LEFT", yrightlabel="RIGHT"))]), + [:(plot(Vector[randn(100), randn(100)*100]; axis = [:l,:r], ylabel="LEFT", yrightlabel="RIGHT"))]), PlotExample("Vectors w/ pluralized args", "Plot multiple series with different numbers of points. Mix arguments that apply to all series (singular... see `marker`) with arguments unique to each series (pluralized... see `colors`).", [:(plot(Vector[rand(10), rand(20)]; marker=:ellipse, markersize=8, colors=[:red,:blue]))]), @@ -45,7 +45,7 @@ const examples = PlotExample[ [:(plot(rand(100)/3; reg=true, fillto=0))]), PlotExample("", "and add to it later.", - [:(scatter!(rand(100); markersize=6, color=:blue))]), + [:(scatter!(rand(100); markersize=6, c=:blue))]), PlotExample("Heatmaps", "", [:(heatmap(randn(10000),randn(10000); nbins=100))]), @@ -55,19 +55,19 @@ const examples = PlotExample[ :(n = length(types)), :(x = Vector[sort(rand(20)) for i in 1:n]), :(y = rand(20,n)), - :(plot(x, y; linetypes=types, labels=map(string,types)))]), + :(plot(x, y; t=types, lab=map(string,types)))]), PlotExample("Line styles", "", - [:(styles = setdiff(supportedStyles(), [:auto])), :(plot(cumsum(randn(20,length(styles)),1); linestyle=:auto, labels=map(string,styles), width=5))]), + [:(styles = setdiff(supportedStyles(), [:auto])), :(plot(cumsum(randn(20,length(styles)),1); style=:auto, label=map(string,styles), w=5))]), PlotExample("Marker types", "", - [:(markers = setdiff(supportedMarkers(), [:none,:auto])), :(scatter(0.5:9.5, [fill(i-0.5,10) for i=length(markers):-1:1]; marker=:auto, labels=map(string,markers), markersize=10))]), + [:(markers = setdiff(supportedMarkers(), [:none,:auto])), :(scatter(0.5:9.5, [fill(i-0.5,10) for i=length(markers):-1:1]; marker=:auto, label=map(string,markers), markersize=10))]), PlotExample("Bar", "x is the midpoint of the bar. (todo: allow passing of edges instead of midpoints)", [:(bar(randn(1000)))]), PlotExample("Histogram", - "note: fillto isn't supported on all backends", - [:(histogram(randn(1000); nbins=50, fillto=20))]), + "", + [:(histogram(randn(1000); nbins=50))]), PlotExample("Subplots", """ subplot and subplot! are distinct commands which create many plots and add series to them in a circular fashion. @@ -85,7 +85,7 @@ const examples = PlotExample[ [:(subplot!(randn(100,3)))]), PlotExample("Open/High/Low/Close", "Create an OHLC chart. Pass in a vector of 4-tuples as your `y` argument. Adjust the tick width with arg `markersize`.", - [:(n=20), :(hgt=rand(n)+1), :(bot=randn(n)), :(openpct=rand(n)), :(closepct=rand(n)), :(y = [(openpct[i]*hgt[i]+bot[i], bot[i]+hgt[i], bot[i], closepct[i]*hgt[i]+bot[i]) for i in 1:n]), :(ohlc(y; markersize=8))]), + [:(n=20), :(hgt=rand(n)+1), :(bot=randn(n)), :(openpct=rand(n)), :(closepct=rand(n)), :(y = [OHLC(openpct[i]*hgt[i]+bot[i], bot[i]+hgt[i], bot[i], closepct[i]*hgt[i]+bot[i]) for i in 1:n]), :(ohlc(y; markersize=8))]), ] @@ -136,7 +136,7 @@ function generate_markdown(pkgname::Symbol) imgname = "$(pkgname)_example_$i.png" # NOTE: uncomment this to overwrite the images as well - # savepng("$IMGDIR/$pkgname/$imgname") + savepng("$IMGDIR/$pkgname/$imgname") # write out the header, description, code block, and image link write(md, "### $(example.header)\n\n") diff --git a/docs/gadfly_examples.md b/docs/gadfly_examples.md index 38605e6e..079571e5 100644 --- a/docs/gadfly_examples.md +++ b/docs/gadfly_examples.md @@ -1,10 +1,10 @@ # Examples for backend: gadfly -- Supported arguments: `args`, `axis`, `color`, `kwargs`, `label`, `legend`, `linestyle`, `linetype`, `marker`, `markercolor`, `markersize`, `nbins`, `reg`, `size`, `title`, `width`, `windowtitle`, `xlabel`, `ylabel`, `yrightlabel` +- Supported arguments: `args`, `axis`, `background_color`, `color`, `fillto`, `foreground_color`, `group`, `kwargs`, `label`, `legend`, `linestyle`, `linetype`, `marker`, `markercolor`, `markersize`, `nbins`, `reg`, `ribbon`, `show`, `size`, `title`, `width`, `windowtitle`, `xlabel`, `xticks`, `ylabel`, `yrightlabel`, `yticks` - Supported values for axis: `:auto`, `:left` -- Supported values for linetype: `:none`, `:line`, `:step`, `:sticks`, `:scatter`, `:heatmap`, `:hexbin`, `:hist`, `:bar`, `:hline`, `:vline`, `:ohlc` -- Supported values for linestyle: `:auto`, `:solid` -- Supported values for marker: `:none`, `:auto`, `:rect`, `:ellipse`, `:diamond`, `:utriangle`, `:dtriangle`, `:cross`, `:xcross`, `:star1`, `:star2`, `:hexagon` +- Supported values for linetype: `:none`, `:line`, `:path`, `:steppost`, `:sticks`, `:scatter`, `:heatmap`, `:hexbin`, `:hist`, `:bar`, `:hline`, `:vline`, `:ohlc` +- Supported values for linestyle: `:auto`, `:solid`, `:dash`, `:dot`, `:dashdot`, `:dashdotdot` +- Supported values for marker: `:none`, `:auto`, `:rect`, `:ellipse`, `:diamond`, `:utriangle`, `:dtriangle`, `:cross`, `:xcross`, `:star1`, `:star2`, `:hexagon`, `:octagon` - Is `subplot`/`subplot!` supported? Yes ### Initialize @@ -19,7 +19,7 @@ gadfly!() A simple line plot of the 3 columns. ```julia -plot(rand(100,3)) +plot(rand(50,5),w=3) ``` ![](../img/gadfly/gadfly_example_1.png) @@ -51,7 +51,7 @@ Or make a parametric plot (i.e. plot: (fx(u), fy(u))) with plot(fx, fy, umin, um ```julia plot(sin,(x->begin # /home/tom/.julia/v0.4/Plots/docs/example_generation.jl, line 33: sin(2x) - end),0,2π,legend=false) + end),0,2π,legend=false,fillto=0) ``` ![](../img/gadfly/gadfly_example_4.png) @@ -61,7 +61,7 @@ plot(sin,(x->begin # /home/tom/.julia/v0.4/Plots/docs/example_generation.jl, li Change the guides/background without a separate call. ```julia -plot(rand(10); title="TITLE",xlabel="XLABEL",ylabel="YLABEL",background_color=RGB(0.5,0.5,0.5)) +plot(rand(10); title="TITLE",xlabel="XLABEL",ylabel="YLABEL",background_color=RGB(0.2,0.2,0.2)) ``` ![](../img/gadfly/gadfly_example_5.png) @@ -73,7 +73,7 @@ Use the `axis` or `axiss` arguments. Note: Currently only supported with Qwt and PyPlot ```julia -plot(Vector[randn(100),randn(100) * 100]; axiss=[:left,:right],ylabel="LEFT",yrightlabel="RIGHT") +plot(Vector[randn(100),randn(100) * 100]; axis=[:l,:r],ylabel="LEFT",yrightlabel="RIGHT") ``` ![](../img/gadfly/gadfly_example_6.png) @@ -103,7 +103,7 @@ plot(rand(100) / 3; reg=true,fillto=0) and add to it later. ```julia -scatter!(rand(100); markersize=6,color=:blue) +scatter!(rand(100); markersize=6,c=:blue) ``` ![](../img/gadfly/gadfly_example_9.png) @@ -123,11 +123,11 @@ heatmap(randn(10000),randn(10000); nbins=100) ```julia -types = intersect(supportedTypes(),[:line,:step,:stepinverted,:sticks,:scatter]) +types = intersect(supportedTypes(),[:line,:path,:steppre,:steppost,:sticks,:scatter]) n = length(types) x = Vector[sort(rand(20)) for i = 1:n] y = rand(20,n) -plot(x,y; linetypes=types,labels=map(string,types)) +plot(x,y; t=types,lab=map(string,types)) ``` ![](../img/gadfly/gadfly_example_11.png) @@ -138,7 +138,7 @@ plot(x,y; linetypes=types,labels=map(string,types)) ```julia styles = setdiff(supportedStyles(),[:auto]) -plot(rand(20,length(styles)); linestyle=:auto,labels=map(string,styles)) +plot(cumsum(randn(20,length(styles)),1); style=:auto,label=map(string,styles),w=5) ``` ![](../img/gadfly/gadfly_example_12.png) @@ -149,7 +149,7 @@ plot(rand(20,length(styles)); linestyle=:auto,labels=map(string,styles)) ```julia markers = setdiff(supportedMarkers(),[:none,:auto]) -scatter(0.5:9.5,[fill(i - 0.5,10) for i = length(markers):-1:1]; marker=:auto,labels=map(string,markers),markersize=10) +scatter(0.5:9.5,[fill(i - 0.5,10) for i = length(markers):-1:1]; marker=:auto,label=map(string,markers),markersize=10) ``` ![](../img/gadfly/gadfly_example_13.png) @@ -166,10 +166,10 @@ bar(randn(1000)) ### Histogram -note: fillto isn't supported on all backends + ```julia -histogram(randn(1000); nbins=50,fillto=20) +histogram(randn(1000); nbins=50) ``` ![](../img/gadfly/gadfly_example_15.png) @@ -219,7 +219,7 @@ hgt = rand(n) + 1 bot = randn(n) openpct = rand(n) closepct = rand(n) -y = [(openpct[i] * hgt[i] + bot[i],bot[i] + hgt[i],bot[i],closepct[i] * hgt[i] + bot[i]) for i = 1:n] +y = [OHLC(openpct[i] * hgt[i] + bot[i],bot[i] + hgt[i],bot[i],closepct[i] * hgt[i] + bot[i]) for i = 1:n] ohlc(y; markersize=8) ``` diff --git a/src/Plots.jl b/src/Plots.jl index dcef62e4..33d58d19 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -46,6 +46,7 @@ export backends, aliases, dataframes!, + OHLC, supportedArgs, supportedAxes, diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl index dbee457b..a6bc839f 100644 --- a/src/backends/gadfly.jl +++ b/src/backends/gadfly.jl @@ -9,7 +9,7 @@ gadfly!() = plotter!(:gadfly) supportedArgs(::GadflyPackage) = setdiff(_allArgs, [:heatmap_c, :pos]) supportedAxes(::GadflyPackage) = setdiff(_allAxes, [:right]) -supportedTypes(::GadflyPackage) = [:none, :line, :path, :step, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :ohlc] +supportedTypes(::GadflyPackage) = [:none, :line, :path, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :ohlc] supportedStyles(::GadflyPackage) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] supportedMarkers(::GadflyPackage) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star1, :star2, :hexagon, :octagon] @@ -49,7 +49,7 @@ function getLineGeoms(d::Dict) lt == :path && return [Gadfly.Geom.path] lt == :scatter && return [Gadfly.Geom.point] lt == :bar && return [Gadfly.Geom.bar] - lt == :step && return [Gadfly.Geom.step] + lt == :steppost && return [Gadfly.Geom.step] # NOTE: we won't actually show this (we'll set width to 0 later), but we need a geom so that Gadfly doesn't complain if lt in (:none, :ohlc) @@ -120,7 +120,7 @@ function addGadflySeries!(gplt, d::Dict, initargs::Dict) # line_style = getGadflyStrokeVector(d[:linestyle]) # set theme: color, line width, and point size - line_width = d[:width] * (d[:linetype] == :none ? 0 : 1) * Gadfly.px # 0 width when we don't show a line + line_width = d[:width] * (d[:linetype] in (:none, :ohlc) ? 0 : 1) * Gadfly.px # 0 width when we don't show a line # fg = initargs[:foreground_color] theme = Gadfly.Theme(; default_color = d[:color], line_width = line_width, @@ -188,7 +188,8 @@ function addGadflySeries!(gplt, d::Dict, initargs::Dict) # add the layer to the Gadfly.Plot - prepend!(gplt.layers, Gadfly.layer(unique(gfargs)..., d[:args]...; x = x, y = d[:y], d[:kwargs]...)) + # prepend!(gplt.layers, Gadfly.layer(unique(gfargs)..., d[:args]...; x = x, y = d[:y], d[:kwargs]...)) + prepend!(gplt.layers, Gadfly.layer(unique(gfargs)...; x = x, y = d[:y])) nothing end @@ -259,7 +260,7 @@ function setGadflyDisplaySize(w,h) Compose.set_default_graphic_size(w * Compose.px, h * Compose.px) end -function Base.writemime(io::IO, ::MIME"image/png", plt::PlottingObject{GadflyPackage}) +function Base.writemime(io::IO, ::MIME"image/png", plt::Plot{GadflyPackage}) gplt = getGadflyContext(plt.plotter, plt) setGadflyDisplaySize(plt.initargs[:size]...) Gadfly.draw(Gadfly.PNG(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt) @@ -271,7 +272,50 @@ function Base.display(::PlotsDisplay, plt::Plot{GadflyPackage}) display(plt.o) end -function Base.display(::PlotsDisplay, subplt::Subplot{GadflyPackage}) - setGadflyDisplaySize(plt.initargs[:size]...) - display(buildGadflySubplotContext(subplt)) + + +function Base.writemime(io::IO, ::MIME"image/png", plt::Subplot{GadflyPackage}) + gplt = getGadflyContext(plt.plotter, plt) + setGadflyDisplaySize(plt.initargs[1][:size]...) + Gadfly.draw(Gadfly.PNG(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt) +end + +function Base.display(::PlotsDisplay, subplt::Subplot{GadflyPackage}) + setGadflyDisplaySize(subplt.initargs[1][:size]...) + ctx = buildGadflySubplotContext(subplt) + + + # taken from Gadfly since I couldn't figure out how to do it directly + + filename = string(Gadfly.tempname(), ".html") + output = open(filename, "w") + + plot_output = IOBuffer() + Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width, + Compose.default_graphic_height, false), ctx) + plotsvg = takebuf_string(plot_output) + + write(output, + """ + + + + Gadfly Plot + + + + + + $(plotsvg) + + + """) + close(output) + Gadfly.open_file(filename) + + # display(buildGadflySubplotContext(subplt)) end diff --git a/src/backends/gadfly_shapes.jl b/src/backends/gadfly_shapes.jl index 92360f44..94299f02 100644 --- a/src/backends/gadfly_shapes.jl +++ b/src/backends/gadfly_shapes.jl @@ -12,7 +12,7 @@ function createGadflyAnnotation(d::Dict) if d[:linetype] == :ohlc shape = ohlcshape(x, y, d[:markersize]) - d[:y] = Float64[z[1] for z in y] + d[:y] = Float64[z.open for z in y] d[:linetype] = :none return Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), shape, Gadfly.fill(nothing), Gadfly.stroke(d[:color]))) @@ -253,14 +253,18 @@ end # --------------------------- -function ohlcshape{T}(xs::AVec, ys::AVec{Tuple{T,T,T,T}}, tickwidth::Real) +function ohlcshape(xs::AVec, ys::AVec{OHLC}, tickwidth::Real) @assert length(xs) == length(ys) n = length(xs) u = tickwidth * Compose.px polys = Vector{Vector{Tuple{Compose.Measure, Compose.Measure}}}(n) for i in 1:n x = Compose.x_measure(xs[i]) - o,h,l,c = map(Compose.y_measure, ys[i]) + o = Compose.y_measure(ys[i].open) + h = Compose.y_measure(ys[i].high) + l = Compose.y_measure(ys[i].low) + c = Compose.y_measure(ys[i].close) + # o,h,l,c = map(Compose.y_measure, ys[i]) polys[i] = Tuple{Compose.Measure, Compose.Measure}[ (x, o), (x - u, o), (x, o), # open tick (x, l), (x, h), (x, c), # high/low bar diff --git a/src/plot.jl b/src/plot.jl index 8bff8e5a..dabd32ce 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -135,6 +135,9 @@ convertToAnyVector{T<:Real}(v::AMat{T}; kw...) = Any[v[:,i] for i in 1:size(v,2) # function convertToAnyVector(f::Function; kw...) = Any[f] +# vector of OHLC +convertToAnyVector(v::AVec{OHLC}; kw...) = Any[v] + # list of things (maybe other vectors, functions, or something else) convertToAnyVector(v::AVec; kw...) = Any[vi for vi in v] diff --git a/src/types.jl b/src/types.jl index 68002ab4..1afbc381 100644 --- a/src/types.jl +++ b/src/types.jl @@ -33,4 +33,13 @@ type Subplot{T<:PlottingPackage} <: PlottingObject{T} layout::SubplotLayout initargs::Vector{Dict} initialized::Bool -end \ No newline at end of file +end + + + +type OHLC{T<:Real} + open::T + high::T + low::T + close::T +end