简体   繁体   English

修复图表上混乱的标题

[英]Fixing Cluttered Titles on Graphs

I made the following 25.network graphs (all of these graphs are copies for simplicity - in reality, they will all be different):我制作了以下 25.network 图(为简单起见,所有这些图都是副本 - 实际上,它们都是不同的):

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

I would like to "tile" them as 5 x 5: Since these are interactive html plots - I used the following command:我想将它们“平铺”为 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")

I found out how to add a zoom option for each individual graph:我发现了如何为每个单独的图表添加缩放选项:

 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")

[![enter image description here][1]][1] [![在此处输入图片描述][1]][1]

But now the "zoom" options and "titles" have "cluttered" all the graphs!但是现在“缩放”选项和“标题”已经“弄乱”了所有图表!

I was thinking it might be better to "stack" all these graphs on top of each other and save each graph as a "group type" - and then hide/unhide as we please:我在想将所有这些图表“堆叠”在一起并将每个图表保存为“组类型”可能会更好 - 然后根据需要隐藏/取消隐藏:

visNetwork(data, relations) %>% 
 visOptions(selectedBy = "group")
  • Can we put all 25 graphs on one page and then "zoom" into each individual graph to view it better (eg have only one set of zoom/navigation buttons in the corner of the screen that works for all graphs)?我们能否将所有 25 个图表放在一页上,然后“放大”每个单独的图表以更好地查看它(例如,在屏幕的角落只有一组缩放/导航按钮适用于所有图表)?

  • Is there a way to stop the titles from overlapping with the graphs?有没有办法阻止标题与图表重叠?

  • Can we put all 25 graphs on one page and then "hide" individual graphs by "checking" an option menu button?我们能否将所有 25 个图表放在一页上,然后通过“选中”选项菜单按钮来“隐藏”各个图表? (like the last example on this page: https://datastorm-open.github.io/visNetwork/options.html ) (如本页最后一个示例: https://datastorm-open.github.io/visNetwork/options.html

Here are the possible solutions I have thought of for this problem:以下是我为这个问题想到的可能的解决方案:

  • Option 1: (a single zoom/navigation option for all graphs and no cluttered labels)选项 1:(所有图形的单一缩放/导航选项,没有杂乱的标签)

  • Option 2: (In the future, each "trip" will be different - "trips" will contain the same nodes, but have different edge connections and different titles/subtitles.)选项 2:(将来,每个“行程”都会不同——“行程”将包含相同的节点,但具有不同的边连接和不同的标题/副标题。)

I know that this style of selection ("Option 2") can be made using the following code:我知道可以使用以下代码进行这种选择(“选项 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")

But I am not sure how to adapt the above code for a pre-existing set of "visNetwork" graphs.但是我不确定如何将上面的代码改编为一组预先存在的“visNetwork”图。 For example, suppose I already have "visNetwork" graphs "a, b, c, d, e" - how can I "stack them on top of each other" and "shuffle through them" with a "select menu" like in the above code?例如,假设我已经有了“visNetwork”图“a、b、c、d、e”——我如何“将它们堆叠在一起”并使用“选择菜单”“在它们之间随机播放”,就像在以上代码?

[![enter image description here][4]][4] [![在此处输入图片描述][4]][4]

Can someone please show me a way of addressing this clutter problem using Option 1 and Option 2?有人可以告诉我使用选项 1 和选项 2 解决这个混乱问题的方法吗?

Thank you!谢谢!

While my solution isn't exactly what you describe under Option 2 , it is close.虽然我的解决方案与您在Option 2下描述的不完全一样,但它很接近。 We use combineWidgets() to create a grid with a single column and a row height where one graph covers most of the screen height.我们使用combineWidgets()创建一个具有单列和行高的网格,其中一个图形覆盖大部分屏幕高度。 We squeeze in a link between each widget instance that scrolls the browser window down to show the following graph when clicked.我们在每个小部件实例之间插入一个链接,该链接会向下滚动浏览器 window 以在单击时显示下图。

Let me know if this is working for you.如果这对您有用,请告诉我。 It should be possible to automatically adjust the row size according to the browser window size.应该可以根据浏览器window大小自动调整行大小。 Currently, this depends on the browser window height being around 1000px.目前,这取决于浏览器 window 高度在 1000px 左右。

I modified your code for the graph creation slightly and wrapped it in a function. This allows us to create 25 different-looking graphs easily.我稍微修改了您的图形创建代码并将其包装在 function 中。这使我们能够轻松创建 25 个不同外观的图形。 This way testing the resulting HTML file is more fun!这种方式测试生成的 HTML 文件更有趣! What follows the function definition is the code to create a list of HTML objects that we then feed into combineWidgets() . function 定义之后是创建 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")

If you want to have 5.network maps per row the code gets a bit more complex and it also might lead to a situation where the user might have to do horizontal scrolling in order to see everything, which is something you usually want to avoid when creating HTML pages.如果你想每行有 5.network 地图,代码会变得有点复杂,它也可能导致用户可能必须进行水平滚动才能看到所有内容的情况,这是你通常希望避免的情况创建 HTML 页。 Here is the code for a 5 maps per row solution:这是每行 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")

In general I'd recommend you play around with the height and width , ncol and nrow arguments of combineWidgets() to achieve a satisfying solution.一般来说,我建议您尝试使用combineWidgets()heightwidthncolnrow arguments 以获得令人满意的解决方案。 My strategy when building this was to first create a grid without the scroll link and add that in, after getting the grid right.我在构建它时的策略是首先创建一个没有滚动链接的网格,然后在正确设置网格后添加它。

The sizing works, but at first glance, it looks like it doesn't.尺码有效,但乍一看,似乎无效。 It's not ready, though.不过,它还没有准备好。

When you select options, it doesn't trigger the auto-resize functionality within the canvases.当您使用 select 选项时,它不会触发画布内的自动调整大小功能。

The auto-resize of the graph objects works just fine.图形对象的自动调整大小工作得很好。 (You'll see in the gif.) (你会在 gif 中看到。)

The Viewer pane in RStudio is not the best way to check the knitted file. RStudio 中的查看器窗格不是检查编织文件的最佳方式。 Look at it in a browser after knitting...especially if you want to make changes.编织后在浏览器中查看它......特别是如果你想进行更改。 It appears as if sometimes it thinks that all of RStudio is the container size, and you get graphs running off the screen.似乎有时它认为所有 RStudio 都是容器大小,并且您会在屏幕上运行图形。 I'm sure it's how I have it coded, but that doesn't appear to be an issue in Safari or Chrome (I didn't check the other browsers).我确定这是我的编码方式,但这在 Safari 或 Chrome 中似乎不是问题(我没有检查其他浏览器)。

I have tried to trigger the resizing of the canvas many different ways.我尝试以多种不同方式触发 canvas 的大小调整。 This code may have some redundancies from attempts to trigger a resize/zoom extent of the canvases.此代码可能因尝试触发画布的调整大小/缩放范围而存在一些冗余。 (I think I deleted all of the things that didn't work.) Perhaps with this, someone else can figure that part out. (我想我删除了所有不起作用的东西。)也许有了这个,其他人可以弄清楚那部分。

I used some Shiny code, but this is not using a Shiny runtime.我使用了一些 Shiny 代码,但这没有使用 Shiny 运行时。 Essentially the static work is R, but dynamic elements cannot be in R (ie, resizing events, reading selections, etc.).本质上 static 作品是 R,但动态元素不能在 R(即调整大小事件、阅读选择等)。

In the libraries I used, I called shinyRPG .在我使用的库中,我调用shinyRPG I added and commented out package installation code because that package isn't a Cran package. (It's on Github.)我添加并注释掉了 package 安装代码,因为 package 不是 Cran package。(它在 Github 上。)

Assumptions I've made in coding (and this answer):我在编码中所做的假设(和这个答案):

  • You have working knowledge of Rmarkdown.您具有 Rmarkdown 的应用知识。
  • There are 25 of these.network diagrams.这些网络图共有 25 张。
  • There are no other HTML widgets in the script.脚本中没有其他 HTML 小部件。

If these are not true, let me know.如果这些不是真的,请告诉我。

The YAML YAML

The Output Options Output 选项

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

The Styles Styles

This code goes between the YAML and the first R code chunk.此代码介于 YAML 和第一个 R 代码块之间。 In the regular text area of the RMD–not in an R chunk.在 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>

Libraries图书馆

The first R chunk is next.接下来是第一个 R 块。 You don't have to set echo = F in flexdashboard .您不必在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 Code to Create the Diagrams R 创建图表的代码

This next part is essentially your code.下一部分本质上是您的代码。 I changed a few things in the final version of the call to create the vizNetwork .我在创建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

```

The Multi-Select Box多选框

Between the last chunk and before the next chunk of code is where this next part goes.在最后一个代码块之间和下一个代码块之前是下一部分的位置。 This creates the left column, where the multi-select box is.这将创建左列,多选框所在的位置。 (This is not in a code chunk.) (这不在代码块中。)

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

### Select Options

You can select one or more options from the list. 

No to build the select box and append the function that will trigger changes.否构建 select 框和 append 将触发更改的 function。 This part will require modification.这部分将需要修改。 Name the options that the user sees on the screen here.在此处命名用户在屏幕上看到的选项。 ( letters[1:25] in this code.) (此代码中的letters[1:25] 。)

Your object names do not have to match the names you have here.您的 object 名称不必与您在此处的名称相匹配。 They do need to be in the same order, though.不过,它们确实需要以相同的顺序排列。

```{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

```

The Network Diagrams网络图

Then between the previous chunk and the next chunk (not in a chunk):然后在前一个块和下一个块之间(不在一个块中):

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

<div class="containIt">

Now call your graphs.现在调用你的图表。

```{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

```

Close the div tag after that chunk:关闭该块之后的 div 标签:

</div>

Final Chunk: Javascript最后一块:Javascript

This started out nice and neat...but after a lot of trial and error–WYSIWYG.这开始很好很整洁......但经过大量的试验和错误 - 所见即所得。 Effective commenting fizzled out somewhere along the way, too.在此过程中,有效的评论也逐渐消失了。 If there are questions as to what does what, let me know.如果对什么做什么有疑问,请告诉我。

This chunk won't do anything if you run the chunk in R Markdown (while in the Source pane).如果您在 R Markdown 中运行该块(在“源”窗格中),则该块不会执行任何操作。 To execute JS, you have to knit .要执行 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); 
}

```

Developer Tools Console开发者工具控制台

If you go to the developer tools console, you will be able to see how many and which options are selected as the selections are made.如果您 go 到开发人员工具控制台,您将能够在进行选择时看到选择了多少个选项以及选择了哪些选项。 That way, if there is something odd like reverse order (which I suspect but couldn't validate), you'll see what is or isn't happening as you might have expected.这样,如果有一些奇怪的事情,比如倒序(我怀疑但无法验证),你会看到你可能预期的发生了什么或没有发生什么。 Where ever you see console.log , that is sending a message to the console, so you can watch what's happening.无论你在哪里看到console.log ,它都会向控制台发送一条消息,这样你就可以看到发生了什么。

Dashboard Colors仪表盘 Colors

If there are any colors, custom or otherwise you would like in the background, let me know.如果后台有任何 colors、自定义或其他您想要的,请告诉我。 I can help with that part, as well.我也可以在这方面提供帮助。 Right now, the colors of the dashboard are the default colors.目前dashboard的colors默认为colors。

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

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