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

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

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

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

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

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

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

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

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

                                        last_command_id = doRCommand ('levels (' + variable + ')', "commandFinished");
                                }

                                commandFinished = function (result, id) {
                                        if (id != last_command_id) return;  // зараз з’явиться новий результат
                                        if (typeof (result) == "undefined") {
                                                gui.setListValue ("selector.available", Array ("ERROR"));
                                                return;
                                        }
                                        gui.setValue ("selector.enabled", 1);
                                        gui.setListValue ("selector.available", result);
                                }
                ]]></script>
        

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

Під час виконання команди програма виконує вказаний виклик (у нашому випадку commandFinished) з двома параметрами: самим результатом та ідентифікатором відповідної команди. Результат належатиме до типу, який є відповідним представленню у R, тобто до числових масивів, якщо результат є числовим тощо. Результатом може бути навіть list() R, але у цьому випадку його буде представлено як Array() JS без назв.

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