speed up the development of your application in Julia


This article provides a translation of the manual: “How to quickly turn your Julia code into a web app with Genie Builder“. The article will discuss a new tool for rapid development of web applications based on the Ginie Framework – a platform for Internet applications in the language Julia.

Data scientists usually do not start writing full-fledged web applications from the very beginning. Instead, we start with typical activities, including data cleaning, preliminary analysis, testing multiple models, etc., and only when we are confident in the quality of the information extracted from the data do we start thinking about sharing it publicly on the web. application. The Genie framework is very handy for this last step because it allows you to implement an interactive web interface to:

  • You can share your thoughts by simply clicking on the link.

  • Other users can re-run the analysis and fine-tune the analysis using the controls in the user interface (UI).

All this without writing a single line of HTML or Javascript thanks to low-code/no-code decision Genie Builder – extension module for programming environment Visual Studio Code as a visual editor.

This tutorial will show you how to migrate from your existing Julia code to a Genie app in just a few steps. The code for the sample application can be downloaded heretake a look at the animation below to see how it looks in the browser.

Content:

  • Writing code for data analysis

  • Creating a New Application in Genie Builder

  • UI development in Genie Builder editor

  • Implementation of application logic

  • Running an application outside of Genie Builder

1. Writing code for data analysis

To illustrate the Genie workflow, we will write some code to extract information from German Credit Risk Dataset. This data set contains information about 1000 people, where each person is described by 20 characteristics, such as age, gender, or loan amount. In addition, each user was manually labeled as “good credit risk” or “bad credit risk” according to characteristic values.

Let’s say we want to extract the following data from a dataset:

  • The amount and amount of money in good and bad loans.

  • Loan amounts and age of lenders.

  • Number of loans broken down by age range.

To calculate these metrics, save the below code in a script german credits.jl and run it in the Julia REPL to make sure everything works. (Translator’s note: Don’t forget to download the credit risk data set (german_credits.csv) from the https://github.com/GenieFramework/GenieBuilderDemos repository, as the Kaggle site has an incomplete version of the file and the script will not work).

using DataFrames, Dates, OrderedCollections
 
 function good_bad_credits_stats(data::DataFrame)
     good_credits_count = data[data.Good_Rating .== true, [:Good_Rating]] |> nrow
     bad_credits_count = data[data.Good_Rating .== false, [:Good_Rating]] |> nrow
     good_credits_amount = data[data.Good_Rating .== true, [:Amount]] |> Array |> sum
     bad_credits_amount = data[data.Good_Rating .== false, [:Amount]] |> Array |> sum
 
     (; good_credits_count, bad_credits_count, good_credits_amount, bad_credits_amount)
 end
 
 function credit_age_amount(data::DataFrame; good_rating::Bool)
     data[data.Good_Rating .== good_rating, [:Age, :Amount]]
 end
 
 function credit_no_by_age(data::DataFrame; good_rating::Bool)
     age_stats::LittleDict{Int,Int} = LittleDict()
     for x in 20:10:90
       age_stats[x] = data[(data.Age .∈ [x:x+10]) .& (data.Good_Rating .== good_rating), [:Good_Rating]] |> nrow
     end
     age_stats
 end
 
 # testing the functions
 using CSV
 data = CSV.File("german_credits.csv") |> DataFrame
 @show good_bad_credits_stats(data)
 @show credit_age_amount(data, good_rating=true)
 @show credit_no_by_age(data, good_rating=true)

Now that the analysis code is complete and running, it’s time to turn it into a Genie Platform Application.

2. Create a new application in Genie Builder

To create an application, we will use the Genie Builder plugin (hereinafter referred to as GB) for VSCode. After installing the plugin, start the GB server and create a new application called German Credits. Click Yes when asked if you want to run it and a visual editor will appear.

Translator’s note: after installing the GenieBuilder plugin, it is recommended to restart VSCode. Also, at the first start of the server, the download may take a long time, since the necessary packages will be installed in the environment.

On the workspace tab, you will find that the code of the newly created application is divided into two files: app.jl and app.jl.html . Of the two app.jl is one that needs to be edited by hand, whereas app.jl.html generated by the visual editor. At this point you can add a script germancredits.jl go to workspace so that all your files are in one place.

To avoid conflicts, it is recommended to wrap the code in a module and remove any test code. So edit germancredits.jlto make it look like this:

module GermanCredits
     export good_bad_credits_stats, credit_age_amount_duration, credit_data_by_age
     using DataFrames, Dates, OrderedCollections
 
     function good_bad_credits_stats(data::DataFrame)
         ...
     end
     function credit_age_amount(data::DataFrame; good_rating::Bool)
         ...
     end
     function credit_no_by_age(data::DataFrame; good_rating::Bool)
         ...
     end
 end

To install the required packages DataFrames, Dates and OrderedCollections in the application, launch the Genie Builder package manager by right-clicking on the application’s name in the left sidebar. You will see the installation progress in the REPL and the package versions will be added to the file Project.toml.

Next, we will develop a user interface for displaying the analyzed data.

3. Designing the user interface in the Genie Builder editor

For the German Credits UI we want to have:

  • Page title.

  • Icons showing the number of credits and their total value in monetary terms.

  • A range control to filter the age of the people whose data is displayed.

  • A bar chart showing the number of credits by age.

  • Scatter plot showing age versus amount for each loan.

To create a user interface using the visual editor, find the components you need on the right sidebar and drag them onto the canvas. Start with the header, rows and columns to set up the page layout:

Then add the following components:

  • Paragraph (x4).

  • Range.

  • Bar.

  • Scatter.

Finally, let’s increase the font of the number icons. Click the icon </> and change the element class <p> on bignumber. Then add a new css style .bignumber{font-size:40px; text-align:center;}.

To view the user interface, click on the monitor icon next to the “GET” tab on the left sidebar. Note that while nothing works, you still have to implement the application logic and bind the UI components to the Julia code.

4. Implementation of application logic

To make an application interactive, you must implement its logic with:

  • Exposing reactive variables from Julia code to the user interface.

  • Writing reactive code to manage user interaction.

  • Binding public variables to UI components.

File app.jl in the workspace is the main entry point to the application and it is in this file that you will write the logic. Here is what the default file looks like:

 using GenieFramework
 @genietools
 
 @handlers begin
   @out message = "Hello World!"
   @onchange isready begin
     @show "App is loaded"
   end
 end
 
 @page("/", "app.jl.html")

To start with a clean application, delete the contents of the block separated by the macro @handlers. Then enable the German Credits package and load the dataset by adding the following code in front of it:

include("germancredits.jl")
 using .GermanCredits
 using GenieFramework, CSV, DataFrames, OrderedCollections
 
 const data = CSV.File("german_credits.csv") |> DataFrame

Next, we’ll add reactive variables and code for each UI element. Since we want to filter the data to show only a specific age range, let’s start by selecting a range.

Range selector

In Genie applications, reactivity is based on two concepts:

  • Variables are displayed in the user interface by marking them with a macro @inif they take their value from the user interface, or by a macro @outif they output their value to the user interface.

  • The code for handling interactions is written in a block delimited by a macro @onchangewhich keeps track of the variable and whenever it changes, executes the code in the block.

To filter data using the range selector in the UI, we need to:

  • type variable RangeData to store the range selected in the user interface.

  • DataFrame to store filtered data.

  • Calling a function to update the available data when an age range is selected.

To implement these elements, add the following code inside the macro @handlers:

 @handlers begin
     @in age_range::RangeData{Int} = RangeData(18:90)
     @out filtered_data = DataFrame()
     @onchange age_range begin
         filtered_data = data[(age_range.range.start .<= data[!, :Age] .<= age_range.range.stop), :]
     end
 end

Note that the variables have default values ​​so that the UI can be displayed when the page loads. Now go to no code editor, select the Range component and assign a variable age_range its data binding field.

That’s it for range selection. Each time you move one end of the slider in the user interface, the content filtered_data will be updated. Let’s continue with the next item to show the updated information.

License badges

To display the number and amount in credits, you will need:

  • Variables for storing values.

  • Call good_bad_credits_stats to update variables when a new range is selected.

@handlers begin
     ...
     @out good_credits_count = 0 
     @out bad_credits_count = 0
     @out good_credits_amount = 0
     @out bad_credits_amount = 0
     @onchange age_range begin
         ...
         good_credits_count, bad_credits_count, good_credits_amount,
         bad_credits_amount = good_bad_credits_stats(filtered_data)
     end
 end

To display numbered icons in the user interface, assign each variable to the anchor text box of the paragraph component.

Number of loans by age

We will graph loans by age using a bar chart indexed by age ranges in 10 year increments. For this you will need:

  • Array to store x-axis labels.

  • array PlotData to store graph data.

  • type variable PlotLayout to specify the plot layout.

  • Reactive code to update plots with values ​​calculated using credit_no_by_age.

 @handlers begin
     ...
     @out age_slots = ["20-30", "30-40", "40-50", "50-60", "60-70", "70-80", "80-90"]
     @out credit_no_by_age_plot = PlotData[]
     @out credit_no_by_age_plot_layout = PlotLayout(barmode="group", showlegend = true)
     @onchange age_range begin
         ...
         credit_no_by_age_plot = [
             PlotData(
                 x = age_slots, 
                 y = collect(values(credit_no_by_age(filtered_data; good_rating = true))),
                 name = "Good credits", 
                 plot = StipplePlotly.Charts.PLOT_TYPE_BAR, 
                 marker = PlotDataMarker(color = "#72C8A9")
             ),
             PlotData(
                 x = age_slots, 
                 y = collect(values(credit_no_by_age(filtered_data; good_rating = false))),
                 name = "Bad credits", 
                 plot = StipplePlotly.Charts.PLOT_TYPE_BAR, 
                 marker = PlotDataMarker(color = "#BD5631")
             )
         ]
     end
 end

Dot plot of age versus loan amount

For this plot you will need:

 @handlers begin
     ...
     @out age_amount_plot_layout = PlotLayout(showlegend = true)
     @out age_amount_plot = PlotData[]
 
     @onchangeany age_range begin
         ...
         dgood = credit_age_amount(filtered_data; good_rating = true)
         dbad = credit_age_amount(filtered_data; good_rating = false)
         age_amount_plot = [
             PlotData(
                 x = dgood.Age, 
                 y = dgood.Amount, 
                 name = "Good credits", 
                 mode = "markers",
                 marker = PlotDataMarker(size=18, opacity= 0.4, color = "#72C8A9", symbol="circle")
             ),
             PlotData(
                 x = dbad.Age, 
                 y = dbad.Amount, 
                 name = "Bad credits", 
                 mode = "markers",
                 marker = PlotDataMarker(size=18, opacity= 0.4, color = "#BD5631", symbol="cross")
             )
         ]
     end
 end

And with this last component, you are done with your Genie app!

5. Running the application outside of Genie Builder

You can run your application locally in VSCode from the GenieBuilder Applications menu in the sidebar. However, if you want to run your app outside of GenieBuilder, the app files are in the folder ~/.julia/geniebuilder/apps/GermanCredits/. Before running the application, you will need to tell Genie to start the server by adding the following line at the end app.jl:

Server.isrunning() || Server.up()

Then open the REPL with julia --project in the application folder and enter include("app.jl")to start the application app.

PS Additionally, you can watch a tutorial video on how to use Ginie Builder v0.2 on YouTube:

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *