Создание пользовательских приложений в Engee
Построение графиков с помощью Genie
В этом разделе вы познакомитесь с построением графиков в пользовательских приложениях с помощью фреймворка Genie. Вы научитесь создавать графики, форматировать их внешний вид и управлять отображаемыми данными с помощью реактивного пользовательского интерфейса.
Какое приложение мы будем создавать
В качестве примера мы создадим приложение, которое по выбору пользователя строит график одной из пяти элементарных функций: , , , и . Каждый график будет отображаться своим цветом: синим, красным, зеленым, оранжевым и черным соответственно.
✏️Задание 1
Начните создание приложения:
- В папке данного курса создайте скрипт
app3.jl. - Добавьте в скрипт следующий код, создающий "пустое" приложение:
using GenieFramework, Stipple, PlotlyBase
@app begin
end
function ui()
end
@page("/", ui)
Здесь к подключаемым библиотекам GenieFramework и Stipple добавляется библиотека PlotlyBase, содержащая функции для построения графиков.
Создание заголовка приложения
Заголовок приложения добавим с помощью команды h4(). Сделаем так, чтобы заголовок содержал название функции, отображаемой в данный момент на графике. Для этого введем переменную строкового типа caption, которая может принимать одно из пяти возможных значений, соответствующих названиям наших функций.
✏️Задание 2
Создайте заголовок приложения:
- В начало интерфейсной части кода добавьте команду, создающую заголовок приложения:
h4("График функции {{caption}}"),
Здесь конструкция {{caption}} добавляет значение реактивной переменной caption к выводимой строковой константе График функции .
- В модель данных добавьте описание выходной переменной
caption, принимающей начальное значениеy = x^2:
@out caption = "y = x^2"
Решение
using GenieFramework, Stipple, PlotlyBase
@app begin
@out caption = "y = x^2"
end
function ui()
h4("График функции {{caption}}"),
end
@page("/", ui)
Переключатели
Рассмотрим еще один элемент интерфейса – переключатель. В Genie он задается с помощью команды toggle().
Нам понадобятся пять переключателей, чтобы пользователь мог включить отображение графика любой из пяти элементарных функций. Состояние переключателей будет описываться логическими переменными toggle1 ... toggle5. Если соответствующая переменная принимает значение true, то переключатель находится во включенном состоянии; если false – то в выключенном. В любой момент времени во включенном состоянии может находиться не более одного переключателя.
✏️Задание 3
Добавьте в приложение переключатели:
- В интерфейсную часть кода добавьте команды
toggle("y = x^2", :toggle1, color = "blue"),
toggle("y = x^3", :toggle2, color = "red"),
toggle("y = sin(x)", :toggle3, color = "green"),
toggle("y = cos(x)", :toggle4, color = "orange"),
toggle("y = ln(x)", :toggle5, color = "black"),
Здесь первый аргумент задает надпись рядом с переключателем (название функции, график которой включается с помощью этого переключателя). Второй аргумент – логическая переменная, которая описывает состояние переключателя. Третий аргумент задает цвет переключателя, когда тот находится во включенном состоянии (в выключенном состоянии все переключатели серые).
- В модель данных добавьте описание входных переменных
toggle,toggle2,toggle3,toggle4иtoggle5:
@in toggle1 = true
@in toggle2 = false
@in toggle3 = false
@in toggle4 = false
@in toggle5 = false
В начальном состоянии первый переключатель, отвечающий за выбор функции , будет включен, а остальные – выключены.
Решение
using GenieFramework, Stipple, PlotlyBase
@app begin
@out caption = "y = x^2"
@in toggle1 = true
@in toggle2 = false
@in toggle3 = false
@in toggle4 = false
@in toggle5 = false
end
function ui()
h4("График функции {{caption}}"),
toggle("y = x^2", :toggle1, color = "blue"),
toggle("y = x^3", :toggle2, color = "red"),
toggle("y = sin(x)", :toggle3, color = "green"),
toggle("y = cos(x)", :toggle4, color = "orange"),
toggle("y = ln(x)", :toggle5, color = "black"),
end
@page("/", ui)
График
График в Genie строится с помощью одной из двух функций: plot() или plotly(). Мы воспользуемся функцией plotly(), находящейся в библиотеке PlotlyBase.
✏️Задание 4
Добавьте в приложение график:
- В основную часть скрипта (сразу после строки
using...) добавьте вектор значений аргументаxи переменнуюplot1, хранящую график функции :
x1 = [0:0.01:10;]
plot1 = Plot(scatter(x=x1, y=x1.^2, line=attr(color="blue")))
Здесь переменная x1 – вектор значений аргумента x от 0 до 10 с шагом 0.01. Функция Plot формирует график, но не строит его. scatter – тип графика (точечный). Аргументы x=x1 и y=x1.^2 задают координаты точек графика, line=attr(color="blue") задает цвет линии (синий).
- Аналогично добавьте в скрипт еще четыре переменные
plot2,plot3,plot4иplot5, хранящие графики четырех других функций: , , и . Цвета линий задайте красным, зеленым, оранжевым и черным соответственно. Напомним, что операции с векторами записываются с точкой:.^,sin.,cos.иlog..
Обратите внимание! Созданные переменные не являются реактивными, т.е. они не взаимодействуют с интерфейсом, поэтому в модели данных (в разделе
@app) их описание не требуется.
- Ниже задайте макет графика с помощью функции
PlotlyBase.Layout():
layout = PlotlyBase.Layout(
xaxis=attr(title="X", showgrid=true, range=[0, 10]),
yaxis=attr(title="Y", showgrid=true),
width=800, height=550
)
Здесь задаются подписи на координатных осях (X и Y), сетка, диапазон от 0 до 10 по оси Ox (по оси Oy диапазон не задается, он будет рассчитываться автоматически) и размеры графика (ширина 800 пикселей, высота 550 пикселей).
- В модель данных добавьте описание выходной переменной
chosen_plot(выбранный пользователем график) с начальным значениемplot1. Эта переменная будет принимать одно из пяти значений:plot1,plot2,plot3,plot4илиplot5. Добавьте описание выходной переменнойlayout, задающей макет графика.
@out chosen_plot = plot1
@out layout = layout
- В интерфейсную часть кода добавьте команду
plotlyдля построения графика, заданного переменнойchosen_plot, с макетом, заданным переменнойlayout:
plotly(:chosen_plot, layout=:layout)
Решение
using GenieFramework, Stipple, PlotlyBase
x1 = [0:0.01:10;]
plot1 = Plot(scatter(x=x1, y=x1.^2, line=attr(color="blue")))
plot2 = Plot(scatter(x=x1, y=x1.^3, line=attr(color="red")))
plot3 = Plot(scatter(x=x1, y=sin.(x1), line=attr(color="green")))
plot4 = Plot(scatter(x=x1, y=cos.(x1), line=attr(color="orange")))
plot5 = Plot(scatter(x=x1, y=log.(x1), line=attr(color="black")))
layout = PlotlyBase.Layout(
xaxis=attr(title="X", showgrid=true, range=[0, 10]),
yaxis=attr(title="Y", showgrid=true),
width=800, height=550
)
@app begin
@out caption = "y = x^2"
@in toggle1 = true
@in toggle2 = false
@in toggle3 = false
@in toggle4 = false
@in toggle5 = false
@out chosen_plot = plot1
@out layout = layout
end
function ui()
h4("График функции {{caption}}"),
toggle("y = x^2", :toggle1, color = "blue"),
toggle("y = x^3", :toggle2, color = "red"),
toggle("y = sin(x)", :toggle3, color = "green"),
toggle("y = cos(x)", :toggle4, color = "orange"),
toggle("y = ln(x)", :toggle5, color = "black"),
plotly(:chosen_plot, layout=:layout)
end
@page("/", ui)
Обработчики переключателей
Нам осталось добавить реактивную логику работы приложения: выбор графика в зависимости от того, какой переключатель включен пользователем. Для этого нам понадобятся макросы @onchange – обработчики изменения состояния переключателей, в которых мы опишем, что должно происходить при включении того или иного переключателя.
✏️Задание 5
Добавьте в модель обработчики переключателей:
- В модель данных (после описания реактивных переменных) добавьте макрос
@onchange– обработчик изменения состояния первого переключателя:
@onchange toggle1 begin
if toggle1 == true
caption = "y = x^2"
toggle2 = false
toggle3 = false
toggle4 = false
toggle5 = false
chosen_plot = plot1
end
end
Здесь проверяется условие: если переключатель включен (if toggle1 == true), то название функции "y = x^2" добавляется в заголовок приложения, а все остальные переключатели выключаются (соответствующие им логические переменные принимают значение false, что соответствует выключенному состоянию). Переменная chosen_plot принимает значение plot1, т.е. для построения выбирается график функции . Таким образом, аргумент функции plotly принимает значение plot1, и график функции немедленно отображается на экране.
- Аналогично добавьте четыре обработчика изменения состояния всех остальных переключателей. Переменная
captionбудет принимать значения"y=x^3","y=sin(x)","y=cos(x)"и"y=ln(x)"соответственно, а переменнаяchosen_plot– значенияplot2,plot3,plot4иplot5соответственно. Все переключатели, кроме текущего, должны быть переведены в выключенное состояние.
Решение
using GenieFramework, Stipple, PlotlyBase
x1 = [0:0.01:10;]
plot1 = Plot(scatter(x=x1, y=x1.^2, line=attr(color="blue")))
plot2 = Plot(scatter(x=x1, y=x1.^3, line=attr(color="red")))
plot3 = Plot(scatter(x=x1, y=sin.(x1), line=attr(color="green")))
plot4 = Plot(scatter(x=x1, y=cos.(x1), line=attr(color="orange")))
plot5 = Plot(scatter(x=x1, y=log.(x1), line=attr(color="black")))
layout = PlotlyBase.Layout(
xaxis=attr(title="X", showgrid=true, range=[0, 10]),
yaxis=attr(title="Y", showgrid=true),
width=800, height=550
)
@app begin
@in toggle1 = true
@in toggle2 = false
@in toggle3 = false
@in toggle4 = false
@in toggle5 = false
@out caption = "y = x^2"
@out chosen_plot = plot1
@out layout = layout
@onchange toggle1 begin
if toggle1 == true
caption = "y = x^2"
toggle2 = false
toggle3 = false
toggle4 = false
toggle5 = false
chosen_plot = plot1
end
end
@onchange toggle2 begin
if toggle2 == true
caption = "y = x^3"
toggle1 = false
toggle3 = false
toggle4 = false
toggle5 = false
chosen_plot = plot2
end
end
@onchange toggle3 begin
if toggle3 == true
caption = "y = sin(x)"
toggle1 = false
toggle2 = false
toggle4 = false
toggle5 = false
chosen_plot = plot3
end
end
@onchange toggle4 begin
if toggle4 == true
caption = "y = cos(x)"
toggle1 = false
toggle2 = false
toggle3 = false
toggle5 = false
chosen_plot = plot4
end
end
@onchange toggle5 begin
if toggle5 == true
caption = "y = ln(x)"
toggle1 = false
toggle2 = false
toggle3 = false
toggle4 = false
chosen_plot = plot5
end
end
end
function ui()
h4("График функции {{caption}}"),
toggle("y = x^2", :toggle1, color = "blue"),
toggle("y = x^3", :toggle2, color = "red"),
toggle("y = sin(x)", :toggle3, color = "green"),
toggle("y = cos(x)", :toggle4, color = "orange"),
toggle("y = ln(x)", :toggle5, color = "black"),
plotly(:chosen_plot, layout=:layout)
end
@page("/", ui)
Запуск приложения
✏️Задание 6
Запустите приложение:
-
Находясь в папке данного курса, выполните в командной строке следующую команду:
engee.genie.start("app3.jl") -
Перейдите по ссылке, появившейся в ячейке вывода. Приложение откроется в новой вкладке браузера.
-
Проверьте правильность работы приложения, изменяя состояния переключателей в различном порядке.
Решение
Окно приложения:
Построенный график является интерактивным. Над полотном графика находятся кнопки взаимодействия с графиком:
С их помощью можно скачать график в формате png и изменить масштаб (приблизить, отдалить или масштабировать график автоматически). При наведении мышью на линию графика можно увидеть координаты точек графика.
Расположение элементов интерфейса по строкам и столбцам
Вы могли заметить, что в этом приложении, а также в приложениях, созданных в двух предыдущих разделах курса, элементы интерфейса располагаются на экране друг под другом в том порядке, в котором они описаны в интерфейсной части кода. Однако это выглядит не всегда красиво, особенно при большом числе элементов. В Genie есть возможность группировки элементов в строки и столбцы, благодаря чему приложение выглядит более аккуратно и компактно. Для расположения нескольких элементов горизонтально (в строку) используется команда row(), а для расположения вертикально (в столбец) – команда column().
Расположим элементы интерфейса в нашем приложении в два столбца: в первом столбце будут располагаться заголовок и пять переключателей, во втором – полотно графика.
✏️Задание 7
Перепишите интерфейсную часть кода в следующем виде:
function ui()
row([
column([
h4("График функции {{caption}}"),
toggle("y = x^2", :toggle1, color = "blue"),
toggle("y = x^3", :toggle2, color = "red"),
toggle("y = sin(x)", :toggle3, color = "green"),
toggle("y = cos(x)", :toggle4, color = "orange"),
toggle("y = ln(x)", :toggle5, color = "black"),
], size = 3),
column(plotly(:chosen_plot, layout=:layout), size = 6),
])
end
Здесь команда row() задает строку, состоящую из двух элементов. Каждый элемент строки представляет собой столбец, задаваемый командой column(). Первый столбец содержит шесть элементов: заголовок и пять переключателей. Из этих шести элементов составлен вектор, поэтому они перечислены через запятую и взяты в квадратные скобки. Второй аргумент size = 3 задает ширину столбца в некоторых условных единицах (максимальное значение – 12 единиц). Второй столбец содержит один элемент – полотно графика. Его ширина задана равной 6 единицам.
Решение
using GenieFramework, Stipple, PlotlyBase
x1 = [0:0.01:10;]
plot1 = Plot(scatter(x=x1, y=x1.^2, line=attr(color="blue")))
plot2 = Plot(scatter(x=x1, y=x1.^3, line=attr(color="red")))
plot3 = Plot(scatter(x=x1, y=sin.(x1), line=attr(color="green")))
plot4 = Plot(scatter(x=x1, y=cos.(x1), line=attr(color="orange")))
plot5 = Plot(scatter(x=x1, y=log.(x1), line=attr(color="black")))
layout = PlotlyBase.Layout(
xaxis=attr(title="X", showgrid=true, range=[0, 10]),
yaxis=attr(title="Y", showgrid=true),
width=800, height=550
)
@app begin
@in toggle1 = true
@in toggle2 = false
@in toggle3 = false
@in toggle4 = false
@in toggle5 = false
@out caption = "y = x^2"
@out chosen_plot = plot1
@out layout = layout
@onchange toggle1 begin
if toggle1 == true
caption = "y = x^2"
toggle2 = false
toggle3 = false
toggle4 = false
toggle5 = false
chosen_plot = plot1
end
end
@onchange toggle2 begin
if toggle2 == true
caption = "y = x^3"
toggle1 = false
toggle3 = false
toggle4 = false
toggle5 = false
chosen_plot = plot2
end
end
@onchange toggle3 begin
if toggle3 == true
caption = "y = sin(x)"
toggle1 = false
toggle2 = false
toggle4 = false
toggle5 = false
chosen_plot = plot3
end
end
@onchange toggle4 begin
if toggle4 == true
caption = "y = cos(x)"
toggle1 = false
toggle2 = false
toggle3 = false
toggle5 = false
chosen_plot = plot4
end
end
@onchange toggle5 begin
if toggle5 == true
caption = "y = ln(x)"
toggle1 = false
toggle2 = false
toggle3 = false
toggle4 = false
chosen_plot = plot5
end
end
end
function ui()
row([
column([
h4("График функции {{caption}}"),
toggle("y = x^2", :toggle1, color = "blue"),
toggle("y = x^3", :toggle2, color = "red"),
toggle("y = sin(x)", :toggle3, color = "green"),
toggle("y = cos(x)", :toggle4, color = "orange"),
toggle("y = ln(x)", :toggle5, color = "black"),
], size = 3),
column(plotly(:chosen_plot, layout=:layout), size = 6),
])
end
@page("/", ui)
✏️Задание 8
Для повторного запуска приложения выполните следующие действия:
- Остановите предыдущую версию приложения. Для этого, не выходя из папки данного курса, в командной строке выполните следующую команду:
engee.genie.stop("app3.jl")
В ячейке вывода должно появиться сообщение:
`GenieApplicationStatus(STOPPED <путь к приложению>)`.
- Запустите новую версию приложения. Перейдите по ссылке, появившейся в ячейке вывода. Приложение откроется в новой вкладке браузера.
- Убедитесь в том, что расположение элементов интерфейса изменилось, но функционал приложения остался прежним.
Решение
Окно приложения: