Далее предполагается, что у вас установлена последняя версия Chrome с установленными инструментами разработчика.
Прелюдия
Начнем с обзора кода JavaScript для ggvis -- особенно его интерфейс с Shiny.
ggvis, как и Shiny, взаимодействует с серверной частью R через HTTP-запросы, которые включены в https://github.com/rstudio/httpuv (первоначально основанном на в библиотеке libuv C++). В частности, он осуществляет некоторые коммуникации по протоколу веб-сокетов: R и JavaScript постоянно перетасовывают сообщения. взад и вперед друг к другу, используя открытое соединение Websockets.
Отладка с помощью инструментов разработчика Chrome
В частности, наведя указатель мыши на всплывающую подсказку, откройте консоль разработчика Chrome, щелкнув правой кнопкой мыши и выбрав «Проверить элемент».
![введите здесь описание изображения](https://i.stack.imgur.com/wQXTa.png)
(Если вы его не видите, возможно, вам придется включить его — Google вам в помощь). Затем откройте вкладку «Сеть», перезагрузите страницу, наведите указатель мыши на точку данных и просмотрите содержимое с помощью ttFunc2
после выбора ресурса "websocket/"
:
![введите здесь описание изображения](https://i.stack.imgur.com/UQOCI.png)
Вы можете щелкнуть правой кнопкой мыши и скопировать содержимое в файл:
{
"custom": {
"ggvis_message": {
"type": "show_tooltip",
"id": null,
"data": {
"pagex": 382,
"pagey": 175,
"html": {
"name": "table",
"attribs": [],
"children": [
[
{
"name": "tr",
...
(Я урезал часть содержимого). Как вы можете заметить, ggvis получает сообщение с телом всплывающей подсказки, но структурированное как объект JavaScript. Сравните это с выводом ttFunc1
:
{
"custom": {
"ggvis_message": {
"type": "show_tooltip",
"id": null,
"data": {
"pagex": 264,
"pagey": 238,
"html": "<table> <tr><td> xs </td><td> 7 </td></tr><tr><td> ys </td><td> -0.07295337 </td></tr><tr><td> color </td><td> red </td></tr><tr><td> size </td><td> 150 </td></tr></table>"
}}}}
Таким образом, первый запрос получает объект Javascript, представляющий HTML, а второй — необработанный HTML. Вскоре мы увидим, почему это так. А пока обратите внимание на код JavaScript код, обрабатывающий это сообщение:
// Tooltip message handlers
ggvis.messages.addHandler("show_tooltip", function(data, id) {
/* jshint unused: false */
// Remove any existing tooltips
$('.ggvis-tooltip').remove();
// Add the tooltip div
var $el = $('<div id="ggvis-tooltip" class="ggvis-tooltip"></div>')
.appendTo('body');
$el.html(data.html);
...
Ах ха! Таким образом, он использует jQuery для установки HTML непосредственно в элемент html
сообщения Websocket. Поскольку jQuery никогда не предполагал, что он будет взаимодействовать с потоком веб-вывода из пакета Rhtmltools
, конечным результатом будет то, что он получит объект JavaScript вместо строки, а поведение по умолчанию заключается в том, чтобы не отображать ничего.
К исправлению
Теперь, когда мы изолировали нашу ошибку, у нас есть выбор: мы можем исправить это на стороне R или на стороне JavaScript. Я предлагаю первое, так как преобразование htmltools
вывода не должно быть задачей клиентского кода и нарушает основные принципы разработчика, такие как модульность.
Таким образом, мы должны выяснить, где он находится на стороне R. Начнем с того, что перейдем к коду ggvis github и найдем "tooltip"
(это полезно знать — вы можете поиск по всей кодовой базе с помощью Github!):
![введите здесь описание изображения](https://i.stack.imgur.com/W5toM.png)
Находим interact_tooltip.R
и замечаем функцию:
show_tooltip <- function(session, l = 0, t = 0, html = "") {
ggvis_message(session, "show_tooltip",
list(pagex = l, pagey = t, html = html))
}
Ошибка в том, что в нашем примере html
является объектом shiny.tag
, а не character
. К счастью, shiny.tag
можно преобразовать в его представление HTML с помощью as.character
, как мы можем проверить из консоли:
> as.character(tags$table(tags$tr(tags$td('test'))))
<table>
<tr>
<td>test</td>
</tr>
</table>
так что мы можем пойти дальше и исправить код:
show_tooltip <- function(session, l = 0, t = 0, html = "") {
ggvis_message(session, "show_tooltip",
list(pagex = l, pagey = t, html = as.character(html)))
}
Помощь своим друзьям
Теперь, когда мы нашли исправление, мы должны поделиться им с нашими друзьями, чтобы они тоже могли его использовать. Мы можем сделать это, разветвив репозиторий на Github и отправив запрос на включение (большой зеленая кнопка).
![введите здесь описание изображения](https://i.stack.imgur.com/DD9U9.png)
![введите здесь описание изображения](https://i.stack.imgur.com/BIoE9.png)
Если вы хотите сразу же использовать фиксированный код, не дожидаясь, пока Winston объединит его, вы можете ввести
require(devtools); install_github('robertzk/ggvis')
и правильная версия будет установлена (но не делайте этого после того, как этому посту исполнится неделя, так как мой форк, вероятно, устарел). Я протестировал его, используя как ttFunc1
, так и ttFunc2
, и теперь их поведение идентично.
Можно копаться во внутренностях пакета. Никогда не бойся!
person
Robert Krzyzanowski
schedule
01.08.2014