【问题标题】:Fixing Cluttered Titles on Graphs修复图表上杂乱的标题
【发布时间】:2022-07-04 14:03:05
【问题描述】:

我制作了以下 25 个网络图(为简单起见,所有这些图都是副本 - 实际上,它们都会有所不同):

library(tidyverse)
library(igraph)


set.seed(123)
n=15
data = data.frame(tibble(d = paste(1:n)))

relations = data.frame(tibble(
  from = sample(data$d),
  to = lead(from, default=from[1]),
))

data$name = c("new york", "chicago", "los angeles", "orlando", "houston", "seattle", "washington", "baltimore", "atlanta", "las vegas", "oakland", "phoenix", "kansas", "miami", "newark" )

graph = graph_from_data_frame(relations, directed=T, vertices = data) 

V(graph)$color <- ifelse(data$d == relations$from[1], "red", "orange")

plot(graph, layout=layout.circle, edge.arrow.size = 0.2, main = "my_graph")

library(visNetwork)

    a = visIgraph(graph)  

m_1 = 1
m_2 = 23.6

 a = toVisNetworkData(graph) %>%
    c(., list(main = paste0("Trip ", m_1, " : "), submain = paste0 (m_2, "KM") )) %>%
    do.call(visNetwork, .) %>%
    visIgraphLayout(layout = "layout_in_circle") %>% 
    visEdges(arrows = 'to') 



y = x = w = v = u = t = s = r = q  = p = o = n = m = l = k = j = i = h = g = f = e = d = c = b = a

我想将它们“平铺”为 5 x 5:因为这些是交互式 html 图 - 我使用了以下命令:

library(manipulateWidget)
library(htmltools)

ff = combineWidgets(y , x , w , v , u , t , s , r , q  , p , o , n , m , l , k , j , i , h , g , f , e , d , c , b , a)

htmltools::save_html(html = ff, file = "widgets.html")

我发现了如何为每个单独的图表添加缩放选项:

 a = toVisNetworkData(graph) %>%
    c(., list(main = paste0("Trip ", m_1, " : "), submain = paste0 (m_2, "KM") )) %>%
    do.call(visNetwork, .) %>%
    visIgraphLayout(layout = "layout_in_circle") %>%  
    visInteraction(navigationButtons = TRUE) %>% 
    visEdges(arrows = 'to') 

y = x = w = v = u = t = s = r = q  = p = o = n = m = l = k = j = i = h = g = f = e = d = c = b = a

ff = combineWidgets(y , x , w , v , u , t , s , r , q  , p , o , n , m , l , k , j , i , h , g , f , e , d , c , b , a)

htmltools::save_html(html = ff, file = "widgets.html")

[![在此处输入图片描述][1]][1]

但是现在“缩放”选项和“标题”已经“混乱”了所有图表!

我在想最好将所有这些图表“堆叠”在一起并将每个图表保存为“组类型” - 然后随意隐藏/取消隐藏:

visNetwork(data, relations) %>% 
 visOptions(selectedBy = "group")
  • 我们能否将所有 25 个图表放在一个页面上,然后“缩放”到每个单独的图表以更好地查看它(例如,在屏幕一角只有一组缩放/导航按钮适用于所有图表)?

  • 有没有办法阻止标题与图表重叠?

  • 我们能否将所有 25 个图表放在一个页面上,然后通过“选中”选项菜单按钮来“隐藏”各个图表? (如本页最后一个示例:https://datastorm-open.github.io/visNetwork/options.html

以下是我为这个问题想到的可能的解决方案:

  • 选项 1:(所有图表的单一缩放/导航选项,没有杂乱的标签)

  • 选项 2:(将来,每个“行程”都会有所不同——“行程”将包含相同的节点,但具有不同的边连接和不同的标题/字幕。)

我知道可以使用以下代码进行这种选择方式(“选项 2”):

nodes <- data.frame(id = 1:15, label = paste("Label", 1:15),
 group = sample(LETTERS[1:3], 15, replace = TRUE))

edges <- data.frame(from = trunc(runif(15)*(15-1))+1,
 to = trunc(runif(15)*(15-1))+1)



visNetwork(nodes, edges) %>% 
    visOptions(selectedBy = "group")

但我不确定如何将上述代码调整为一组预先存在的“visNetwork”图。例如,假设我已经有“visNetwork”图“a、b、c、d、e” - 我如何使用“选择菜单”“将它们堆叠在一起”和“随机播放”上面的代码?

[![在此处输入图片描述][4]][4]

有人可以告诉我使用选项 1 和选项 2 解决这个混乱问题的方法吗?

谢谢!

【问题讨论】:

  • 感谢您编辑 ThomasIsCoding!
  • 我很好奇您是否愿意使用仪表板之类的东西?我认为这会给你更多的灵活性。闪亮是另一种选择。最终渲染将占用多少空间?我可以让我的查看器尽可能大,但这并不能告诉我你将如何使用它。
  • 仪表板绝对最好用 HTML 呈现。是和是(对于选项)。我将使用仪表板制定解决方案。
  • 我在考虑 RMarkdown 和 Flexdashboard。不过,那里有很多很棒的选择。如果你没有经常使用 RMarkdown,它是一种全新的动物。事实上,您可以在同一个脚本文件中使用多种语言进行编程……如果您问我,那真是太神奇了!
  • 很抱歉,我看到你的答案很好,没有进一步看。我可以添加我的答案。我会完成它并将其添加到问题中。

标签: r data-visualization igraph visnetwork


【解决方案1】:

虽然我的解决方案与您在Option 2 下描述的不完全一样,但它很接近。我们使用combineWidgets() 创建一个具有单列和行高的网格,其中一个图形覆盖了大部分屏幕高度。我们在每个小部件实例之间插入一个链接,该链接向下滚动浏览器窗口以在单击时显示下图。

让我知道这是否适合您。应该可以根据浏览器窗口大小自动调整行大小。目前,这取决于浏览器窗口高度约为 1000 像素。

我稍微修改了您的代码以创建图形并将其包装在一个函数中。这使我们能够轻松创建 25 个外观不同的图表。这种方式测试生成的 HTML 文件更有趣!函数定义之后是用于创建 HTML 对象的list 的代码,然后我们将其输入combineWidgets()

library(visNetwork)
library(tidyverse)
library(igraph)
library(manipulateWidget)
library(htmltools)

create_trip_graph <-
  function(x, distance = NULL) {
    n <- 15
    data <- tibble(d = 1:n,
                   name =
                     c(
                       "new york",
                       "chicago",
                       "los angeles",
                       "orlando",
                       "houston",
                       "seattle",
                       "washington",
                       "baltimore",
                       "atlanta",
                       "las vegas",
                       "oakland",
                       "phoenix",
                       "kansas",
                       "miami",
                       "newark"
                     ))
    
    relations <-  tibble(from = sample(data$d),
                         to = lead(from, default = from[1]))    
    graph <-
      graph_from_data_frame(relations, directed = TRUE, vertices = data)
    
    V(graph)$color <-
      ifelse(data$d == relations$from[1], "red", "orange")
    
    if (is.null(distance))
      # This generates a random distance value if none is 
      # specified in the function call. Values are just for 
      # demonstration, no actual distances are calculated.
      distance <- sample(seq(19, 25, .1), 1)
    
    toVisNetworkData(graph) %>%
      c(., list(
        main = paste0("Trip ", x, " : "),
        submain = paste0(distance, "KM")
      )) %>%
      do.call(visNetwork, .) %>%
      visIgraphLayout(layout = "layout_in_circle") %>%
      visInteraction(navigationButtons = TRUE) %>%
      visEdges(arrows = 'to')
  }

comb_vgraphs <- lapply(1:25, function (x) list(
  create_trip_graph(x),
  htmltools::a("NEXT TRIP", 
               onclick = 'window.scrollBy(0,950)', 
               style = 'color:blue; text-decoration:underline;')))  %>%
  unlist(recursive = FALSE)


ff <-
  combineWidgets(
    list = comb_vgraphs,
    ncol = 1,
    height = 25 * 950,
    rowsize = c(24, 1)
  )

htmltools::save_html(html = ff, file = "widgets.html")

如果您希望每行有 5 个网络地图,则代码会变得有点复杂,并且还可能导致用户可能必须进行水平滚动才能看到所有内容的情况,这是您通常想要的在创建 HTML 页面时避免。这是每行 5 个地图解决方案的代码:

comb_vgraphs2 <- lapply(1:25, function(x) {
  a <- list(create_trip_graph(x))
  # We detect whenever we are creating the 5th, 10th, 15th etc. network map
  # and add the link after that one.
  if (x %% 5 == 0 & x < 25) a[[2]] <- htmltools::a("NEXT 5 TRIPS", 
                                          onclick = 'window.scrollBy(0,500)', 
                                          style = 'color:blue; text-decoration:underline;')
  a
}) %>%
  unlist(recursive = FALSE)

ff2 <-
  combineWidgets(
    list = comb_vgraphs2,
    ncol = 6, # We need six columns, 5 for the network maps 
              # and 1 for the link to scroll the page.
    height = 6 * 500,
    width = 1700
    #rowsize = c(24, 1)
  )

# We need to add some white space in for the scrolling by clicking the link to 
# still work for the last row.
ff2$widgets[[length(ff2$widgets) + 1]] <- htmltools::div(style = "height: 1000px;")

htmltools::save_html(html = ff2, file = "widgets2.html")

一般来说,我建议您使用combineWidgets()heightwidthncolnrow 参数来获得令人满意的解决方案。我在构建它时的策略是首先创建一个没有滚动链接的网格,然后在正确设置网格后添加它。

【讨论】:

  • 感谢您的回答!我尝试运行您的代码,但无法通过“comb_vgraphs()”部分:
  • comb_vgraphs
  • 这是我的会话信息的一部分: sessionInfo() R 版本 4.0.3 (2020-10-10) 平台:x86_64-w64-mingw32/x64 (64-bit) 运行条件:Windows 10 x64(构建 22000)
  • 抱歉,我的解决方案是使用匿名函数简写和基本 R 管道 |&gt;,两者都在 R 4.1.0 中引入。我编辑了我的答案以与以前的 R 版本兼容。
  • 非常感谢!这太酷了!!有没有可能把这 25 个图每行放 5 个?
【解决方案2】:

尺寸调整有效,但乍一看,它似乎没有。不过,它还没有准备好。

当您选择选项时,它不会触发画布内的自动调整大小功能。

图形对象的自动调整大小可以正常工作。 (你会在 gif 中看到。)

RStudio 中的查看器窗格不是检查针织文件的最佳方式。编织后在浏览器中查看它……尤其是如果您想进行更改。似乎有时它认为所有 RStudio 都是容器大小,并且您会看到图形在屏幕外运行。我确定这是我编码的方式,但这在 Safari 或 Chrome 中似乎不是问题(我没有检查其他浏览器)。

我尝试了多种不同的方式来触发画布的大小调整。此代码可能会因尝试触发画布的调整大小/缩放范围而产生一些冗余。 (我想我删除了所有不起作用的东西。)也许有了这个,其他人可以解决这个问题。

我使用了一些闪亮的代码,但这不是使用闪亮的运行时。本质上,静态工作是 R,但动态元素不能在 R 中(即调整事件大小、读取选择等)。

在我使用的库中,我调用了shinyRPG。我添加并注释掉了包安装代码,因为该包不是 Cran 包。 (在 Github 上。)

我在编码中所做的假设(以及这个答案):

  • 您具有 Rmarkdown 的应用知识。
  • 这些网络图有 25 个。
  • 脚本中没有其他 HTML 小部件。

如果这些不正确,请告诉我。

YAML

输出选项

---
title: "Just for antonoyaro8"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
---

风格

此代码位于 YAML 和第一个 R 代码块之间。在 RMD 的常规文本区域中——而不是在 R 块中。

<style>
select {
  // A reset of styles, including removing the default dropdown arrow
  appearance: none;
  background-color: transparent;
  border: none;
  padding: 0 1em 0 0;
  margin: 0;
  width: 100%;
  font-family: inherit;
  font-size: inherit;
  cursor: inherit;
  line-height: inherit;
}
.select {
  display: grid;
  grid-template-areas: "select";
  align-items: center;
  position: relative;
  min-width: 15ch;
  max-width: 100ch;
  border: 1px solid var(--select-border);
  border-radius: 0.25em;
  padding: 0.25em 0.5em;
  font-size: 1.25rem;
  cursor: pointer;
  line-height: 1.1;
  background-color: #fff;
  background-image: linear-gradient(to top, #f9f9f9, #fff 33%);
}
select[multiple] {
  padding-right: 0; 
  /* Safari will not show options unless labels fit   */
  height: 50rem;   // how many options show at one time
  font-size: 1rem;
}
#column-1 > div.containIt > div.visNetwork canvas {
  width: 100%;
  height: 80%;
}
.containIt {
  display: flex;
  flex-flow: row wrap;
  flex-grow: 1;
  justify-content: space-around;
  align-items: flex-start;
  align-content: space-around;
  overflow: hidden;
  height: 100%;
  width: 100%;
  margin-top: 2vw;
  height: 80vh;
  widhth: 80vw;
  overflow: hidden;
}

</style>

接下来是第一个 R 块。您不必在flexdashboard 中设置echo = F

```{r setup, include=FALSE}

library(flexdashboard)
library(visNetwork)
library(htmltools)
library(igraph)
library(tidyverse)
library(shinyRPG) # remotes::install_github("RinteRface/shinyRPG")

```

创建图表的 R 代码

下一部分本质上是您的代码。我在调用的最终版本中更改了一些内容以创建 vizNetwork

```{r dataStuff}

set.seed(123)
n=15
data = data.frame(tibble(d = paste(1:n)))

relations = data.frame(tibble(
  from = sample(data$d),
  to = lead(from, default=from[1]),
))
data$name = c("new york", "chicago", "los angeles", "orlando", "houston", "seattle", "washington", "baltimore", "atlanta", "las vegas", "oakland", "phoenix", "kansas", "miami", "newark" )

graph = graph_from_data_frame(relations, directed=T, vertices = data) 

#red circle: starting point and final point
V(graph)$color <- ifelse(data$d == relations$from[1], "red", "orange")

a = visIgraph(graph)  

m_1 = 1
m_2 = 23.6

a = toVisNetworkData(graph) %>%
  c(., list(main = paste0("Trip ", m_1, " : "), 
            submain = paste0 (m_2, "KM") )) %>%
  do.call(visNetwork, .) %>%
  visIgraphLayout(layout = "layout_in_circle") %>% 
  visEdges(arrows = 'to')

# collect the correct order
df2 <- data %>% 
  mutate(d = as.numeric(d),
         nuname = factor(a$x$edges$from, 
                         levels = unlist(data$name))) %>%
  arrange(nuname) %>% 
  select(d) %>% unlist(use.names = F)
#  [1] 11  5  2  8  7  6 10 14 15  4 12  9 13  3  1 
V(graph)$name = data$label = paste0(df2, "\n", data$name)
a = visIgraph(graph)  

m_1 = 1
m_2 = 23.6
a = toVisNetworkData(graph) %>%
  c(., list(main = list(text = paste0("Trip ", m_1, " : "), 
                        style = "font-family: Georgia; font-size: 100%; font-weight: bold; text-align:center;"),
            submain = list(text = paste0(m_2, "KM"),
                           style = "font-family: Georgia; font-size: 100%; text-align:center;"))) %>%
  do.call(visNetwork, .) %>%
  visInteraction(navigationButtons = TRUE) %>%
  visIgraphLayout(layout = "layout_in_circle") %>% 
  visEdges(arrows = 'to') %>% 
  visOptions(width = "100%", height = "80%", autoResize = T)

a[["sizingPolicy"]][["knitr"]][["figure"]] <- FALSE

y = x = w = v = u = t = s = r = q  = p = o = n = m = l = k = j = i = h = g = f = e = d = c = b = a

```

多选框

在最后一个代码块和下一个代码块之间是下一部分的位置。这将创建多选框所在的左列。 (这不在代码块中。)

Column {data-width=200}
-----------------------------------------------------------------------

### Select Options

You can select one or more options from the list. 

否构建选择框并附加将触发更改的功能。这部分需要修改。 在此处命名用户在屏幕上看到的选项。(此代码中为letters[1:25]。)

您的对象名称不必必须与您在此处的名称相匹配。不过,它们确实需要按相同的顺序排列。

```{r selectiver}
tagSel <- rpgSelect(
  "selectBox",                      # don't change this (connected)
  "Selections:",                    # visible on HTML; change away or set to ""
  c(setNames(1:25, letters[1:25])), # left is values, right is labels
  multiple = T                      # all multiple selections
)        # other attributes controlled by css at the top

tagSel$attribs$class <- 'select select--multiple'       # connect styles
tagSel$children[[2]]$attribs$class <- "mutli-select"    # connect styles
tagSel$children[[2]]$attribs$onchange <- "getOps(this)" # connect the JS function

tagSel

```

网络图

然后在上一个chunk和下一个chunk之间(不在一个chunk中):

Column
-----------------------------------------------------------------------

<div class="containIt">

现在调用你的图表。

```{r notNow, include=T}

a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y

```

在该块之后关闭 div 标签:

</div>

最终块:Javascript

这开始时很好很整洁......但经过大量的试验和错误 - 所见即所得。 在此过程中,有效的评论也逐渐消失。如果有关于什么做什么的问题,请告诉我。

如果您在 R Markdown 中运行该块(在“源”窗格中),该块将不会做任何事情。要执行JS,你必须knit

```{r pickMe,results='asis',engine='js'}

//remove inherent knitr element-- after using mutlti-select starts harboring space
byeknit = document.querySelector('#column-1 > div.containIt > div.knitr-options');
byeknit.remove(1);

// Reset Sizing of Widgets
h = document.querySelector('#column-1 > div.containIt').clientHeight;
w = document.querySelector('#column-1 > div.containIt').clientWidth;
hw = h * w;

cont = document.querySelectorAll('#column-1 > div.containIt > div');

newHeight = Math.floor(Math.sqrt(hw/cont.length)) * .85;

for(i = 0; i < cont.length; ++i){
  cont[i].style.height = newHeight + 'px';
  cont[i].style.width = newHeight + 'px';
  cn = cont[i].childNodes;
  if(cn.length > 0){
      th = cn[0].clientHeight + cn[1].clientHeight;
      console.log("canvas found");
      mb = newheight - th;
      cn[5].style.height = mb + 'px'; //canvas control attempt
  }
}

function resizePlease(count) { //resize plots based on selections
  // screen may have resized**
  h = document.querySelector('#column-1 > div.containIt').clientHeight;
  w = document.querySelector('#column-1 > div.containIt').clientWidth;
  hw = h * w;  // get the area
  
  // based on selected count** these should fit--- 
  // RStudio!
  newHeight = Math.floor(Math.sqrt(hw/count)) * .85; 
  for(i = 0; i < graphy.length; ++i){
    graphy[i].style.height = newHeight + 'px';
    graphy[i].style.width = newHeight + 'px';
    gcn = graphy[i].childNodes;
    if(cn.length > 0){
        th = gcn[0].clientHeight + gcn[1].clientHeight;
        mb = newHeight - th;
        gcn[5].style.height = mb + 'px'; //canvas control attempt
        canYouPLEASElisten = graphy[i].querySelector('canvas');
        canYouPLEASElisten.style.height = mb + 'px'; //trigger zoom extent!!
        canYouPLEASElisten.style.height = '100%';
    }
  }
}


// Something selected triggers this function
function getOps(sel) {   
  //get ref to select list and display text box
  graphy = document.querySelectorAll('#column-1 div.visNetwork');
  count = 0; // reset count of selected vis
  // loop through selections
  for(i = 0; i < sel.length; i++) {
    opt = sel.options[i];
    if ( opt.selected ) {
      count++
      graphy[i].style.display = 'block';
      console.log(opt + "selected");
      console.log(count + " options selected");
    } else {
      graphy[i].style.display = 'none';
    }
  }
  resizePlease(count); 
}

```

开发者工具控制台

如果您转到开发人员工具控制台,您将能够看到在做出选择时选择了多少选项以及选择了哪些选项。这样,如果有一些奇怪的事情,比如逆序(我怀疑但无法验证),你会看到你可能预期的发生或没有发生的事情。无论您在哪里看到console.log,都会向控制台发送一条消息,以便您查看正在发生的事情。

仪表板颜色

如果背景中有任何颜色、自定义或其他您想要的颜色,请告诉我。我也可以在这部分提供帮助。目前,仪表板的颜色是默认颜色。

【讨论】:

  • @Kat: 谢谢你的回答,抱歉耽搁了!我自己痴迷地研究了这个问题……最后,我只是手动将单个图形复制/粘贴到 Microsoft Paint 中,然后手动调整它们并制作拼贴画。非常感谢您的帮助!我需要大约一年的时间才能理解理解您发布的所有代码所需的所有背景。非常感谢!
  • 我只是想如果我可以共享整个 RMD 文件会更容易......so ya, here it is.
猜你喜欢
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多