Skip to content

Commit

Permalink
New @manipulate syntax. Addresses #8
Browse files Browse the repository at this point in the history
  • Loading branch information
shashi committed Aug 22, 2014
1 parent 8214d37 commit 4f920bf
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 68 deletions.
80 changes: 41 additions & 39 deletions doc/notebooks/Introduction.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"language": "Julia",
"name": "",
"signature": "sha256:1b47130e7dc41ef94a6ee0e47ba98d387c122f9450b974aadf0d9900655fc51c"
"signature": "sha256:3e66accf11f2fc875daf586aaf78c6293c07d2a12d9cc5ff2a0b6ab012f6ecb4"
},
"nbformat": 3,
"nbformat_minor": 0,
Expand Down Expand Up @@ -222,10 +222,10 @@
"\t\t\t var selector = $(self).empty();\n",
"\t\t\t var oa = new IPython.OutputArea(_.extend(selector, {\n",
"\t\t\t\tselector: selector,\n",
"\t\t\t\tprompt_area: true,\n",
"\t\t\t\tprompt_area: false,\n",
"\t\t\t\tevents: IPython.events,\n",
"\t\t\t\tkeyboard_manager: IPython.keyboard_manager\n",
"\t\t\t })); // Hack to work with IPython 2.1.0\n",
"\t\t\t }), false); // Hack to work with IPython 2.1.0\n",
"\t\t\t var toinsert = IPython.OutputArea.append_map[type].apply(\n",
"\t\t\t\toa, [val[type], {}, selector]\n",
"\t\t\t );\n",
Expand Down Expand Up @@ -310,7 +310,7 @@
"output_type": "pyout",
"prompt_number": 2,
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"Slider X:\",0.0,0.0:0.01:1.0)"
"Slider{Float64}([Input{Float64}] 0.5,\"Slider X:\",0.5,0.0:0.01:1.0)"
]
}
],
Expand All @@ -327,13 +327,13 @@
"outputs": [
{
"metadata": {
"comm_id": "8f301332-acbe-4e55-9e10-3af2ed0117b9",
"comm_id": "cc6abb10-6540-48f3-b3f9-c463e13bb194",
"reactive": true
},
"output_type": "pyout",
"prompt_number": 3,
"text": [
"0.0"
"0.5"
]
}
],
Expand Down Expand Up @@ -424,7 +424,7 @@
"output_type": "pyout",
"prompt_number": 6,
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"Slider X:\",0.0,0.0:0.01:1.0)"
"Slider{Float64}([Input{Float64}] 0.5,\"Slider X:\",0.5,0.0:0.01:1.0)"
]
}
],
Expand Down Expand Up @@ -456,13 +456,13 @@
"outputs": [
{
"metadata": {
"comm_id": "73694993-c028-4068-b463-1c15ddd1f418",
"comm_id": "002ca03a-93ca-4ded-9f92-9f7e287bae1d",
"reactive": true
},
"output_type": "pyout",
"prompt_number": 7,
"text": [
"0.0"
"0.25"
]
}
],
Expand Down Expand Up @@ -494,7 +494,7 @@
"outputs": [
{
"metadata": {
"comm_id": "d341d1f4-3c5b-4964-ae8b-8e9afee04ecf",
"comm_id": "c21bcf33-c04a-4c60-bf4b-063068cdad09",
"reactive": true
},
"output_type": "pyout",
Expand All @@ -506,11 +506,11 @@
"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n",
" width=\"25mm\" height=\"25mm\" viewBox=\"0 0 1 1\">\n",
" <rect width=\"1\" height=\"1\"\n",
" fill=\"#008080\" stroke=\"none\"/>\n",
" fill=\"#808080\" stroke=\"none\"/>\n",
"</svg>\n"
],
"text": [
"RGB{Float64}(0.0,0.5,0.5)"
"RGB{Float64}(0.5,0.5,0.5)"
]
}
],
Expand Down Expand Up @@ -540,23 +540,23 @@
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"R\",0.0,0.0:0.01:1.0)"
"Slider{Float64}([Input{Float64}] 0.5,\"R\",0.5,0.0:0.01:1.0)"
]
},
{
"html": [],
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"G\",0.0,0.0:0.01:1.0)"
"Slider{Float64}([Input{Float64}] 0.5,\"G\",0.5,0.0:0.01:1.0)"
]
},
{
"html": [],
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"B\",0.0,0.0:0.01:1.0)"
"Slider{Float64}([Input{Float64}] 0.5,\"B\",0.5,0.0:0.01:1.0)"
]
}
],
Expand All @@ -573,7 +573,7 @@
"outputs": [
{
"metadata": {
"comm_id": "d12c863d-0ce5-4f7b-99d6-fb35d647afa4",
"comm_id": "d7e76890-a1d0-4cc5-833e-8e9059bf4362",
"reactive": true
},
"output_type": "pyout",
Expand All @@ -585,11 +585,11 @@
"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n",
" width=\"25mm\" height=\"25mm\" viewBox=\"0 0 1 1\">\n",
" <rect width=\"1\" height=\"1\"\n",
" fill=\"#000000\" stroke=\"none\"/>\n",
" fill=\"#808080\" stroke=\"none\"/>\n",
"</svg>\n"
],
"text": [
"RGB{Float64}(0.0,0.0,0.0)"
"RGB{Float64}(0.5,0.5,0.5)"
]
}
],
Expand All @@ -613,7 +613,7 @@
"outputs": [
{
"metadata": {
"comm_id": "2eb6a43b-21d6-4f7d-8484-c7beb342b014",
"comm_id": "bb35010a-9a77-4678-9979-ee85f2a3e1f7",
"reactive": true
},
"output_type": "pyout",
Expand All @@ -625,11 +625,11 @@
"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n",
" width=\"25mm\" height=\"25mm\" viewBox=\"0 0 1 1\">\n",
" <rect width=\"1\" height=\"1\"\n",
" fill=\"#000000\" stroke=\"none\"/>\n",
" fill=\"#808080\" stroke=\"none\"/>\n",
"</svg>\n"
],
"text": [
"RGB{Float64}(0.0,0.0,0.0)"
"RGB{Float64}(0.5,0.5,0.5)"
]
}
],
Expand Down Expand Up @@ -657,7 +657,7 @@
"output_type": "pyout",
"prompt_number": 12,
"text": [
"HTML(\"\",\"<div style='color:#000000'>Hello, World!</div>\")"
"HTML(\"\",\"<div style='color:#808080'>Hello, World!</div>\")"
]
}
],
Expand All @@ -682,7 +682,9 @@
"cell_type": "code",
"collapsed": false,
"input": [
"@manipulate HTML(string(\"<div style='color:#\", hex(RGB(r,g,b)), \"'>Color me concise</div>\")) r in 0:.01:1 g in 0:.01:1 b in 0:.01:1"
"@manipulate for r = 0:.05:1, g = 0:.05:1, b = 0:.05:1\n",
" HTML(string(\"<div style='color:#\", hex(RGB(r,g,b)), \"'>Color me concise</div>\"))\n",
"end"
],
"language": "python",
"metadata": {},
Expand All @@ -692,36 +694,36 @@
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"r\",0.0,0.0:0.01:1.0)"
"Slider{Float64}([Input{Float64}] 0.5,\"r\",0.5,0.0:0.05:1.0)"
]
},
{
"html": [],
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"g\",0.0,0.0:0.01:1.0)"
"Slider{Float64}([Input{Float64}] 0.5,\"g\",0.5,0.0:0.05:1.0)"
]
},
{
"html": [],
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"b\",0.0,0.0:0.01:1.0)"
"Slider{Float64}([Input{Float64}] 0.5,\"b\",0.5,0.0:0.05:1.0)"
]
},
{
"html": [],
"metadata": {},
"output_type": "pyout",
"prompt_number": 13,
"prompt_number": 16,
"text": [
"HTML(\"\",\"<div style='color:#000000'>Color me concise</div>\")"
"HTML(\"\",\"<div style='color:#808080'>Color me concise</div>\")"
]
}
],
"prompt_number": 13
"prompt_number": 16
},
{
"cell_type": "heading",
Expand Down Expand Up @@ -755,27 +757,27 @@
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"x\",0.0,0.0:0.1:6.2)"
"Slider{Float64}([Input{Float64}] 3.1,\"x\",3.1,0.0:0.1:6.2)"
]
},
{
"html": [],
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"sin(2x)\",0.0,-1.0:0.05:1.0)"
"Slider{Float64}([Input{Float64}] -0.0830894028174964,\"sin(2x)\",-0.0830894028174964,-1.0:0.05:1.0)"
]
},
{
"html": [],
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 1.0,\"cos(2x)\",1.0,-1.0:0.05:1.0)"
"Slider{Float64}([Input{Float64}] 0.9965420970232175,\"cos(2x)\",0.9965420970232175,-1.0:0.05:1.0)"
]
}
],
"prompt_number": 14
"prompt_number": 17
},
{
"cell_type": "markdown",
Expand All @@ -802,17 +804,17 @@
"outputs": [
{
"metadata": {
"comm_id": "bd169aee-45ea-44b0-a7c0-3b95c75da957",
"comm_id": "cc360816-9f36-429a-9651-eecebe961d2e",
"reactive": true
},
"output_type": "pyout",
"prompt_number": 15,
"prompt_number": 18,
"text": [
"0.0"
]
}
],
"prompt_number": 15
"prompt_number": 18
},
{
"cell_type": "code",
Expand All @@ -830,19 +832,19 @@
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"x\",0.0,0.0:0.1:6.2)"
"Slider{Float64}([Input{Float64}] 3.1,\"x\",3.1,0.0:0.1:6.2)"
]
},
{
"html": [],
"metadata": {},
"output_type": "display_data",
"text": [
"Slider{Float64}([Input{Float64}] 0.0,\"f(x)\",0.0,-1.0:0.05:1.0)"
"Slider{Float64}([Input{Float64}] 0.0,\"f(x)\",0.04158066243329049,-1.0:0.05:1.0)"
]
}
],
"prompt_number": 16
"prompt_number": 19
},
{
"cell_type": "markdown",
Expand Down
78 changes: 49 additions & 29 deletions src/manipulate.jl
Original file line number Diff line number Diff line change
@@ -1,41 +1,61 @@
export @manipulate

function make_widget(spec::Expr, m::Module)
if spec.head != :in ||
!isa(spec.args[1], Symbol)
error("Widget spec must be of the form <symbol> in <domain>")
end
sym = spec.args[1]
label = string(sym)
domain = eval(m, spec.args[2])
if isa(domain, Widget)
return sym, domain
function widget(domain, label)
if isa(domain, Signal)
return domain
elseif isa(domain, Widget)
return domain
elseif isa(domain, Range)
return sym, Slider(domain, label=label)
return Slider(domain, label=label)
elseif isa(domain, Tuple) || isa(domain, Vector)
return sym, ToggleButtons(domain, label=label)
return ToggleButtons(domain, label=label)
elseif isa(domain, Bool)
return sym, Checkbox(value=domain, label=label)
return Checkbox(value=domain, label=label)
elseif isa(domain, String)
return sym, Textbox(domain, label=label)
return Textbox(domain, label=label)
else
# XXX: What can be done?
# XXX: TODO: Add React.constant - a constant signal.
error("There is no widget for the value ", domain)
end
end

macro manipulate(ex, specs...)
m = current_module()
mapping = map(s->make_widget(s, m), specs)
fst(t) = t[1]
snd(t) = t[2]
widgets = map(snd, mapping)
result = Expr(:call, :lift,
Expr(:->,
Expr(:tuple, map(fst, mapping)...), ex),
map(signal, widgets)...)
# TODO: `hstack` widgets instead of just display()-ing them
return Expr(:block,
map(w -> Expr(:call, :display, w), widgets)...,
esc(result))
function make_widget(binding)
if binding.head != :(=)
error("@manipulate syntax error.")
end
sym, expr = binding.args
Expr(:(=), esc(sym),
Expr(:call, widget, esc(expr), string(sym)))
end

function display_widgets(widgetvars)
map(v -> Expr(:call, esc(:display), esc(v)), widgetvars)
end

function lift_block(block, symbols)
lambda = Expr(:(->), Expr(:tuple, symbols...),
block)
Expr(:call, React.lift, lambda, symbols...)
end

function symbols(bindings)
map(x->x.args[1], bindings)
end

macro manipulate(expr)
if expr.head != :for
error("@manipulate syntax is @manipulate for ",
" [<variable>=<domain>,]... <expression> end")
end
block = expr.args[2]
if expr.args[1].head == :block
bindings = expr.args[1].args
else
bindings = [expr.args[1]]
end
syms = symbols(bindings)
Expr(:let, Expr(:block,
display_widgets(syms)...,
esc(lift_block(block, syms))),
map(make_widget, bindings)...)
end

0 comments on commit 4f920bf

Please sign in to comment.