在 R 上对 rpivottable 进行几个配置 saves/loadings

Make several configuration saves/loadings of rpivottable on R

我在另一个 post 上找到的以下代码(如果有人感兴趣,我可以 link)使用 flexdashboard 在 R rpivottable 上添加了保存选项。保存是通过 cookie 完成的。
我正在尝试重新创建它,但有多个保存选项,基本上有 SAVE1、SAVE2,.. 并且能够加载想要的保存。我对JS没有经验,所以真的很难做。

---
title: "rpivottable_test"
output: html_document
---
knitr::opts_chunk$set(echo = FALSE)
# devtools::install_github("fraupflaume/rpivotTable")
library(rpivotTable)
data(mtcars)
names(mtcars)[10] <- "George.Dontas"

保存当前配置 恢复以前的配置


rpivotTable(mtcars,rows="George.Dontas", cols = c("cyl"), width = "90%", height = "40%",
            rendererOptions = list(
              c3 = list(legend = list(show = FALSE), 
                        data = list(labels = TRUE),
                        options = list(responsive = TRUE,
                                       maintainAspectRatio = FALSE),
                        size = list(width = "600",
                                    height = "500")),
              d3 = list(size = list(width = "500", height = "500")))) 

// save current state of the tables to my browser
setTimeout(function(){       //add the events first
  document.querySelector('a#saveBtn').addEventListener('click', savoring);
  document.querySelector('a#restoBtn').addEventListener('click', giveItBack);
  function savoring() {                             // function to save
    el = document.querySelectorAll('.rpivotTable');
    for(i=0; i < el.length; i++){
      elId = el[i].getAttribute("id");
      stringy = $('#' + elId).data("pivotUIOptions"); // collect rows/columns filters
      delete stringy['aggregators'];                 // remove the arbitrary
      delete stringy['renderers'];
      stringy2 = JSON.stringify(stringy);            // make it one key:value
      window.localStorage.setItem('table' + i, stringy2); // store it!
    }
  };
  function giveItBack() {                           // function to regurgitate
    el = document.querySelectorAll('.rpivotTable');
    console.log("working on the giver");
    ods = [...el[0].ownerDocument.scripts];         // make it an array
    for(j=0; j < el.length; j++){
      elId = el[j].getAttribute("id");
      where = ods.filter(function(ods){             // filter scripts for table data
        return ods.dataset['for'] === elId;
      })[0].innerHTML; 
      where2 = JSON.parse(where).x.data;            // WOOO HOO! I figured it out!!
      where3 = HTMLWidgets.dataframeToD3(where2);   // finally sheesh!!
      gimme = window.localStorage.getItem('table' + j); // get storage
      $('#' + elId).pivotUI(where3, JSON.parse(gimme), true, "en"); // put it back!
    }
  }
},100);

这使用默认的系统警报和提示框。它们的外观从一个 OS 到另一个略有不同。

我为按钮和 RMD 添加了 CSS。我用了html_document。如果您使用 flex_dashboard,则 class main-container 不需要 CSS。 body 的 CSS 可能有用,也可能没用(取决于您进行的其他操作)。

如果您使用的是 Cran 软件包,rendererOptions 将不起作用 as-is。创建对象后,您必须删除列表级别。除非您更改 rpivotTable 包中的 Javascript 文件 d3_renderers.js,否则 D3 rendererOptions 将不起作用。 (这就是我用我的叉子做的。)如果你用我的叉子,它会工作 as-is。

我已经为

添加了处理程序
  • 命名违规(白色space、特殊字符之类的)
  • 恢复配置时没有匹配的名称
    • returns存储中所有名字的列表
    • 然后提示用户输入另一个配置名称
  • 如果在提示中按下取消,它会取消保存或恢复过程

您可能会注意到恢复功能有不少变化。那是因为原来的代码会丢失subtotals, sorters, renderer tsv.

我试着想出任何可能出错的地方,这就是我所在的位置。如果您 运行 遇到任何问题,请告诉我。如有疑问,请提问。

YAML、选项和 CSS:

---
title: "button and input tester!"
author: "me"
date: '2022-05-12'
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```

<style>
body {    /*push content away from far right and left edges*/
  margin-right: 2%;
  margin-left: 2%;
}
.main-container {
  max-width: unset;
}
.btn { 
  vertical-align: middle;
  -moz-box-shadow: 0px 10px 14px -7px #000000;
  -webkit-box-shadow: 0px 10px 14px -7px #000000;
  box-shadow: 0px 10px 14px -7px #000000;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
  border-radius: 4px;
  border: .5px solid black;
  display: inline-block;
  font-size: 1.2em;           
  padding: .3em 0px;
  width: 20em;                 
  text-decoration: none; /*no underline!!*/
  cursor: pointer;
}
.btn:active {      /*simulate movement*/
  position: relative;
  top: 1px;
}
</style>

table.

```{r data,include=F}
# devtools::install_github("fraupflaume/rpivotTable")
library(rpivotTable)
data(mtcars)

```

## Make it Interesting...or not

Do you want to save or restore the previously saved pivot tables' configuration?

<a id='saveNamed' class='btn' style="background-color:#003b70;color:white;">Save Configuration by Name</a>
<a id='restoNamed' class='btn' style="background-color:#b21e29;color:white;">Restore Configuration with Custom Name</a>


```{r showMe, echo=FALSE, fig.show="hold"}
rpivotTable(mtcars, rows="am", cols = c("cyl"), width = "90%", 
            height = "40%", subtotals = TRUE,
            rendererOptions = list(
              c3 = list(legend = list(show = FALSE), 
                        data = list(labels = TRUE),
                        options = list(responsive = TRUE,
                                       maintainAspectRatio = FALSE),
                        size = list(width = "600",
                                    height = "500")),
              d3 = list(size = list(width = "500", height = "500")) 
            ))
```


That's all, folks.

最后,JS。

```{r listenOrElse,results="asis",engine="js"}

// for ONE TABLE
setTimeout(function(){  // add to buttons
  document.querySelector('a#saveNamed').addEventListener('click', savoring); 
  document.querySelector('a#restoNamed').addEventListener('click', giveItBack);
  function savoring() {                              // function to save
    el = document.querySelector('.rpivotTable');
    msg = "Choose a name for the configuration that you are saving.";
    inName = prompt(msg, ['Enter a name with no spaces or special characters'])
    if(inName === null) {return;};                   // they changed their mind; nothing saved
    inName = inName.replace(/[^a-z0-9.]/gi, '');     // validate string
    path = window.location.pathname.split("/").pop().split(".").slice()[0]; //filename
    elId = el.getAttribute("id");
    stringy = $('#' + elId).data("pivotUIOptions");  // collect rows/col filters
    delete stringy['aggregators'];                   // remove not-parse-friendly keys
    delete stringy['renderers'];
    stringy2 = JSON.stringify(stringy);              // one key:value pair for storage
    window.localStorage.setItem(path + '_' + inName, stringy2);  // STORE it!
  };
  function giveItBack() {                           // function to regurgitate
    el = document.querySelector('.rpivotTable');
    msg = "Enter the name of the configuration you would like to retrieve.";
    confName = prompt(msg, ["Enter a name with no spaces or special characters"]);
    if(confName === null) {return;}; 
    confName = confName.replace(/[^a-z0-9.]/gi, '');    // validate string
    ods = [...el.ownerDocument.scripts];             // make it an array
    path = window.location.pathname.split("/").pop().split(".").slice()[0]; //filename
    elId = el.getAttribute("id");
    where = ods.filter(function(ods){             // filter scripts for data
      return ods.dataset['for'] === elId;
    })[0].innerHTML; 
    where2 = JSON.parse(where).x.data;            // format data for pivotUI()
    where3 = HTMLWidgets.dataframeToD3(where2);   // ...still formatting
    if(window.localStorage.getItem(path + '_' + confName) === null) { // alert
      len = window.localStorage.length
      var str;
      for(i = 0; i < len; i++) {
        w = window.localStorage.key(i);
        ind = w.lastIndexOf('_');
        w2 = w.substr(ind + 1);   // remove file/page name and table number
        str = str + w2 + '\n';    // make one long string of names
      }
      str2 = "WARNING: There is no saved pivot table configuration with the name " + confName + '.';
      str2 += " Here is a list of the configuration names that are currently stored for this page:\n";
      str2 += str;
      alert(str2);
      confName = prompt(msg, ["Enter a name with no spaces or special characters"]);
      if(confName === null) {
        return
      }; 
      confName = confName.replace(/[^a-z0-9.]/gi, '');    // validate string
    }
    gimme = window.localStorage.getItem(path + '_' + confName); // get storage
    gimmeMore = JSON.parse(gimme);                            // prepare for recall
    if(where.includes('"subtotals":true')){       // is the option 'subtotal' used?
      gimmeMore.renderers = $.pivotUtilities.subtotal_renderers;
      gimmeMore.dataClass = $.pivotUtilities.SubtotalPivotData;
    }; 
    if(where.includes('"tsv":true')){             // is the option 'tsv' used?
      gimmeMore.renderers = $.extend(gimmeMore.renderers, $.pivotUtilities.export_renderers);
    };
    if(where.includes('sortAs')){
      // passed as a function, they will get lost in save & retrieve
      stringy = $('#' + elId).data("pivotUIOptions").sorters;
      gimmeMore.sorters = stringy;
    }
    $('#' + elId).pivotUI(where3, gimmeMore, true, "en"); // put it back!
  };
}, 500);

```

在此图像中,您可以看到输入了 'bar chart'(名称违规)。

在恢复期间,我搜索了 'bar'(不存在)。

现在,当我再次收到提示时,我将输入条形图(使用 space),即使您可以看到 'barchart' 存在,而不是条形图。

您仍然会看到图表。处理程序还将删除此处的白色 space 和特殊字符。