# Hosting Web Apps in Julia

**URL:** <https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063>\
**Category:** General Usage\
**Tags:** package, webapps\
**Created:** [December 20, 2016, 4:36pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063 "2016-12-20T16:36:52Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 22, 2016, 9:13pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/21 "2016-12-22T21:13:30Z")

</div>

It’s pretty rough, but that’s not stopping me from cackling maniacally:

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

After the first call, the time from clicking “solve it” to having a new plot is ~550 ms, and this is with the entire back-end in a giant try … catch block and the front-end in development mode.

The big input is not sanitized yet, but it should be in decent shape if anyone wants to play around with it.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 22, 2016, 9:34pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/22 "2016-12-22T21:34:40Z")

</div>

Hmm, where are you actually plotting it? Are you generating the plot in Plotly using the data you send back? The reason why I suggested using the plot recipe via Plots.jl + Plotly is because it handles thing like dense plotting, which makes those lines smoother, and will make it easy to do phase plots etc. Then you’d just have to send the Javascript back.

Is this all found here?

[https://github.com/amellnik/JuliaAPIDemo/blob/fa40e7c355fbd7130b3541927e45af7480fd81ba/api/srvr.jl#L15](https://github.com/amellnik/JuliaAPIDemo/blob/fa40e7c355fbd7130b3541927e45af7480fd81ba/api/srvr.jl#L15)

What I would add is, outside of the function call:

```julia
using Plots # need this earlier
plotly() # change the backend, this could be done outside of the function when Plots is instantiated

```

then in the function after solving, add

```julia
p = plot(sol)
jscript = # Somehow get the javascript for the plot out of the Plotly plot itself?
res = Dict("u" => sol.u, "t" => sol.t, "jscript" => jscript)

```

and directly display the plot from that Javascript. That will make it so that way all of the plotting work that we’re working on wouldn’t have to be recreated in Javascript itself.

---

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 22, 2016, 9:52pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/23 "2016-12-22T21:52:51Z")

</div>

Currently the plotting happens on the front-end [here](https://github.com/amellnik/JuliaAPIDemo/blob/master/src/app/home/home.component.ts#L61). It receives `t` and `u` from the back end and uses the Javascript version of Plotly in the client.

I don’t think we want to try to do the plotting on the back-end and pass some resulting object forward. I’m not sure runtime javascript injection is even possible with the front-end framework I’m using and I think it’s strongly discouraged in general due to security concerns. It also puts a larger burden on the back-end and increases the amount of data we have to shuttle back and forth.

I’m not familiar with Plots.jl – is it doing some sort of smoothing? If so, can we just send the resampled `t` and `u` to the client?

Edit: I guess the smoothing is done by the function `interp` that’s packaged into the solution. I’ll try returning a much-finer sampling of `t` and `u` instead of those that come in the solution.

Edit2: This is what it looks like with 1k sample points:

 ![](https://global.discourse-cdn.com/julialang/original/3X/7/a/7a00dd6b77edf08236c75205253db45de2cfa651.png)

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 23, 2016, 12:34am UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/24 "2016-12-23T00:34:47Z")

</div>

> [@amellnik](#):
>
> I don’t think we want to try to do the plotting on the back-end and pass some resulting object forward. I’m not sure runtime javascript injection is even possible with the front-end framework I’m using and I think it’s strongly discouraged in general due to security concerns. It also puts a larger burden on the back-end and increases the amount of data we have to shuttle back and forth.

Plotly has some representation for its plots, could we take that and send it over to the other Plotly? It has some way of sending the data over to its cloud server: is that something we can tap into?

I mean, the easiest way to do this simple case is to use the interpolation `sol(t)` at say 1000 points (`sol.interp(t)` is what’s called by `sol(t)`). But we have many improvements going on in plotting, so it would be nice to use them directly. For example, we have a way of choosing which coordinates to plot:

> <https://github.com/SciML/DiffEqBase.jl/pull/15>
>
> The most precise way to specify which variables to plot is to pass a
> list of tu…ples \`(x, y)\` where \`x\` and \`y\` are positive integers to
> indicate the corresponding dependent variable, or 0 to refer to time
> (the independent variable). Example:
> 
> vars = \[(0,1), (1,3), (4,5)\]
> 
> will plot on the same graph \`sol\[1\]\` as a function of \`t\`, \`sol\[3\]\` as a
> function of \`sol\[1\]\`, and \`sol\[5\]\` as a function of \`sol\[4\]\` (whatever
> that could mean).
> 
> Everything could be done with that, but for convenience several
> shortcuts are allowed:
> 
> \* Everywhere in a tuple position where we only find an integer, this
> variable is plotted as a function of time. For example, the list above
> is equivalent to:
> 
> vars = \[1, (1,3), (4,5)\]
> 
> and
> 
> vars = \[1, 3, 4\]
> 
> is the most concise way to plot the variables 1, 3, and 4 as a function
> of time.
> 
> \* It is possible to omit the list if only one plot is wanted: \`(2,3)\`
> and \`4\` are respectively equivalent to \`\[(2,3)\]\` and \`\[(0,4)\]\`.
> 
> \* Finally, a tuple containing one or several lists will be expanded by
> associating corresponding elements of the lists with each other:
> 
> vars = (\[1,2,3\], \[4,5,6\])
> 
> is equivalent to
> 
> vars = \[(1,4), (2,5), (3,6)\]
> 
> and
> 
> vars = (1, \[2,3,4\])
> 
> is equivalent to
> 
> vars = \[(1,2), (1,3), (1,4)\]

It seems this will soon be updated to even switch between 3D plots and everything, and Plots.jl makes it easy to do subplots. There’s also an algorithm for automatically choosing the number and location of points to plot in the works:

> <https://github.com/JuliaPlots/Plots.jl/issues/621>
>
> It would be nice to be able to \`plot(f)\` for \`f(t)\` some function which returns …scalars (or more). Mathematica handles this with a sophisticated algorithm. It's only mentioned on this page:
> 
> https://reference.wolfram.com/language/ref/Plot.html
> 
> and described as
> 
> \>Plot initially evaluates f at a number of equally spaced sample points specified by PlotPoints. Then it uses an adaptive algorithm to choose additional sample points, subdividing a given interval at most MaxRecursion times.
> 
> !\[image\_5\](https://cloud.githubusercontent.com/assets/1814174/21425820/2fb20cc0-c800-11e6-8754-6c82d2c10512.gif)
> 
> It seems like the algorithm does the following (or at least something like it): 
> 
> 1. Take an initial number of points (lets say 100) 
> 2. Take two points skipping over one, do a linear interpolation
> 3. Check the difference between the linear interpolation and the actual value (the skipped point). If it's large enough, subdivide the interval.
> 4. Recurse 3 on the points you are getting until \`max\_recursion\` or it hits the tolerance.
> 5. Repeat 2 until you're point of point triples.
> 
> This form of adaptive plotting would make it easy to plot a function without knowing the details. This is nice for when you don't actually know what the function looks like until plotting it! 
> 
> @Armavica

In the end, I think we’d have a lot of free flexibility if we let the Julia function control the plotting output since it’s getting a lot of work already.

---

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 23, 2016, 1:11am UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/25 "2016-12-23T01:11:09Z")

</div>

Ah good catch, I think there’s probably a way to access the JSON  
representation of the plot that PlotlyJS hands off to Plotly to actually do  
the plotting. This JSON could be sent back to the client Plotly to recreate  
the exact same plot.

(Please excuse brevity and errors, sent from a mobile device.)

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 23, 2016, 2:48pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/26 "2016-12-23T14:48:26Z")

</div>

Hey,  
Did some investigative work. If you make a `plotly()` plot in Plots.jl:

```julia
using Plots; plotly()
...
p = plot(sol)

```

then you can get the JSON via

```julia
layout = Plots.plotly_layout_json(p)
series = Plots.plotly_series_json(p)

```

You can see from here:

[https://github.com/tbreloff/Plots.jl/blob/master/src/backends/plotly.jl#L657](https://github.com/tbreloff/Plots.jl/blob/master/src/backends/plotly.jl#L657)

That Tom generates the Plotly plot using the JSON via:

```javascript
        <div id=\"$(uuid)\" style=\"$(style)\"></div>
        <script>
        PLOT = document.getElementById('$(uuid)');
        Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
        </script>

```

While the full Javascript output was too large to show in the REPL (it just kept printing and printing…), the JSON is not bad at all. I think this is definitely the way to go.

---

<div class="post-metadata">

**Author:** ![Evizero](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evizero/32/10118_2.png) [@Evizero](https://discourse.julialang.org/u/Evizero)\
**Post date:** [December 23, 2016, 3:03pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/27 "2016-12-23T15:03:00Z")

</div>

The one big issue I encountered in the wild with clientside plotting (using plotly and shiny in R) is using boxplots. I think one wants to generate boxplots serverside unless the clientside has some way to use the precomputed stats, which plotly back then didn’t have (not sure about now). So one needed to send all the data around even though only some primitive shapes and some outliers are drawn. It froze my browser a couple of times until I switched to using ggplot instead.

---

<div class="post-metadata">

**Author:** ![Tem\_Pl](https://avatars.discourse-cdn.com/v4/letter/t/8dc957/32.png) [@Tem\_Pl](https://discourse.julialang.org/u/Tem_Pl)\
**Post date:** [December 23, 2016, 3:55pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/28 "2016-12-23T15:55:11Z")

</div>

There is a “] Compile to static HTML” feature mentioned here: [https://github.com/shashi/Escher.jl/issues/1](https://github.com/shashi/Escher.jl/issues/1)

@shashi Does that allow compiling a frontend focused Escher app to HTML, or is it somethign else?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 23, 2016, 4:54pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/29 "2016-12-23T16:54:50Z")

</div>

Hmm, I’m really close. The new srvr.jl file gets the series and layout JSON and adds them to what’s returned. I tried changing the plot command to:

```julia
  plot() {
    console.log(this.resultsObj);
    var self = this;
    Plotly.newPlot('results-plot',this.resultsObj.series,this.resultsObj.layout);
  }

```

But then I get no plot. @tbreloff 's plot command in Plots.jl is simply:

```julia
function html_body(plt::Plot{PlotlyBackend}, style = nothing)
    if style == nothing
        w, h = plt[:size]
        style = "width:$(w)px;height:$(h)px;"
    end
    uuid = Base.Random.uuid4()
    html = """
        <div id=\"$(uuid)\" style=\"$(style)\"></div>
        <script>
        PLOT = document.getElementById('$(uuid)');
        Plotly.plot(PLOT, $(plotly_series_json(plt)), $(plotly_layout_json(plt)));
        </script>
    """
    html
end

```

---

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 23, 2016, 5:08pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/30 "2016-12-23T17:08:35Z")

</div>

You’re returning an object like

```json
{
    series: {...},
    layout: {...},
    error: false,
    ...
}

```

right? If so, the top one looks correct. Are you getting any errors on the browser console? It should also echo the returned response there so you can confirm that it looks right.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 23, 2016, 5:10pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/31 "2016-12-23T17:10:10Z")

</div>

I fixed up the srvr.jl file. Now everything works and the plot is made, but it’s blank. It’s because `layout` and `series` seem to come back as strings. I need to interpret those strings as a JSON object. Do you know how to do that?

---

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 23, 2016, 5:10pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/32 "2016-12-23T17:10:42Z")

</div>

Plotly does a pretty good job on this now – check out [this example](https://plot.ly/javascript/box-plots/#fully-styled-box-plot).

---

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 23, 2016, 5:14pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/33 "2016-12-23T17:14:43Z")

</div>

You’re getting a stringed version of the `layout` and `series` objects from Plotly, right? I bet it’s because the server takes the object you want to return and strings it again with `JSON.json()`. If they are already strings you may need to construct the final JSON string by hand with string interpolation.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 23, 2016, 5:32pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/34 "2016-12-23T17:32:11Z")

</div>

Alright! I got it plotting the Plots.jl JSON. I updated the README to make it super noob friendly, so feel free to give it a try. One thing that really needs to be done now though is the plot window needs to be resized. @tbreloff does this via [https://github.com/tbreloff/Plots.jl/blob/master/src/backends/plotly.jl#L641](https://github.com/tbreloff/Plots.jl/blob/master/src/backends/plotly.jl#L641) . Using the JSON directly makes a plot which is too big for the default Window:

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

See how it chops off the axis?

But the rest is just allowing the user to send more options, which just follows the same template.

Edit: Here’s the repo link again:

> **[GitHub - SciML/DiffEqOnline: It's Angular2 business in the front, and a Julia...](https://github.com/SciML/DiffEqOnline)**
>
> It's Angular2 business in the front, and a Julia party in the back! It's scientific machine learning (SciML) for the web - GitHub - SciML/DiffEqOnline: It's Angular2 business in the fro...

---

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 23, 2016, 6:08pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/35 "2016-12-23T18:08:57Z")

</div>

The size of the plot div can be set statically [here](https://github.com/amellnik/JuliaAPIDemo/blob/master/src/app/home/home.component.html#L34) or it could be adjusted programatically by [binding those values](http://stackoverflow.com/questions/35882670/dynamically-updating-css-in-angular-2) in Angular 2. I don’t know how well it works with Plotly, but we could also make the plot [resizable by the user](http://www.w3schools.com/cssref/css3_pr_resize.asp).

Any stylings from `Plots.jl` that you want to override can be done client side with something like `Object.assign(this.resultsObj, {layout: {xaxis: {title: 't'}}`, or done on the server.

I don’t want to belabor the point since this is your party, but if we can capture the styling decisions that are being made by `Plots.jl` I still think it would be best to apply them client side and just pass the data. Even on my beefy computer, the request to the server takes more than 2 sec to resolve for a new problem now. This may work for now, but if we want to make this publicly available it will be running in a container on a wet noodle of a VM.

 ![](https://global.discourse-cdn.com/julialang/original/3X/8/2/8213914a1091d824c5fbe67aebb62cb2459acce2.png)

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 23, 2016, 6:15pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/36 "2016-12-23T18:15:36Z")

</div>

Is passing the JSON the problem, or passing the points? I would think that since by default I have it passing back 1000 points (`const numpoints = 1000`) that would be the bigger issue. What happens when that is knocked down? I am running it from a very beefy computer so I don’t really see a cost for the request.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 23, 2016, 6:21pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/37 "2016-12-23T18:21:56Z")

</div>

If this doesn’t knock it down, what we can do is refactor the plotting tools so that way to points and labels for the plots could be computed without producing the plot, and then sent over and plotted on the client side.

---

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 23, 2016, 6:30pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/38 "2016-12-23T18:30:56Z")

</div>

Looking at this more closely, it looks like I timed it incorrectly yesterday – after the first run solving is taking about 1.7 sec, and the call to `plot` is ~0.2 sec, so it’s not actually expensive and is probably fine if you want to do it server-side. Sorry for the confusion!

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [December 23, 2016, 6:57pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/39 "2016-12-23T18:57:53Z")

</div>

> [@amellnik](#):
>
> after the first run solving is taking about 1.7 sec, and the call to plot is ~0.2 sec, so it’s not actually expensive and is probably fine if you want to do it server-side

Cool. It sounds like this is definitely doable, and there are some things that may need to get streamlined (we’re working on getting ParameterizedFunctions.jl precompiled and not have to use any evals (almost got it last night), and getting 1000 interpolated points has a higher cost than it should, but that’s fixed on v0.6 by broadcast fusion).

> [@amellnik](#):
>
> The size of the plot div can be set statically here or it could be adjusted programatically by binding those values in Angular 2. I don’t know how well it works with Plotly, but we could also make the plot resizable by the user.

We could probably just have it match Plots.jl’s default size for now. I’ll do that when I get back.

Is there a way to link the `gh-pages` render to a Julia process? No, right?

---

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [December 23, 2016, 7:08pm UTC](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063/40 "2016-12-23T19:08:45Z")

</div>

> [@ChrisRackauckas](#):
>
> Is there a way to link the gh-pages render to a Julia process? No, right?

Not quite sure what you’re asking, but probably not. All `gh-pages` does is statically serve contents of that branch, and if a request goes to a file that doesn’t exist, serve `404.html` instead (this last bit is crucial to getting Angular 2 apps to work).

[Previous page](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063.md?page=1)

[Next page](https://discourse.julialang.org/t/hosting-web-apps-in-julia/1063.md?page=3)
