Is it possible to reproduce a meta-analysis type of flowchart as the one in the picture below using any R tool?
My attempt was using mermaid:
diagram = "
graph LR
subgraph Screening
b1-->b2
end
subgraph Eligibility
c1-->c2
end
subgraph Included
d1-->d2
end
subgraph Identification
a1-->a2
end
"
mermaid(diagram)
Which generated:
But I cannot find a way of connect the nodes accross the subgraphs.
Is there another tool better fitting to this kind of job? I am thinking on any package that I could use from within my Rmarkdown document.
I have found the DiagrammeR package easiest to do this. The general idea would be something like:
library(glue)
library(DiagrammeR)
excluded <- glue('Full text articles excluded
n = 1000
Reasons for exclusion
Reason 1
Reason 2')
grViz("
digraph cohort_flow_chart
{
node [fontname = Helvetica, fontsize = 12, shape = box, width = 4]
a[label = 'Records identified in original search']
b[label = 'Records identified with update']
c[label = 'Records after duplicates removed']
d[label = 'Records screened']
e[label = 'Records excluded']
f[label = 'Full text articles assessed']
g[label = 'Studies included']
h[label = '##1']
{ rank = same; a b}
{ rank = same; d, e}
{ rank = same; f, h}
a -> c;
b -> c;
c -> d;
d -> e [ minlen = 3 ];
d -> f;
f -> h [ minlen = 3 ];
f -> g;
}
[1]: excluded
")
Will look like:
Image with labels and empty nodes
grViz("
digraph cohort_flow_chart
{
node [fontname = Helvetica, fontsize = 12, shape = box, width = 4]
i[label = 'Identification', fillcolor = LightBlue,
style = filled, width = 2]
j[label = 'Screening',fillcolor = LightBlue, style = filled, width = 2]
k[label = 'Eligibility', fillcolor = LightBlue, style = filled,
width = 2]
l[label = 'Included', fillcolor = LightBlue, style = filled, width = 2]
a[label = 'Records identified in original search']
b[label = 'Records identified with update']
c[label = 'Records after duplicates removed']
d[label = 'Records screened']
e[label = 'Records excluded']
f[label = 'Full text articles assessed']
g[label = 'Studies included']
h[label = '##1']
blank_1[label = '', width = 0.01, height = 0.01]
blank_2[label = '', width = 0.01, height = 0.01]
blank_4[label = '', width = 4, color = White]
{ rank = same; a b i}
{ rank = same; blank_4 c j}
{ rank = same; f k}
{ rank = same; g l}
{ rank = same; blank_1 e}
{ rank = same; blank_2 h}
a -> c;
b -> c;
b -> blank_4 [ dir = none, color = White];
c -> d;
d -> blank_1 [ dir = none ];
blank_1 -> e [ minlen = 3 ];
blank_1 -> f;
f -> blank_2 [ dir = none ];
blank_2 -> h [ minlen = 3 ];
blank_2 -> g;
}
[1]: excluded
")
Related
I am using DiagrammeR/grViz in R Studio to make a flow chart from left to right. I have included the R code below. This works fine but I would like to align Block 1 to Block 6 with the top so that they are flush at the top.
Any ideas or links to help would be appreciated.
library(DiagrammeR)
grViz("
digraph boxes_and_circles {
graph[rankdir = LR]
graph [overlap = false, fontsize = 10]
node[shape = rectangle, style = filled, style = rounded]
subgraph cluster_0 {
label = 'BLOCK 1'
node [shape = box,
fixedsize = true,
height = 0.7,
width = 1.2,
]
CS1[label = '1A'];
CS2[label = '1B'];
CS3[label = '1C'];
}
subgraph cluster_1 {
label = 'BLOCK 2'
node [shape = circle,
fixedsize = true,
width = 1.2,
] // sets as circles
CR1[label = '2A'];
CR2[label = '2B'];
}
subgraph cluster_3 {
label = 'BLOCK 4'
node [shape = box,
fixedsize = true,
height = 0.7,
width = 1.2,
]
RM1; RM2;
RM1[label = '4A'];
RM2[label = '4B'];
}
subgraph cluster_5 {
label = 'BLOCK 6'
node [shape = box,
fixedsize = true,
height = 0.7,
width = 1.2,
]
R1[label = '6A'];
R2[label = '6B'];
R3[label = '6C'];
}
CS1->CR1->RM1->R1
CS1-> R1
CS2->CR2->RM2->R1
CS1->CR2
CS3-> R3
}
")
Using the forceNetwork function of the networkD3 package, it is possible to create an interactive network graph that can show the node names when hovering over them.
I am trying to create a graph that not only shows the node where the mouse is hovering over, but also all neighboring nodes, i.e. all nodes that are directly connected to the selected node. However, it should not show any nodes that are not directly connected to the node.
Although I found the argument opacityNoHover, it will affect all the nodes that the mouse is not covering and not just the nodes with a direct connection.
library(networkD3)
# example data
data(MisLinks)
data(MisNodes)
# creating the plot
forceNetwork(Links = MisLinks, Nodes = MisNodes,
Source = "source", Target = "target",
Value = "value", NodeID = "name",
Group = "group", opacity = 1, fontSize = 15,
opacityNoHover = 0)
You could re-write the mouseover and mouseout functions and override them with htmlwidgets::onRender...
library(networkD3)
library(htmlwidgets)
data(MisLinks)
data(MisNodes)
fn <- forceNetwork(Links = MisLinks, Nodes = MisNodes, Source = "source",
Target = "target", Value = "value", NodeID = "name",
Group = "group", opacity = 1, fontSize = 15,
opacityNoHover = 0)
customJS <- '
function(el,x) {
var link = d3.selectAll(".link")
var node = d3.selectAll(".node")
var options = { opacity: 1,
clickTextSize: 10,
opacityNoHover: 0.1,
radiusCalculation: "Math.sqrt(d.nodesize)+6"
}
var unfocusDivisor = 4;
var links = HTMLWidgets.dataframeToD3(x.links);
var linkedByIndex = {};
links.forEach(function(d) {
linkedByIndex[d.source + "," + d.target] = 1;
linkedByIndex[d.target + "," + d.source] = 1;
});
function neighboring(a, b) {
return linkedByIndex[a.index + "," + b.index];
}
function nodeSize(d) {
if(options.nodesize){
return eval(options.radiusCalculation);
}else{
return 6}
}
function mouseover(d) {
var unfocusDivisor = 4;
link.transition().duration(200)
.style("opacity", function(l) { return d != l.source && d != l.target ? +options.opacity / unfocusDivisor : +options.opacity });
node.transition().duration(200)
.style("opacity", function(o) { return d.index == o.index || neighboring(d, o) ? +options.opacity : +options.opacity / unfocusDivisor; });
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", function(d){return nodeSize(d)+5;});
node.select("text").transition()
.duration(750)
.attr("x", 13)
.style("stroke-width", ".5px")
.style("font", 24 + "px ")
.style("opacity", function(o) { return d.index == o.index || neighboring(d, o) ? 1 : 0; });
}
function mouseout() {
node.style("opacity", +options.opacity);
link.style("opacity", +options.opacity);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", function(d){return nodeSize(d);});
node.select("text").transition()
.duration(1250)
.attr("x", 0)
.style("font", options.fontSize + "px ")
.style("opacity", 0);
}
d3.selectAll(".node").on("mouseover", mouseover).on("mouseout", mouseout);
}
'
onRender(fn, customJS)
Using code from a previous post I was able to add a search bar that highlights specific points on a scatter plot in plotly using R, which worked well in 2 dimensions. However, I have now produced a 3 dimensional plot with the same data and the code for the search bar no longer works. Is it possible to have a search bar in a 3 dimensional plot, and if so is there a way to alter the following code to achieve that?
p <- plot_ly(carsDf, x = ~Comp.1 , y = ~Comp.2, text = rownames(carsDf),
mode = "markers", color = ~cluster_name, marker = list(size = 11), type = 'scatter', mode = 'markers')
p <- htmlwidgets::appendContent(p, htmltools::tags$input(id='inputText', value='Merc', ''), htmltools::tags$button(id='buttonSearch', 'Search'))
p <- htmlwidgets::appendContent(p, htmltools::tags$script(HTML(
'document.getElementById("buttonSearch").addEventListener("click", function()
{
var i = 0;
var j = 0;
var found = [];
var myDiv = document.getElementsByClassName("js-plotly-plot")[0]
var data = JSON.parse(document.querySelectorAll("script[type=\'application/json\']")[0].innerHTML);
for (i = 0 ;i < data.x.data.length; i += 1) {
for (j = 0; j < data.x.data[i].text.length; j += 1) {
if (data.x.data[i].text[j].indexOf(document.getElementById("inputText").value) !== -1) {
found.push({curveNumber: i, pointNumber: j});
}
}
}
Plotly.Fx.hover(myDiv, found);
}
);')))
htmlwidgets::saveWidget(p, paste('pca', ".html", sep=""))
p
Thanks
Here is the general idea, in practice I'd like to feasibly execute list of [alpha, beta, gamma ... etc] with an arbitrary number of items for each of the subsequent else if statement.
if (v == n(r)[alpha]) {
inc(c)
v = sample(c(names(r)), 1, replace = FALSE, prob = p[alpha,])
new = v
if (new == n(r)[ori])
{
inc(c)
dis = b+c
av = c(av,dis)
}
else if (v == names(r)[beta])
{
inc(b)
v = sample(c(n(r)), 1, replace = FALSE, prob = p[beta,])
new = v
if (new == n(r)[ori])
{
inc(b)
dis = b+c
av = c(av,dis)
}
else if (v == names(r)[gamma]
....
I have a table which looks like this:
table =
{
{
id = 1,
name = 'john',
png = 'john.png',
descr = "..."
},
{
id = 2,
name = 'sam',
png = "sam.png",
descr = "..."
}
...
}
What function could I use to display each picture like this and make them buttons
so that when I click on their image I can open their info.
This is where I am stuck:
local buttons = display.newGroup()
local xpos = -20
local ypos = 0
local e = -1
function addpicture ()
for i=1, #table do
xpos = (xpos + 100) % 300
e = e + 1
ypos = math.modf((e)*1/3) * 100 + 100
local c = display.newImage( table[i].name, system.TemporaryDirectory, xpos, ypos)
c:scale( 0.4, 0.4 )
c.name = table[i].tvname
buttons:insert(c)
end
end
function buttons:touch( event )
if event.phase == "began" then
print(self, event.id)
end
end
buttons:addEventListener('touch', buttons)
addpicture()
How can I recognize which image is touched in order to go back to the persons info?
I solved my problem by adding the listener inside of the loop like this:
function addpicture ()
for i=1, #table do
xpos = (xpos + 100) % 300
e = e + 1
ypos = math.modf((e)*1/3) * 100 + 100
local c = display.newImage( table[i].name, system.TemporaryDirectory, xpos, ypos)
c:scale( 0.4, 0.4 )
c.name = table[i].tvname
buttons:insert(c)
function c:touch( event )
if event.phase == "began" then
print(self, event.id)
end
end
c:addEventListener('touch', c)
end
end
addpicture()