【问题标题】:Plotly axis as exponential format将轴绘制为指数格式
【发布时间】:2018-09-23 21:14:03
【问题描述】:

这是对这个问题的跟进:SO Q

上述问题的答案使用了将轴刻度变为指数的 JavaScript 代码。它适用于单个图上的单个轴。

在 subplot() 结构中运行它时,当我将其应用于最终图时,它仅适用于第一个图。

我正在寻找的修改是这些:

1:如何使它在子图上工作。我尝试在每个子图的构建中调用 JavaScript,但是所有图都没有指数。

2:让它同时适用于 x 和 y 轴(我试过了,失败了,哭了一点)

3:当轴不是数字时,使其不破坏宇宙(我的应用程序也可以绘制日期列,因此需要检查它是否实际上是数字输入)

4:如果可能,打印为 1.23E+1 而不是 1E+1

 library(shiny)
library(plotly)
library(htmlwidgets)


ui <- fluidPage(
    mainPanel(
     plotlyOutput('myplotly')
     )
  )

server <- function(input, output, session) {

  javascript <- "
function(el, x) 
{
  function fix_ticks()
  {
    ticks = Plotly.d3.selectAll('g.ytick').selectAll('text');
    ticks.forEach(function(tick) 
    {
      var num = parseInt(tick[0].innerHTML); 
      tick[0].innerHTML = num.toExponential();
    })
  }
  el.on('plotly_afterplot', fix_ticks);
}"


  output$myplotly <- renderPlotly({

    myplots <- lapply(unique(mtcars$cyl), function(v) {

    data <- mtcars[which(mtcars$cyl == v), ] 
      subp <-   plot_ly(data = data,
                x = rownames(data), 
                y = ~mpg,
                type = "bar")
      subp
     })

    p <- subplot(myplots, margin = 0.08)

    p$elementId <- NULL   ## to surpress warning of widgetid
    p <- onRender(p, javascript)

    p <- p %>% layout(margin =list(l = 60, r = 20, b = 160, t = 70) )

    p
  })
 }

shinyApp(ui = ui, server = server)

更新 根据此处给出的答案建议,我现在正在运行以下代码来检查数字,然后适用于每个轴。我还没有得到最后一个处理负值的建议,它是使用 tick[0].innerHTML。我最终使用了第 1 点下答案下的建议,因为我无法让 tick[0].innerHTML 方法在 forEach 循环内工作。但是,针对先前评论的建议是回到 tick[0] 方法,我无法让一种方法完全起作用。

这是我在遇到负面问题之前最终使用的代码 -> NaN 问题

  javascriptMPP <- "
  function(el, x) 
  {
    function isNumber(n) {
      return (Object.prototype.toString.call(n) === '[object Number]' || Object.prototype.toString.call(n) === '[object String]') &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
    }
    function fixTicks()
    {
      ticks = Plotly.d3.selectAll('g.yaxislayer-above,g.xaxislayer-above').selectAll('text');
      ticks.each(function(d) 
      {
        if(parseInt(d.text) !== 0 )
        {
          var num = parseInt(d.text).toExponential(2);
          Plotly.d3.select(this).text(num);
        }
      })
    }
    el.on('plotly_afterplot', fixTicks);
  }"

【问题讨论】:

  • 注意正确拼写 JavaScript 以避免与 Java 发生搜索冲突。

标签: javascript r plotly subplot


【解决方案1】:

感谢此处发布的其他答案,我终于设法解决了所有问题。

javascript:
替换符号,使其也适用于负值

  var num1 = parseInt(d.text.replace(/\\u2013|\\u2014|\\u2212/g, '-'));

如果 value 为 0 则跳过,因为它不必更改为 exp 格式

   if(parseInt(d.text) !== 0 )

如果值为文本则跳过(在更改负数符号后,否则它们被视为文本

 if(isNaN(num1)){

还在绘图代码中添加了布局命令,并将标签以45度角放置在x轴上,否则它们会相互重叠。 对 mtcars df 进行了一些更改,以便我们在数据中获得负数和大数。

为了在 xaxis 上绘制文本值,它适用于:

x = rownames(data),  

而不是数字 x 参数

x = ~disp, 

这是工作代码:

library(shiny)
library(plotly)
library(htmlwidgets)


ui <- fluidPage(
  mainPanel(
    plotlyOutput('myplotly')
  )
)

server <- function(input, output, session) {

  javascriptMPP <- "
  function(el, x) 
  {
  function isNumber(n) {
  return (Object.prototype.toString.call(n) === '[object Number]' || Object.prototype.toString.call(n) === '[object String]') &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, ''));
  }
  function fixTicks()
  {
  ticks = Plotly.d3.selectAll('g.yaxislayer-above,g.xaxislayer-above').selectAll('text');
  ticks.each(function(d) 
  {
   if(parseInt(d.text) !== 0 )
  {
  var num1 = parseInt(d.text.replace(/\\u2013|\\u2014|\\u2212/g, '-'));
  if(isNaN(num1)){
  } else {
    var num = parseInt(num1).toExponential(2);
  Plotly.d3.select(this).text(num);
  }
}
  })
  }
  el.on('plotly_afterplot', fixTicks);
  }"

  output$myplotly <- renderPlotly({
    mtcars2 <- mtcars
    mtcars2$mpg <- mtcars2$mpg*-1
    mtcars <- rbind(mtcars, mtcars2)
    mtcars3 <- mtcars
    mtcars3$mpg <- mtcars3$mpg*1000000

    mtcars <- rbind(mtcars, mtcars3)

    myplots <- lapply(unique(mtcars$cyl), function(v) {

      data <- mtcars[which(mtcars$cyl == v), ] 
      subp <-   plot_ly(data = data,
                        x = ~disp, 
                        y = ~mpg,
                        type = "bar")
      subp <- layout(subp, xaxis = list(tickangle = 45))
      subp
    })

    p <- subplot(myplots, margin = 0.08)

    p$elementId <- NULL   ## to surpress warning of widgetid
    p <- onRender(p, javascriptMPP)

    p <- p %>% layout(margin =list(l = 60, r = 20, b = 160, t = 70) )

    p
  })
}

shinyApp(ui = ui, server = server)

【讨论】:

    【解决方案2】:

    1:如何使它在子图上工作。我尝试在构建中调用 java 每个子图,但所有图都没有指数。

    2nd/3rd/etc 的滴答声。子图的类名如y2tick/y3tick/等。我们可以让我们的 d3 选择器不那么具体,然后使用 each 更改所有刻度。

    ticks = Plotly.d3.selectAll('g.yaxislayer-above').selectAll('text');
    ticks.each(function(d, i) 
    {
      var num = parseInt(d.text).toExponential();
      Plotly.d3.select(this).text(num);
    })
    

    2:使其适用于 x 和 y 轴(我尝试过,失败并哭了 小)

    只需将 selectAll 语句更改为Plotly.d3.selectAll('g.xaxislayer-above').selectAll('text')

    3:当轴不存在时,让它不破坏宇宙 一个数字(我的应用程序也可以绘制日期列,所以它需要检查 是否真的是数字输入)

    您可以更改 fixTicks 函数以检查输入值是否为数字,例如通过使用typeof 或正则表达式。使用 1999、2000 等值可能会很棘手,您需要手动解决。

    4:如果可能,打印为 1.23E+1 而不是 1E+1

    toExponential 取一个parameter,它是“小数点后符号中的位数”,即num.toExponential(3) 在您的情况下可以解决问题。

    来自评论:当刻度上的值为负值时,我似乎得到 NaN

    Plotly 使用 Unicode minus sign 而不是常规的破折号。您可以将其替换为以下 JavaScript 行:

    var num = parseInt(tick[0].innerHTML.replace(/\\u2013|\\u2014|\\u2212/g, '-'));
    

    注意:R 中需要双反斜杠 \\,纯 JavaScript 只需要一个 \

    【讨论】:

    • 嗯,我快到了。找到了一种在 javascript 中检查数字的方法,并将格式设置为指数(2)给出两位小数。在javascript中尝试这个,但是concat阻止它工作 var ticksx = Plotly.d3.selectAll('g.xaxislayer-above').selectAll('text'); var ticksy = Plotly.d3.selectAll('g.yaxislayer-above').selectAll('text');滴答声 = ticksy.concat(ticksx); ticks.each(function(d, i) 没有 concat,我现在可以将它应用于 X OR Y
    • Max,当刻度上的值为负值时,我似乎得到 NaN
    • 嗯,您似乎在我的 2 个问题的答案中的 tick[0].innerHTML 方法和 parseInt(d.text 之间切换。我最终使用了您的 var num = parseInt(d.text) .toExponential(2); Plotly.d3.select(this).text(num); 解决方案,但我尝试了一些类似这样的变体: var num parseInt(d.text).replace(/\\u2013|\\u2014 |\\u2212/g, '-')); var num = num.toExponential(2); Plotly.d3.select(this).text(num);但我似乎无法正确使用语法
    • Max,我认为您的解决方案还有另一个问题。 Plotly 将标签放入 10k、20k 等,您的脚本(逻辑上)将它们放入 1.00E1 和 2,00E1
    • 恐怖!等我有一台可用的电脑回来看看。
    猜你喜欢
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 2018-12-08
    • 1970-01-01
    相关资源
    最近更新 更多