简体   繁体   English

如何在ggplotly中调整条形图?

[英]How to adjust barchart in ggplotly?

I have barchart with dual-axis in order to visualize 3 numerical variables.我有双轴条形图,以便可视化 3 个数值变量。 All these work pretty nice in ggplot.所有这些在 ggplot 中都很好用。 However, when I convert ggplot to ggplotly , there are issues:但是,当我将 ggplot 转换为ggplotly时,会出现问题:

  1. in the legend, there are strange 1s (highlighted in yellow)在传说中,有奇怪的1(以黄色突出显示)
  2. in the hover, there are double values (highlighted in yellow)在悬停中,有双值(以黄色突出显示)
  3. changes of hjust=0, vjust=-0.5 in geom_text are not reflected on the plot geom_text 中 hjust=0, vjust =-0.5的变化不会反映在绘图上

Could anybody help me to adjust these issues?有人可以帮我调整这些问题吗?

df <- data.frame (model  = c("A", "B", "C","D","E","F"),
                  share = c(12,20,15,9,60,20),
                  sale = c(16,25,18,14,67,28),
                  cost = c(14,19,28,24,57,28))

#set levels of model by cost
df$model <- factor(df$model, levels = arrange(df, desc(df$cost))$model)

library(tidyverse)

df_long <- df %>% 
  pivot_longer(
    cols = -model
  ) 


plt <- ggplot(df_long, aes(x = model, y= value, label=value))+
  geom_col(data = filter(df_long, name != "cost"), aes(fill=name), position = position_dodge())+
  scale_fill_manual(values = c("blue", "grey"))+
  geom_line(data = filter(df_long, name == "cost"), aes(color = name, group = 1), size = 1)+
  scale_color_manual(values = "red")+
  geom_text(data = filter(df_long, name == "cost"), size = 3,hjust=0, vjust=-0.5)+
  geom_label(data = filter(df_long, name == "cost"), hjust=0, vjust=-0.5)+
  scale_y_continuous(
    name = "Sale and Share",
    sec.axis = sec_axis(~., name ="Cost")
  )+
  theme_minimal()+
  theme(legend.title=element_blank())


ggplotly(plt)

在此处输入图像描述

Legend issue:传说问题:

Using the code in this post: Strange formatting of legend in ggplotly in R .使用这篇文章中的代码: R 中 ggplotly 中的图例的奇怪格式 You can change the legend in ggplotly like this:您可以像这样更改ggplotly中的图例:

library(plotly)

myplot = ggplotly(plt)
for (i in 1:length(myplot$x$data)){
  if (!is.null(myplot$x$data[[i]]$name)){
    myplot$x$data[[i]]$name =  gsub("\\(","",str_split(myplot$x$data[[i]]$name,",")[[1]][1])
  }
}

myplot

Output:输出:

在此处输入图像描述

Further approach from @Quinten's answer, @Quinten 回答的进一步方法,

to handle 'name name' and 'value value' things,处理'name name'和'value value'的事情,

try尝试

tooltip = c("value", "name", "model")
plt1$x$layout$legend$title$text <- "name"

Full code is完整代码是

plt <- 
  ggplot(df_long, aes(x = model, y= value, label = NA))+
  geom_col(data = filter(df_long, name != "cost"), aes(fill=name), position = position_dodge())+
  scale_fill_manual(values = c("blue", "grey"))+
  geom_line(data = filter(df_long, name == "cost"), aes( group = 1, color = name), size = 1)+
  scale_color_manual(values = "red")+
  #geom_text(data = filter(df_long, name == "cost"), size = 3,hjust=0, vjust=-0.5)+
  geom_label(data = filter(df_long, name == "cost"), hjust=0, vjust=-0.5)+
  scale_y_continuous(
    name = "Sale and Share",
    sec.axis = sec_axis(~., name ="Cost")
  )+
  theme_minimal()

plt1 <- ggplotly(plt, tooltip = c("value", "name", "model")) 
for (i in 1:length(plt1$x$data)){
  if (!is.null(plt1$x$data[[i]]$name)){
    plt1$x$data[[i]]$name =  gsub("\\(","",str_split(plt1$x$data[[i]]$name,",")[[1]][1])
  }
}
plt1$x$layout$legend$title$text <- "name"

It looks like you've got some great information so far.到目前为止,您似乎已经掌握了一些重要信息。 This addresses all of the things you identified.这解决了您确定的所有问题。 Although, at this point, it would be a LOT easier to just make the plot in Plotly!虽然,在这一点上,在 Plotly 中制作情节会容易得多!

The first thing I did is comment out the call for geom_text and geom_label .我做的第一件事是注释掉对geom_textgeom_label的调用。 Plotly doesn't tend to play well here. Plotly 在这里的表现并不好。 It is going back into the plot, but not here.它正在回到情节中,但不是在这里。

Next, I built your plot and looked at the names and legend groups that were assigned by the conversion.接下来,我构建了您的绘图并查看了转换分配的名称和图例组。 This doesn't change anything—this is just looking.这并没有改变任何东西——这只是在寻找。

plt2 <- plotly_build(plt)

invisible(
  lapply(1:length(plt2$x$data),
         function(j) {
           message(j, " ", plt2$x$data[[j]]$name, " & ",
                   plt2$x$data[[j]]$legendgroup)
         })
)
# 1 (sale,1) & (sale,1)
# 2 (share,1) & (share,1)
# 3 (cost,1) & (cost,1)

@Quinten addressed this issue, but this is how you can just look. @Quinten 解决了这个问题,但这就是你的样子。 Once I saw what Plotly "made", I was sure I knew what I needed to change.一旦我看到 Plotly “做出”了什么,我确信我知道我需要改变什么。

This code changes these strings.此代码更改这些字符串。 It also prints the update to the console so that you can inspect what you expect.还将更新打印到控制台,以便您检查您的期望。

invisible(
  lapply(1:length(plt2$x$data),
         function(j) {
           x <- plt2$x$data[[j]]$name           # find the name
           y <- str_extract(x, "[a-z]+")        # remove anything that's not a letter
           plt2$x$data[[j]]$name <<- y          # put it back
           plt2$x$data[[j]]$legendgroup <<- y
           message(j, " ", plt2$x$data[[j]]$name, " & ",
                   plt2$x$data[[j]]$legendgroup)
         })
)
# 1 sale & sale
# 2 share & share
# 3 cost & cost

You can use this sort of look/change/check to validate the information that ends up in the tooltips, as well.您也可以使用这种查看/更改/检查来验证最终出现在工具提示中的信息。 Instead of $name or $legendgroup , you'll look at $text .您将查看$text而不是$name$legendgroup

This next chunk of code doesn't check the input and print it out (I figured that would be redundant).下一段代码不会检查输入并将其打印出来(我认为这将是多余的)。 This just changes it.这只是改变它。 (I did use that process to build this though.) (不过,我确实使用该过程来构建它。)

tx = " "
invisible(
  lapply(1:length(plt2$x$data),
         function(k){
           tx <<- plt2$x$data[[k]]$text # tooltip for each trace
           lapply(1:length(tx),
                  function(m) {
                    tr <- strsplit(tx[[m]], "<br />") # tooltip for each point
                    tr2 <- unique(tr[[1]])            # remove redundancy           
                    str <- paste0(tr2, collapse = "<br />")
                    tx[[m]] <<- str                   # put it back together
                  })
           plt2$x$data[[k]]$text <<- tx               # change the plot
         })
)

Now on to the labels-if you want a background or border, you have to use annotations in Plotly.现在到标签上——如果你想要背景或边框,你必须在 Plotly 中使用annotations Like annotation in the ggplot package, annotations in Plotly has less 'rules' per se.与 ggplot 包中的annotation一样,Plotly 中的annotations本身具有较少的“规则”。

You have an odd order for the model , so that has to be addressed, as well.您对model有一个奇怪的顺序,因此也必须解决这个问题。 When data moves between ggplot and Plotly, things tend to be awry .当数据在 ggplot 和 Plotly 之间移动时,事情往往会出错 So it's unlikely that you'd be able to connect to the original data.因此,您不太可能连接到原始数据。

One thing to keep in mind, I used paper space for the x-axis.需要记住的一件事是,我将图纸空间用于 x 轴。 The default paper space (domain) in Plotly is [0,1]. Plotly 中的默认图纸空间(域)为 [0,1]。 Your graph is evenly spaced along the x, with your values in the middle of each of the six categories, so everything on the x is in terms of 1/6th space.您的图表沿 x 均匀分布,您的值位于六个类别的中间,因此 x 上的所有内容都以 1/6 空间表示。

So first, put the data in order as it needs to appear in the plot.因此,首先,将数据按需要出现在图中的顺序排列。 Then add the annotations (labels) to the plot.然后将注释(标签)添加到图中。 I've also removed the name of the legend here.我还在这里删除了图例的名称。

# to add labels, we need to have the order the data appears on the plot
df2 <- df_long %>% 
  arrange(desc(value)) %>% 
  filter(name == "cost")

plt2 %>% 
  layout(legend = list(title = "")) %>%  # remove legend name
  add_annotations(x = c(1/12, 1/6 + 1/12, 1/3 + 1/12, # using domain for x-axis
                        1/2 + 1/12, 2/3 + 1/12, 5/6 + 1/12),
                  y = df2$value,
                  text = df2$value,
                  xshift = 20,       # shift right 20 px
                  yshift = 15,       # shift up 15 px
                  hoverinfo = "skip",
                  bgcolor = "white",
                  bordercolor = "black",
                  xref = "paper", yref = "y", # cat x, use domain for annot x
                  showarrow = F)

After all of that, here's your plot.毕竟,这是你的情节。

在此处输入图像描述

在此处输入图像描述 在此处输入图像描述

This is straight plotly.这是直截了当的。 I think the labels would look a bit better with padding (which can be added).我认为带有填充(可以添加)的标签看起来会更好一些。

df_long %>% 
  filter(name != "cost") %>% 
  plot_ly(x = ~model, y = ~value, color = ~name, type = "bar", 
          customdata = ~name,  colors = c("blue", "gray"),
          hovertemplate = paste0("Model: %{x}<br>Value: %{y}<br>",
                                 "Name: %{customdata}<extra></extra>")) %>%
  add_lines(inherit = F, data = df, x = ~model, 
            y = ~cost, color = I("red"),
            name = "cost",
            hovertemplate = paste0("Model: %{x}<br>Value: %{y}<br>",
                                   "Name: cost<extra></extra>")) %>% 
  add_annotations(data = df, x = ~model, y = ~cost, text = ~cost,
                  bgcolor = "white", bordercolor = "black", 
                  xshift = 15, yshift = 15, showarrow = F) %>% 
  layout(barmode = "group")

Pretty much the same as the converted plot.与转换后的情节几乎相同。

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM