# Some Interact updates: create your custom widgets easily and composably

**URL:** https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192
**Category:** Community
**Tags:** announcement, web, webapps
**Created:** [August 28, 2018, 3:28pm UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192 "2018-08-28T15:28:29Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [August 28, 2018, 3:28pm UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/1 "2018-08-28T15:28:29Z")

</div>

First of all, I’m happy to say that the Interact package (now based on InteractBase) was updated to Julia 1.0 (thanks to the amazing help of many people, esp. the heroic JuliaRobotics developers who fixed a large number of relevant packages).

## Custom widgets

After a lengthy design discussion with `@shashi` at JuliaCon, we have finalized the recipe framework (a way for the user to define their own recipes), with a focus on simplicity and composability.

In short it works as follows: a `Widget` is basically a `mutable struct` with some components, an output and a layout. The `Interact.@map` macro allows to use `Widgets` like normal values (for example, a slider will be replaced by the numerical value it represents) and the result will be updated when it changes. Here for example we can create a widget with 3 components (`color1, color2, legendpos`) and a plot as output. The layout will be the default (components and then the output are disposed vertically one after another).

```julia
using Interact
using Interact: @map
using Colors, Plots

function myplot(color1, color2, legendpos)
    output = Interact.@map plot([sin, cos], color = [&color1 &color2], legend = &legendpos, label = ["sin" "cos"])
    Widget([:color1 => color1, :color2 => color2, :legendpos => legendpos], output = output)
end

ui = myplot(colorpicker(), colorpicker(), togglebuttons([:topleft, :topright, :bottomleft, :bottomright]));

```

 ![colorpicker](https://global.discourse-cdn.com/julialang/original/3X/b/f/bfe8353d1d85adf399b833a145e36db80e35703f.png)

However this design is very flexible, we can create our own `colorpicker` and use it instead:

```julia
function mycolorpicker()
    r = slider(0:255, label = "red")
    g = slider(0:255, label = "green")
    b = slider(0:255, label = "blue")
    output = @map Colors.RGB(&r/255, &g/255, &b/255)
    wdg = Widget(["r" => r, "g" => g, "b" => b], output = output) # it outputs a color, so it can be used as colorpicker
    @layout! wdg vbox(:r, :g, :b) # custom layout: only display the three sliders aligned vertically but don't display the output color

ui = myplot(mycolorpicker(), mycolorpicker(), togglebuttons([:topleft, :topright, :bottomleft, :bottomright]));

```

 ![mycolorpicker](https://global.discourse-cdn.com/julialang/original/3X/c/0/c0206a87ac71294f124f10352d47cb98bf4bacbd.png)

For more details be sure to checkout the [Interact docs](https://juliagizmos.github.io/Interact.jl/latest/index.html) (esp. the Custom widgets section and the tutorial).

## Deployment

Interact apps are reasonably easy to deploy: see [here](https://juliagizmos.github.io/Interact.jl/latest/deploying.html) for details. As an example, you can check out the GitHub repository a pure Julia website of Interact demos [here](https://github.com/piever/InteractDemos). The site is not yet up online but you can easily set it up on your machine (or on your server) following the instructions on the README, then check it out at `http://localhost:8000/` or `yourserverIP:8000`

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [August 28, 2018, 3:32pm UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/2 "2018-08-28T15:32:37Z")

</div>

To package developers: if you are interested in creating custom `Widgets` for your types and functions in your packages, now is a good time to get started! For example, StatPlots already has a [GUI](https://github.com/JuliaPlots/StatPlots.jl#visualizing-a-table-interactively-important-works-on-julia-06-only-will-take-a-while-to-update) but this kind of simple UI to work with data makes sense in a lot of other packages (data manipulation packages, GLM) etc. Look at the [custom widgets](https://juliagizmos.github.io/Interact.jl/latest/custom_widgets.html) section of the docs if you have doubts, or feel free to ask here or in the Gizmos slack channel.

---

<div class="post-metadata">

### Author: ![waldyrious](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waldyrious/32/80_2.png) [@waldyrious](https://discourse.julialang.org/u/waldyrious)
#### Post date: [August 28, 2018, 5:16pm UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/3 "2018-08-28T17:16:17Z")

</div>

Some feedback starting from a freshly installed Julia 1.0, in case this helps:

I tried saving that code and running it (`julia interact-demo.jl`), and got the following error:

> ERROR: LoadError: ArgumentError: Package Interact not found in current path:  
> - Run `Pkg.add("Interact")` to install the Interact package.

This is obvious – of course the Interact package must be installed to run a demo of the Interact package!

(As a small aside, the error message is incomplete (it should be `import Pkg; Pkg.add("Interact")`, but this has already been fixed in Julia master, via [PR #28555](https://github.com/JuliaLang/julia/pull/28555))

Attempting to run the script after installing the `Interact` package produced a similar error, this time for the Colors package:

> ERROR: LoadError: ArgumentError: Package Colors not found in current path:  
> - Run `Pkg.add("Colors")` to install the Colors package.

However, after installing Colors, the error was now a bit more cryptic:

> ERROR: LoadError: UndefVarError: plot not defined  
> Stacktrace:  
> […]  
> in expression starting at /home/waldyrious/interact-demo.jl:10

I assumed this means I should install Plots, so I did. After this, running the script still produced the same error as before, so I added a line with `using Plots` under the other “using” lines.

This time I could run the script without errors, but the program simply exits after a while, without doing anything. Am I missing something?

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [August 28, 2018, 5:41pm UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/4 "2018-08-28T17:41:51Z")

</div>

Ups, yes, you’ll need `using Plots` and to add all the required packages:

`] add Plots Colors Interact`

There are several way to visualizing the UI (corresponding in the example above to `ui`):

- in the Jupyter notebook: it will appear inline automatically
- in Juno: it should also be more or less automatic but Juno Interact integration in Julia 1.0 is WIP
- in the REPL: you will need Blink to display it in a Blink window:

```julia
] add Blink
w = Window()
body!(w, ui)

```

- in the browser (from your machine or a server):

```julia
] add Mux
WebIO.webio_serve(page("/", req -> ui))

```

and then open the browser at `localhost:8000`

This is all in the [deploying section](https://juliagizmos.github.io/Interact.jl/latest/deploying.html) of the docs: that section could probably be expanded a bit.

EDIT: fixed `webio_serve` command

---

<div class="post-metadata">

### Author: ![waldyrious](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waldyrious/32/80_2.png) [@waldyrious](https://discourse.julialang.org/u/waldyrious)
#### Post date: [August 28, 2018, 8:06pm UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/5 "2018-08-28T20:06:54Z")

</div>

Ah, didn’t realize this was meant to be run in the REPL. I re-ran the first block of code in the REPL, followed by `]add Mux` and `using Mux`, and then I was able to run `WebIO.webio_serve(req -> ui)`:

```julia
julia> WebIO.webio_serve(req -> ui)
[ Info: Listening on: Sockets.InetAddr{Sockets.IPv4}(ip"127.0.0.1", 0x1f40)
[ Info: Accept: 🔗 0↑ 0↓ 0s 127.0.0.1:8000:8000 ≣16
[ Info: Closed: 💀 0↑ 1↓🔒 130s 127.0.0.1:8000:8000 ≣16
^C┌ Warning: Interrupted: listen(Sockets.InetAddr{Sockets.IPv4}(ip"127.0.0.1", 0x1f40))
└ @ HTTP.Servers ~/.julia/packages/HTTP/nUK4f/src/Servers.jl:379

```

For some reason, however, nothing was served when visiting [http://localhost:8000/](http://localhost:8000/) – the page simply remained in the loading stage until I closed it (as the command output above shows). Any hints what I might still be missing, @piever?

* * *

I had better luck with Blink:

```julia
julia> ] add Blink
...
julia> using Blink
julia> w = Window()
ERROR: Cannot find Electron. Try `Blink.AtomShell.install()`
...
julia> Blink.AtomShell.install()
...
w = Window()
Window(1, Electron(Process(`/home/waldyrious/.julia/packages/Blink/KMJt9/deps/atom/electron /home/waldyrious/.julia/packages/Blink/KMJt9/src/AtomShell/main.js port 4949`, ProcessRunning), Sockets.TCPSocket(RawFD(0x00000011) active, 0 bytes waiting), Dict{String,Any}("callback"=>##1#2())), Page(1, #undef, Dict{String,Any}("callback"=>##1#2()), Distributed.Future(1, 1, 1, Some(true))))

julia> body!(w, ui)
Page(1, WebSockets.WebSocket{Sockets.TCPSocket}(Sockets.TCPSocket(RawFD(0x00000018) active, 0 bytes waiting), true, CONNECTED::ReadyState = 1), Dict{String,Any}("webio"=>##77#78{BlinkConnection}(BlinkConnection(Page(#= circular reference @-4 =#))),"callback"=>##1#2()), Distributed.Future(1, 1, 1, Some(true)))

```

That finally allowed me to see the UI, although I kept getting these `Gtk-Message: Failed to load module "pantheon-filechooser-module"` warnings in the console. Anyway, just reporting my experience in case it helps others (or provides the perspective of a beginner to the developers of Interact :))

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [August 29, 2018, 5:29pm UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/6 "2018-08-29T17:29:19Z")

</div>

Thanks for the feedback!

> [@waldyrious](#):
>
> For some reason, however, nothing was served when visiting [http://localhost:8000/](http://localhost:8000/) – the page simply remained in the loading stage until I closed it (as the command output above shows). Any hints what I might still be missing?

That’s a bit worrying, I wonder whether it’s simply due to the Plots precompile so it seemed like nothing was happening: could you maybe try making some warm up plot and then running the app to see if something shows up? Otherwise do open an issue either at Mux or WebIO.

---

<div class="post-metadata">

### Author: ![waldyrious](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waldyrious/32/80_2.png) [@waldyrious](https://discourse.julialang.org/u/waldyrious)
#### Post date: [August 30, 2018, 11:51pm UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/7 "2018-08-30T23:51:16Z")

</div>

> [@piever](#):
>
> could you maybe try making some warm up plot

I tried a couple calls to plot(): `plot([sin, cos])`, `plot([sin, cos, exp])`, `plot([sin, cos, log])` – all of which produced Gtk (IIUC) windows with the plots visible. But running `using Mux; WebIO.webio_serve(req -> ui)` afterwards still left me with an empty (forever loading) page when visiting localhost:8000.

Any ideas if there are better warm-up plot commands I should have run instead? Otherwise, if this might be a bug in Mux or WebIO, how do you suggest I describe it, and on which of the repos should I open it?

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [August 31, 2018, 8:48am UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/8 "2018-08-31T08:48:35Z")

</div>

Actually, this is probably my bad! Somehow I think that you also need to specify on what “page” of the website you want to run the app, so to have it at [http://localhost:8000](http://localhost:8000) you need to say:

`WebIO.webio_serve(page("/", req -> ui))`

whereas for example `WebIO.webio_serve(page("/test", req -> ui))` would serve it at [http://localhost:8000/test](http://localhost:8000/test). This is useful when you want to serve multiple pages, in which case you can “stack” the two apps:

```julia
app1 = page("/", req -> ui1)
app2 = page("/test", req -> ui2)
app = Mux.stack(app1, app2)
WebIO.webio_serve(app)

```

I’m not sure why omitting this worked at some point on my machine. I’ll edit the original post.

---

<div class="post-metadata">

### Author: ![waldyrious](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waldyrious/32/80_2.png) [@waldyrious](https://discourse.julialang.org/u/waldyrious)
#### Post date: [August 31, 2018, 10:24am UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/9 "2018-08-31T10:24:10Z")

</div>

All right! Using `WebIO.webio_serve(page("/", req -> ui))` does work now 🙂

> [@piever](#):
>
> I’m not sure why omitting this worked at some point on my machine.

I’m glad testing in another machine helped identify issues.

Now that this hopefully works reliably as plug-and-play snippet, I would suggest adding this code to the [README](https://github.com/JuliaGizmos/Interact.jl#interact), below the screenshot that is there currently, as that provides a way to immediately try out the example and get a taste of what working with the package is like. (The image may need to be slightly adjusted – IIUC it’s lacking the legend positioning controls – or the code could be tweaked to match it.)

> [@piever](#):
>
> I’ll edit the original post.

While you’re at it, please add a semicolon at the end of the `ui = myplot(...)` line, otherwise its output gets spilled into the console.

---

<div class="post-metadata">

### Author: ![waldyrious](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waldyrious/32/80_2.png) [@waldyrious](https://discourse.julialang.org/u/waldyrious)
#### Post date: [August 31, 2018, 10:25am UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/10 "2018-08-31T10:25:36Z")

</div>

By the way, wouldn’t it make sense for `WebIO.webio_serve(req -> ui)` to be automatically equivalent to `WebIO.webio_serve(page("/", req -> ui))`? That sounds like a reasonable default to me. If you agree, I can open an issue in the WebIO repo.

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [August 31, 2018, 10:37am UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/11 "2018-08-31T10:37:19Z")

</div>

> [@waldyrious](#):
>
> While you’re at it, please add a semicolon at the end of the `ui = myplot(...)` line, otherwise its output gets spilled into the console.

True, that’s very annoying as the text output can be massive…

> [@waldyrious](#):
>
> By the way, wouldn’t it make sense for `WebIO.webio_serve(req -> ui)` to be automatically equivalent to `WebIO.webio_serve(page("/", req -> ui))` ? That sounds like a reasonable default to me. If you agree, I can open an issue in the WebIO repo.

Definitely open an issue! May be a bit tricky to get it to work due to how it works internally but we should at least discuss it properly on GitHub

---

<div class="post-metadata">

### Author: ![waldyrious](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waldyrious/32/80_2.png) [@waldyrious](https://discourse.julialang.org/u/waldyrious)
#### Post date: [August 31, 2018, 10:53am UTC](https://discourse.julialang.org/t/some-interact-updates-create-your-custom-widgets-easily-and-composably/14192/12 "2018-08-31T10:53:57Z")

</div>

> [@piever](#):
>
> Definitely open an issue! May be a bit tricky to get it to work due to how it works internally but we should at least discuss it properly on GitHub

Ok! Opened as [issue #189](https://github.com/JuliaGizmos/WebIO.jl/issues/189).
