Creating your first dashboard
A dashboard is a type of reactive app that displays data visualizations and allows the user to interact via controls such as buttons or sliders. With each user interaction, the application responds by executing code that manipulates the underlying data and promptly reflects these changes in the user interface. All of this happens in real time, without the need to reload the page.
This guide will show you how to create a dashboard which displays statistics about a vector of random numbers, and allows the user to change the length of the vector. The code will rely mainly on the reactive UI features implemented by the Stipple.jl
package, which is already included in the GenieFramework.jl
metapackage.
Project structure
When building a Genie app, the usual assumption is that you already have some code performing some data analysis that you want to turn into a web app. For this demo, we'll start with a StatisticAnalysis
module with the following content:
module StatisticAnalysis
export gen_numbers, calc_mean
function gen_numbers(N::Int)
return rand(N)
end
function calc_mean(x::Vector{Float64})
return round(sum(x) / length(x); digits=4)
end
end
Create a project folder for the demo app, and in it create a lib/
folder and place the StatisticAnalysis.jl
file inside it. The contents of this folder will be automatically loaded into the Main
module when the app is run.
Next, we have the app.jl
file which is the main entry point to the app and also where we'll implement the dashboard. Create the file in the project root with this content:
module App
using Main.StatisticAnalysis
using GenieFramework, PlotlyBase
@genietools
@app begin
#reactive code goes here
end
function ui()
p("") #initialized to an empty paragraph
end
@page("/", ui)
end
The code is divided into three parts:
- Imports of
GenieFramework
,PlotlyBase
and the data analysis code inStatisticAnalysis.jl
. - Reactive code within the
@app
block to control dashboard interactivity. - UI definition in the
ui
function. - Route definition with
@page
to link a URL with the page view provided byui
.
This is what the file structure should look like:
├── app.jl
└── lib
└── StatisticAnalysis.jl
To launch the app, run this in the Julia REPL:
using GenieFramework; Genie.loadapp(); up()
A server will start on port 8000
, and you can access the app at https://localhost:8000
. To stop the server, execute down()
in the REPL.
Let's now add the UI code and reactive code to implement the following:
- A slider to control the length of the vector of random numbers.
- A text line to display the vector's mean.
- A histogram plot for the vector.
Slider and mean - UI
You can build the UI in pure Julia using the low-code API provided by the StippleUI.jl
package, which is automatically included upon using GenieFramework
. This provides multiple calls such as textfield
or slider
that generate the HTML code for the UI component:
julia> slider(1:1:1000, :N)
"<q-slider :min=1 v-model=\"N\" :max=1000 :step=1></q-slider>"
See the component gallery and the API for a complete list of available components.
To incorporate the slider component and the mean display into the UI, add the following code to the ui
function:
function ui()
row([
cell(class="st-col col-3", [
h1("A simple dashboard"),
slider(1:1:1000, :N),
p("The average of {{N}} random numbers is {{m}}", class="st-module"),
])
])
end
A simple dashboard
The average of {{N}} random numbers is {{m}}
The slider
component takes as parameters the range of values it takes, and the symbol name of the reactive variable where the selected number will be stored. This variable does not exist yet. We'll add it later to the reactive code.
The {{variable}}
syntax is used in the paragraph p
to display the content of reactive variables. Moreover, this syntax accepts any valid Javascript expression, so you can write things like {{m.toFixed(2)}}
to display the mean with two decimals.
You can examine the HTML generated by the ui
function by calling it in the REPL, which will yield:
<div class="row">
<div class="st-col col-3 st-col col">
<h1>A simple dashboard</h1>
<q-slider :min=1 v-model="N" :max=1000 :step=1 ></q-slider>
<p class="st-module">The average of {{N}} random numbers is {{m}}</p>
</div>
</div>
Since the N, m
variables in the code are just placeholders for now, the UI won't work. Let's add the reactive code to make it interactive.
Slider and mean - logic
When the slider is moved, we want to set a new value for the vector length and show the updated mean. To this end, first declare a reactive variable N
in the @app
block as:
@app begin
@in N = 0
end
Tagging with @in
makes the variable reactive and writeable from the UI. Whenever its value changes in the UI in the browser, the change will be automatically propagated to the Julia code. Likewise, any change in the Julia code will be propagated to the UI.
Next, add a read-only output variable to hold the value of the mean:
@out m = 0.0
Variables tagged with @out
can only be modified from the Julia code. Any change made in the browser will not be propagated to the backend. Note that reactive variables must always be initialized to a value of the appropriate type.
In addition, you can use the @private
macro to define non-reactive variables that are not exposed to the UI. Use these to store data not meant to be shared between users.
Finally, use the @onchange
macro to declare a reactive handler that generates a new vector and calculates its mean when N
changes:
@app begin
@in N = 0
@out m = 0.0
@onchange N begin
x = gen_numbers(N)
m = calc_mean(x)
end
end
Using the @in
, @out
and @onchange
you can implement all kinds of interactivity in an easy manner. To learn more, check out the Reactivity reference.
You should now have a working reactive UI! Let's add the histogram plot.
Histogram plot
To display a plot in the UI, add the plot
call as:
row([
cell(class="st-col col-3", [
h1("A simple dashboard"),
slider(1:1000, :N),
p("The average of {{N}} random numbers is {{m}}", class="st-module"),
plot(:trace, layout=:layout)
])
])
This will add a Plotly plot, in which the trace
variable will hold the data to be plotted, whereas layout
determines style options.
Now, declare an empty histogram trace and the layout variable as
@app begin
@out trace = [histogram(x=[])]
@out layout = PlotlyBase.Layout(title="Histogram plot")
. . .
end
Then, add the code to update the trace in the reactive handler when N
changes
@onchange N begin
. . .
trace = [histogram(x=x)]
end
This is the final reactive code in app.jl
:
@app begin
@in N = 0
@out m = 0.0
@out trace = []
@out layout = PlotlyBase.Layout(title="Histogram plot")
@onchange N begin
x = gen_numbers(N)
m = calc_mean(x)
trace = [histogram(x=x)]
end
end
And that's it, you've finished your first dashboard! For more details on plotting, see the Plotting reference page. Then, you can continue reading the guides to add more features such as multiple pages or an API.