Надсилання запитів щодо даних до R

Інколи може виникнути потреба у отриманні певних даних від R з метою показу їх у графічному інтерфейсі вашого додатка. Наприклад, ви можете запропонувати набір рівнів фактора, який користувач вибрав для аналізу. Починаючи з версії 0.6.2 RKWard, це можна робити. Перш ніж ми розпочнемо пояснювати, як саме це робити, важливо ознайомитися з певними підводними каменями цього підходу:

Код R, який запускається у частині графічного інтерфейсу додатка, оброблятиметься у циклі обробки подій R, тобто його можна виконувати під час виконання інших обчислень. Так зроблено, щоб графічним інтерфейсом вашого додатка можна було користуватися, навіть коли R виконує якісь інші дії. Втім, це робить важливою відсутність у вашому коді сторонніх ефектів. Зокрема, має бути забезпечено такі вимоги щодо коду:

  • Не виконувати надання змінним значень у .GlobalEnv або будь-якому іншому нелокальному середовищі.

  • Не виводити нічого до файла виведення результатів.

  • Не малювати нічого на екрані.

  • Загалом, не віддавайте ніяких команд, які можуть мати побіжні наслідки. Ваш код може читати дані, але не повинен хоч щось робити.

Беручи це все до уваги, наведемо загальний зразок коду. Ви можете скористатися цим у розділі керування логікою інтерфейсу за допомогою скриптів:

<script><![CDATA[
                                let update = gui.addChangeCommand ("variable", "update ()", function () {
                                        gui.setValue ("selector.enabled", 0);
                                        variable = gui.getValue ("variable");
                                        if (variable == "") return;

                                        new RCommand('levels (' + variable + ')', "myid").then(result =
> {
                                                gui.setValue ("selector.enabled", 1);
                                                gui.setListValue ("selector.available", result);
                                        }).catch(msg =
> {
                                                if (msg === "outdated") return;  // команду було скасовано, оскільки невдовзі має з'явитися нова -> benign
                                                // можлива обробка іншої помилки, msg містить видані попередження та повідомлення про помилки,
                                                // якщо команда не пройшла e.g.:
                                                gui.setListValue ("selector.available", Array ("ERROR:", msg));
                                        });
                                };
                ]]></script>
        

Тут variable — це властивість, що містить назву об’єкта (наприклад, у <varslot>). Кожного разу, коли назва змінюється, виникає потреба у оновленні показу рівнів у <valueselector> із назвою selector. Ключовою функцією тут є інструкція конструктора new RCommand(), функція, яка приймає як перший параметр рядок команди. Зауважте, що команда виконуватиметься у асинхронному режимі, і це дещо ускладнює речі. По-перше, вам слід зробити так, щоб ваш <valueselector> залишався вимкненим, доки у ньому не міститиметься актуальної інформації. По-друге, оскільки користувач може внести зміни швидко, може бути створено декілька команд, перш ніж ми отримаємо якийсь результат. Отже, вам слід забезпечити роботу лише із найсвіжішою командою.

Для роботи з асинхронністю тут повертається об'єкт Promise. Більше інформації про цю потужну функцію JavaScript можна знайти в інтернеті. Важливо знати, що додавання оператора .then() дозволяє вказати, що станеться після завершення команди, а оператор .catch() можна використовувати для обробки будь-яких помилок. Знову ж таки, майте на увазі, що блок .then() не виконується одразу. Щоб зрозуміти наслідки цього, під час розробки може бути корисним вставити Sys.sleep(1); у вашу команду R, щоб побачити, що відбувається, коли виконання команди не завершується негайно.

Зрештою, для обробки створення кількох команд можна вказати другий аргумент new RCommand() (у цьому прикладі - "myid"). Будь-які команди з однаковим (довільно вибраним) ідентифікатором вважатимуться такими, що належать до однієї черги. RKWard потім переконається, що лише остання команда фактично запустить блок .then(), тоді як будь-які застарілі команди надходитимуть у блок .catch(). Тут застарілі команди можна ідентифікувати, оскільки рядок "outdated" передається як їхнє значення, тоді як для будь-яких інших можливих помилок передаються попередження та повідомлення про помилки.

Зауважте, що цей приклад є дещо спрощеним. Насправді, вам доведеться вжити певних застережних заходів, наприклад, уникати надмірної кількості вкладених рівнів у засобі вибору. Втім, ймовірно, вам не потрібно буде дбати про усе самому. Наведений вище приклад взято з додатка rkward::level_select, який ви можете просто вбудувати до вашого власного додатка. Це навіть надасть вам змогу вказати інший вираз для виконання замість levels().

Примітка

У ранніх версіях RKWard команди R запускалися за допомогою дещо складнішої функції doRCommand(). Ця функція усе ще є частиною деяких додатків, але ми не рекомендуємо користуватися нею у новому програмному коді.