diff --git a/README.md b/README.md
index c1ae91bf..d6d321ff 100644
--- a/README.md
+++ b/README.md
@@ -7,18 +7,22 @@ _Julia bindings to Vega-Lite_
|[![VegaLite](http://pkg.julialang.org/badges/VegaLite_0.4.svg)](http://pkg.julialang.org/?pkg=VegaLite&ver=0.4) | N/A | [![Build Status](https://travis-ci.org/fredo-dedup/VegaLite.jl.svg?branch=master)](https://travis-ci.org/fredo-dedup/VegaLite.jl) | [![Coverage Status](https://coveralls.io/repos/github/fredo-dedup/VegaLite.jl/badge.svg?branch=master)](https://coveralls.io/github/fredo-dedup/VegaLite.jl?branch=master) |
-This package provides access to the Vega-Lite high-level visualization grammar (http://vega.github.io/vega-lite/) from within Julia . Install with
-`Pkg.add("VegaLite")` (or `Pkg.clone("https://github.com/fredo-dedup/VegaLite.jl.git")`
-until it hasn't reached the official repository). You can use the integrated documentation (e.g. `? config_mark`) to get the full list of properties.
+This package provides access to the Vega-Lite high-level visualization grammar (http://vega.github.io/vega-lite/) from Julia.
-Vega-Lite is a simpler version of the Vega grammar allowing smaller and more expressive chart specifications. If you don't find this library powerful enough for your needs you can turn to Vega.jl (https://github.com/johnmyleswhite/Vega.jl) on which this project is largely based (thanks !).
+Vega-Lite is a simpler version of the Vega grammar allowing smaller and more expressive chart specifications. If you don't find this library powerful enough for your needs you can turn to Vega.jl (https://github.com/johnmyleswhite/Vega.jl) on which this project is partially based (thanks !).
-##TODO:
-- IJulia/Jupyter integration
-- More tests
-- Implement missing sub-specs : `transform`, `bin`,..
+Install with `Pkg.add("VegaLite")` (or `Pkg.clone("https://github.com/fredo-dedup/VegaLite.jl.git")`
+until it reaches the official repository). You can use the integrated documentation, e.g. `? config_mark` to get the full list of properties of the `config_mark` function.
-Any contribution, PR or issue, is welcome !
+The julia functions follow pretty closely the Vega-Lite JSON format: `data_values()` creates the `{"data": {values: { ...} }}` part of the spec file, etc.
+Only two functions are added:
+- `svg(Bool)` : sets the drawing mode of the plots, SVG if `true`, canvas if `false`. Default = `true`
+- `buttons(Bool)` : indicates if the plot should be accompanied with links 'Save as PNG', 'View source' and 'Open in Vega Editor'.
+
+Currently, VegaLite.jl works with IJulia/Jupyter, Escher and in the standard REPL (a browser window will open).
+
+
+All contributions, PR or issue, are welcome !
##Examples:
@@ -38,7 +42,7 @@ v = data_values(time=ts, res=ys) + # add the data vectors & assign to symbols
![plot1](examples/png/vega (1).png)
-- Scatterplot from a DataFrame:
+- Scatterplot, using a DataFrame as the source:
```julia
using RDatasets
@@ -52,7 +56,7 @@ data_values(mpg) + # add values
![plot1](examples/png/vega (2).png)
-- A scatterplot, with colors and size settings:
+- A scatterplot, with colors and size settings for the plot:
```julia
data_values(mpg) +
mark_point() +
diff --git a/assets/vega-lite.html b/assets/vega-lite.html
index 2c169d3b..b170ec0b 100644
--- a/assets/vega-lite.html
+++ b/assets/vega-lite.html
@@ -27,7 +27,7 @@
var embedSpec = {
mode: "vega-lite",
renderer: this.svg ? "svg" : "canvas",
- actions: false, //this.actions,
+ actions: this.actions,
spec: this.json
}
vg.embed(this, embedSpec, function(error, result) {
diff --git a/src/VegaLite.jl b/src/VegaLite.jl
index 50081ab1..92c25754 100644
--- a/src/VegaLite.jl
+++ b/src/VegaLite.jl
@@ -8,6 +8,8 @@ module VegaLite
export VegaLiteVis, scale, axis, legend
+ export svg, buttons
+
export data_values
export config_grid, config_facet_axis, config_facet_cell,
@@ -51,6 +53,6 @@ module VegaLite
Pkg.installed("DataFrames") != nothing && include("dataframes_integration.jl")
### Integration with IJulia - Jupyter
- # Pkg.installed("IJulia") != nothing && include("ijulia_integration.jl")
+ Pkg.installed("IJulia") != nothing && include("ijulia_integration.jl")
end
diff --git a/src/escher_integration.jl b/src/escher_integration.jl
index 0e38ea5c..6ecf3036 100644
--- a/src/escher_integration.jl
+++ b/src/escher_integration.jl
@@ -1,17 +1,6 @@
import Escher: Elem, Tile, render
import Base: convert
-ESCHER_SVG = true
-ESCHER_BUTTONS = true
-
-export svg, buttons
-
-svg() = ESCHER_SVG
-svg(b::Bool) = (global ESCHER_SVG ; ESCHER_SVG = b)
-buttons() = ESCHER_BUTTONS
-buttons(b::Bool) = (global ESCHER_BUTTONS ; ESCHER_BUTTONS = b)
-
-
type VegaLiteTile <: Tile
json::AbstractString
svg::Bool
@@ -19,7 +8,7 @@ type VegaLiteTile <: Tile
end
function VegaLiteTile(vis::AbstractString)
- VegaLiteTile(vis, ESCHER_SVG, ESCHER_BUTTONS)
+ VegaLiteTile(vis, SVG, SAVE_BUTTONS)
end
convert(::Type{Tile}, v::VegaLiteVis) = VegaLiteTile(JSON.json(v.vis))
diff --git a/src/ijulia_integration.jl b/src/ijulia_integration.jl
new file mode 100644
index 00000000..83c279b1
--- /dev/null
+++ b/src/ijulia_integration.jl
@@ -0,0 +1,79 @@
+######################################################################
+#
+# IJulia Integration
+#
+# - consist in defining a writemime(::IO, m::MIME"text/html", v::VegaLiteVis)
+# including scripts that load the required libraries (D3, vega, vega-lite)
+# - Will it work with other html backends ? probably not.
+#
+######################################################################
+
+import Base.writemime
+
+# FIXME : Apparently, loading local js files is not allowed by the browser
+# => libraries are loaded externally in the `require.config`
+
+# function jslibpath(url...)
+# libpath = Pkg.dir("VegaLite", "assets", "bower_components", url...)
+# replace(libpath, "\\", "/") # for windows...
+# end
+# // d3: "$(jslibpath("d3","d3.min.js"))",
+# // vega: "$(jslibpath("vega", "vega.js"))",
+# // vegalite: "$(jslibpath("vega-lite", "vega-lite.js"))",
+# // vegaembed: "$(jslibpath("vega-embed", "vega-embed.js"))"
+
+
+function writemime(io::IO, m::MIME"text/html", v::VegaLiteVis)
+ divid = "vl" * randstring(10) # generated id for this plot
+
+ fh = """
+
+ """
+ # FIXME : understand why vega-embed can't be loaded
+ # SVG and SAVE_BUTTONS flags are ignored
+ # vg.embed("#$divid", embedSpec, function(error, result) {
+
+ write(io, fh)
+end
+
+
+export writemime
diff --git a/src/render.jl b/src/render.jl
index 0fabcae0..88e31210 100644
--- a/src/render.jl
+++ b/src/render.jl
@@ -29,6 +29,8 @@ function writehtml(io::IO, v::VegaLiteVis; title="Vega.jl Visualization")
var embedSpec = {
mode: "vega-lite",
+ renderer: "$(SVG ? "svg" : "canvas")",
+ actions: $SAVE_BUTTONS,
spec: $(JSON.json(v.vis))
}
@@ -65,7 +67,6 @@ end
###################################################
-import Base.writemime
# asset(url...) = readall(Pkg.dir("Vega", "assets", "bower_components", url...))
@@ -82,7 +83,7 @@ import Base.writemime
# """)
# end
#
-import Patchwork: Elem
+# import Patchwork: Elem
# function patchwork_repr(v::VegaLiteVis)
# divid = "vg" * randstring(3)
@@ -151,9 +152,211 @@ import Patchwork: Elem
# write(io, fh)
# end
-jspath(url...) = Pkg.dir("VegaLite", "assets", "bower_components", url...)
+# function jslibpath(url...)
+# libpath = Pkg.dir("VegaLite", "assets", "bower_components", url...)
+# replace(libpath, "\\", "/") # for windows...
+# end
+#
+#
+# function writemime(io::IO, m::MIME"text/html", v::VegaLiteVis)
+# divid = "vl" * randstring(3) # generated id for this plot
+
+# script = """
+# require.config({
+# paths: {
+# d3: "https://d3js.org/d3.v3.min",
+# vega: "https://vega.github.io/vega/vega.min",
+# vegalite: "https://vega.github.io/vega-lite/vega-lite",
+# vegaembed: "https://vega.github.io/vega-editor/vendor/vega-embed"
+# }
+# });
+#
+# require(["d3"], function(d3){
+#
+# window.d3 = d3;
+#
+# require(["vega", "vegalite", "vegaembed"],
+# function(vg, vgl, vge){
+#
+# // window.vg = vg;
+#
+# vg.parse.spec({
+# "description": "A simple bar chart with embedded data.",
+# "data": {
+# "values": [
+# {"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
+# {"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
+# {"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
+# ]
+# },
+# "mark": "bar",
+# "encoding": {
+# "x": {"field": "a", "type": "ordinal"},
+# "y": {"field": "b", "type": "quantitative"}
+# }
+# }, function(chart) { chart({el:"#$divid"}).update(); });
+#
+# document.getElementById("$divid").insertAdjacentHTML('beforeend', '
Save yourgh ! as PNG')
+#
+#
+# });
+# });
+# """
+#
+# spec = """
+# {
+# "width": 400,
+# "height": 200,
+# "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10},
+# "data": [
+# {
+# "name": "table",
+# "values": [
+# {"x": 1, "y": 28}, {"x": 2, "y": 55},
+# {"x": 3, "y": 43}, {"x": 4, "y": 91},
+# {"x": 5, "y": 81}, {"x": 6, "y": 53},
+# {"x": 7, "y": 19}, {"x": 8, "y": 87},
+# {"x": 9, "y": 52}, {"x": 10, "y": 48},
+# {"x": 11, "y": 24}, {"x": 12, "y": 49},
+# {"x": 13, "y": 87}, {"x": 14, "y": 66},
+# {"x": 15, "y": 17}, {"x": 16, "y": 27},
+# {"x": 17, "y": 68}, {"x": 18, "y": 16},
+# {"x": 19, "y": 49}, {"x": 20, "y": 15}
+# ]
+# }
+# ],
+# "scales": [
+# {
+# "name": "x",
+# "type": "ordinal",
+# "range": "width",
+# "domain": {"data": "table", "field": "x"}
+# },
+# {
+# "name": "y",
+# "type": "linear",
+# "range": "height",
+# "domain": {"data": "table", "field": "y"},
+# "nice": true
+# }
+# ],
+# "axes": [
+# {"type": "x", "scale": "x"},
+# {"type": "y", "scale": "y"}
+# ],
+# "marks": [
+# {
+# "type": "rect",
+# "from": {"data": "table"},
+# "properties": {
+# "enter": {
+# "x": {"scale": "x", "field": "x"},
+# "width": {"scale": "x", "band": true, "offset": -1},
+# "y": {"scale": "y", "field": "y"},
+# "y2": {"scale": "y", "value": 0}
+# },
+# "update": {
+# "fill": {"value": "steelblue"}
+# },
+# "hover": {
+# "fill": {"value": "red"}
+# }
+# }
+# }
+# ]
+# }
+# """
+#
+# spec2 = """
+# {
+# "description": "A simple bar chart with embedded data.",
+# "data": {
+# "values": [
+# {"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
+# {"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
+# {"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
+# ]
+# },
+# "mark": "bar",
+# "encoding": {
+# "x": {"field": "a", "type": "ordinal"},
+# "y": {"field": "b", "type": "quantitative"}
+# }
+# }
+# """
+#
+# script = """
+# require.config({
+# paths: {
+# d3: "https://vega.github.io/vega-editor/vendor/d3.min",
+# vega: "https://vega.github.io/vega/vega.min",
+# cloud: "https://vega.github.io/vega-editor/vendor/d3.layout.cloud",
+# topojson: "https://vega.github.io/vega-editor/vendor/topojson",
+# vegalite: "https://vega.github.io/vega-lite/vega-lite",
+# embed: "https://vega.github.io/vega-editor/vendor/vega-embed"
+# }
+# });
+#
+# require(["d3", "topojson", "cloud"], function(d3, topojson, cloud){
+#
+# window.d3 = d3;
+# window.topojson = topojson;
+# window.d3.layout.cloud = cloud;
+# console.log("d3")
+#
+#
+# require(["vega"], function(vg) {
+#
+# window.vg = vg
+# console.log("vg")
+#
+# require(["vegalite"], function(vgl) {
+#
+# console.log("vegalite")
+#
+# var embedSpec = {
+# renderer: "svg",
+# actions: false,
+# spec: $spec2
+# };
+#
+# var vgSpec = vgl.compile(embedSpec.spec).spec;
+# vg.parse.spec(vgSpec, function(chart) { chart({el:\"#$divid\"}).update(); });
+#
+# }); //vegaembed require end
+# }); //vega require end
+#
+# }); //d3 require end
+# """
+ # vg.embed("#$divid", embedSpec, function(error, result) { });
+ # vg.parse.spec($spec, function(chart) { chart({el:\"#$divid\"}).update(); });
+
+
+ # window.setTimeout(function() {
+ # var pnglink = document.getElementById(\"$divid\").getElementsByTagName(\"canvas\")[0].toDataURL(\"image/png\")
+ # document.getElementById(\"$divid\").insertAdjacentHTML('beforeend', '
Save as PNG')
+ #
+ # }, 20);
+
+ # var vgSpec = vgl.compile(embedSpec.spec).spec;
+ # var embedSpec = {
+ # mode: "vega-lite",
+ # renderer: "svg",
+ # actions: false,
+ # spec: $(JSON.json(v.vis))
+ # };
+ #
+ # vg.embed("#$divid", embedSpec, function(error, result) { result.view });
+
+ # patch = Elem(:div, [
+ # Elem(:div, "") & Dict(:id=>divid, :style=>Dict("min-height"=>"300px")),
+ # # Elem(:div, "") & Dict(:id=>divid),
+ # Elem(:script, script) & Dict(:type=>"text/javascript")
+ # ])
+ #
+ # return writemime(io, m, patch)
+
-function writemime(io::IO, m::MIME"text/html", v::VegaLiteVis)
# fh = """
#
#
@@ -161,50 +364,66 @@ function writemime(io::IO, m::MIME"text/html", v::VegaLiteVis)
#
#
- fh = """
-
- """
-
- println(fh)
- # writemime(io, m, fh)
- write(io, fh)
-end
-
-
-export writemime
+ # // d3: "$(jslibpath("d3","d3.min.js"))",
+ # // vega: "$(jslibpath("vega", "vega.js"))",
+ # // vegalite: "$(jslibpath("vega-lite", "vega-lite.js"))",
+ # // vegaembed: "$(jslibpath("vega-embed", "vega-embed.js"))"
+#
+# fh = """
+#
+# """
+# # FIXME : understand why vega-embed can't be loaded
+# # vg.embed("#$divid", embedSpec, function(error, result) {
+#
+# println(fh)
+# # writemime(io, m, fh)
+# write(io, fh)
+# end
+#
+#
+# export writemime
diff --git a/src/utils.jl b/src/utils.jl
index 473b7e96..2a902c8d 100644
--- a/src/utils.jl
+++ b/src/utils.jl
@@ -21,6 +21,29 @@ softmerge(a::Dict, b::Any) = a
softmerge(a::Any, b::Dict) = b
softmerge(a, b) = b
+
+
+
+
+# Switch for plotting in SVGs or canvas
+SVG = true
+svg() = SVG
+svg(b::Bool) = (global SVG ; SVG = b)
+
+
+
+
+# Switch for showing or not the "save as PNG buttons"
+SAVE_BUTTONS = true
+buttons() = SAVE_BUTTONS
+buttons(b::Bool) = (global SAVE_BUTTONS ; SAVE_BUTTONS = b)
+
+
+
+
+
+
+
# build Dict from kwargs, checks against signature
function _mkdict(signature, properties)
d = Dict()
diff --git a/test/debug.jl b/test/debug.jl
new file mode 100644
index 00000000..ae602968
--- /dev/null
+++ b/test/debug.jl
@@ -0,0 +1,179 @@
+module A ; end
+reload("VegaLite")
+reload("Paper")
+
+
+module A
+using Paper
+using VegaLite
+import JSON
+
+
+# config(abcd="trus")
+# config(viewport="trus")
+# config(viewport=[400,330])
+# JSON.json(v.vis)
+
+@session vgtest vbox pad(2em)
+
+@rewire VegaLite.VegaLiteVis
+
+sleep(3.0)
+vv = Paper.currentSession.window
+push!(vv.assets, ("VegaLite", "vega-lite"))
+
+#-------- draw the header ----------------------------------
+@newchunk pg vbox packacross(center) fillcolor("#ddd") pad(1em)
+
+title(2, "Veg Lite")
+title(1, "with plots using VegaLite") |> fontstyle(italic)
+
+#------- plot ------------------------------------
+@newchunk center
+
+ts = sort(rand(10))
+ys = Float64[ rand()*0.1 + cos(x) for x in ts]
+
+v = data_values(time=ts, res=ys) +
+ mark_line() +
+ encoding_x_quant(:time) +
+ encoding_y_quant(:res)
+
+buttons(false)
+svg(false)
+
+@newchunk center2 hbox
+@newchunk center2.nw hbox
+
+container(10em,10em) |> fillcolor("#daa")
+hline() |> fillcolor("#daa")
+vskip(1em)
+
+v2 = v + config_scale(round=true)
+JSON.print(v2.vis)
+
+
+v2 = v + config_axis(axisWidth=3.2, labelAngle=45)
+v2 = v + config_axis(labelAlign="left")
+v2 = v + config_axis(tickPadding=10)
+JSON.print(v2.vis)
+
+
+
+v = data_values(time=[ts, reverse(ts)], res=[ys, reverse(ys-0.3)]) +
+ mark_area() +
+ encoding_x_quant(:time) +
+ encoding_y_quant(:res) +
+ # encoding_path_quant() +
+ config_cell(width=300, height=300)
+
+v |> fontstyle(italic)
+
+data_values(posit=[1:2length(ts);], time=[ts, reverse(ts)], res=[ys, reverse(ys-0.3)]) +
+ mark_line() +
+ encoding_x_quant(:time, scale=Dict(:domain=>[0,1])) +
+ encoding_y_quant(:res) +
+ encoding_path_ord(:posit) +
+ config(background="#eee") +
+ config_grid(gridColor="green") +
+ config_mark(font="Courrier New", strokeDash=[5,5], stroke="red",
+ filled=true, fill="#8e8", fillOpacity=0.2) +
+ config_cell(width=200, height=150, strokeWidth=.2, strokeDash=[10,5])
+
+
+JSON.print(data_values(posit=[1:2length(ts);], time=[ts, reverse(ts)], res=[ys, reverse(ys-0.3)]))
+
+@newchunk rdataset
+
+using RDatasets
+
+mpg = dataset("ggplot2", "mpg")
+
+
+data_values(mpg) +
+ mark_point() +
+ encoding_x_quant(:Cty) +
+ encoding_y_quant(:Hwy)
+
+data_values(mpg) +
+ mark_point() +
+ encoding_x_quant(:Cty, axis=false) +
+ encoding_y_quant(:Hwy, scale=scale(zero=false)) +
+ encoding_color_nominal(:Manufacturer) +
+ config_cell(width=350, height=400)
+
+data_values(mpg) +
+ mark_line() +
+ encoding_x_ord(:Year,
+ axis = axis(labelAngle=-45, labelAlign="right"),
+ scale = scale(bandSize=50)) +
+ encoding_y_quant(:Hwy, aggregate="mean") +
+ encoding_color_nominal(:Manufacturer)
+
+data_values(mpg) +
+ mark_point() +
+ encoding_column_ord(:Cyl) +
+ encoding_row_ord(:Year) +
+ encoding_x_quant(:Displ) +
+ encoding_y_quant(:Hwy) +
+ encoding_size_quant(:Cty) +
+ encoding_color_nominal(:Manufacturer)
+
+data_values(mpg) +
+ mark_text() +
+ encoding_column_ord(:Cyl) +
+ encoding_row_ord(:Year) +
+ encoding_text_quant(:Displ, aggregate="mean") +
+ config_mark(fontStyle="italic", fontSize=12, font="courier")
+
+
+##################### IJulia #######################
+
+Pkg.build("IJulia")
+Pkg.build("IJulia")
+Pkg.build("IJulia")
+
+using IJulia
+@async notebook()
+
+using SHA
+sha256("abcde")
+5+6
+
+WARNING:root:kernel 6e1e5e58-776c-4d0e-b9e2-0d934ff40742 restarted
+WARNING: Union(args...) is deprecated, use Union{args...} instead.
+ in depwarn at deprecated.jl:73
+ in call at deprecated.jl:50
+ in include at boot.jl:261
+ in include_from_node1 at loading.jl:304
+ in include at boot.jl:261
+ in include_from_node1 at loading.jl:304
+ in include at boot.jl:261
+ in include_from_node1 at loading.jl:304
+ in process_options at client.jl:280
+ in _start at client.jl:378
+while loading D:\frtestar\.julia\v0.4\IJulia\src\handlers.jl, in expression starting on line 49
+ERROR: LoadError: UndefVarError: SHA256 not defined
+ in init at D:\frtestar\.julia\v0.4\IJulia\src\IJulia.jl:62
+ in include at boot.jl:261
+ in include_from_node1 at loading.jl:304
+ in process_options at client.jl:280
+ in _start at client.jl:378
+while loading D:\frtestar\.julia\v0.4\IJulia\src\kernel.jl, in expression starting on line 6
+[I 14:40:00.311 NotebookApp] KernelRestarter: restarting kernel (1/5)
+
+using Nettle
+
+signature_scheme = "hmac-sha256"
+isempty(signature_scheme) && (signature_scheme = "hmac-sha256")
+signature_scheme = split(signature_scheme, "-")
+if signature_scheme[1] != "hmac" || length(signature_scheme) != 2
+ error("unrecognized signature_scheme")
+end
+global const hmacstate = HMACState(eval(symbol(uppercase(signature_scheme[2]))),
+ profile["key"])
+
+
+HMACState(uppercase(signature_scheme[2]), "abcd")
+import IJulia
+whos(IJulia)