Is there a way to build dependent sliders with PlutoUI? - julia

Is there a way to build dependent sliders with PlutoUI.jl in which adjusting one will dynamically change the others?

Here is something that you can try:
using PlutoUI
a = #bind n1 PlutoUI.Slider(0:100)
b = #bind n2 PlutoUI.Slider(0:100, default=n1, show_value=true)
What happens with this is that whenever you change slider a, that causes b to be recreated (that's the way that Pluto works). The default setting is linked to the value of a so moving a causes b to appear to move. You can still re-adjust b to anything you like.
Note that you can't inter-link these two sliders because all cells in Pluto have an order of evaluation with no cycles.

You can simply display the slider multiple times in different cells. These are the same sliders, thus adjusting it in one cell will adjust it also in all other cells.
Example:
# ╔═╡ 84fc2e80-141d-11ed-272a-13a267f5233a
using PlutoUI
# ╔═╡ 2538ee5d-6bd0-48f4-a5d3-fd0084a6a136
a = #bind x Slider(1:10)
# ╔═╡ 50e6b255-26c8-40c9-a5e5-0d95df73d3e6
a
# ╔═╡ 43ccffd4-e721-42b8-b9d3-8cbffcbedec3
x
This is useful when you need the same UI element at multiple places in your notebook for didactic / usability purposes.

Related

How to add node size as legend in Cytoscape 3?

From an R function (cnetplot) I've obtained the following image which does not look very nice.
Therefore, I extracted the data from the R object and wrote a script to create an equivalent network data file that is readable by Cytoscape. The following equivalent plot from Cytoscape looks much better but the problem is that I am not able to add legends based on node size in Cytoscape as the R function did. I tried with Legend Creator app in cytoscspe but couldn't do it.
The original data and R code to reproduce the plots can be found in the following link.
ftp://ftp.lrz.de/transfer/Data_For_Plot/StackOverflow/
I looked into this Mapping nodes sizes and adding legends in cytoscape network, but in that case questioner already was able to load the node sizes as legends in cytoscape and moreover, he/she used a python package.
Any suggestions will highly be appreciated
Here's a little R script that will generate a min/max node size legend. You'll need to set the first variable to the name of the Visual Style in your network. This one works with the sample session file, "Yeast Perturbation.cys" if you want to test it there first.
If you are familiar with RCy3, then it should be self-explanatory. You can customize the positioning of the nodes, labels and label font size, etc. You can even adapt it to generate intermediate values (like in your example above) if you want.
NOTE: This adds nodes to your network. If you run a layout after adding these, then they will be moved! If you rely on node counts or connectivity measures, then these will affect those counts! Etc.
If you find this uesful, I might try to add it as helper function in the RCy3 package. Let me know if you have feedback or questions.
# https://bioconductor.org/packages/release/bioc/html/RCy3.html
library(RCy3)
# Set your current style name
style.name <- "galFiltered Style"
# Extract min and max node size
res<-cyrestGET(paste0("styles/",style.name,"/mappings/NODE_SIZE"))
size.col <- res$mappingColumn
min.size <- res$points[[1]]$equal
min.value <- res$points[[1]]$value
max.size <- res$points[[length(res$points)]]$equal
max.value <- res$points[[length(res$points)]]$value
# Prepare as data.frame
legend.df <-data.frame(c(min.size, max.size), c(min.value, max.value))
colnames(legend.df) <- c("legend.label",size.col)
rownames(legend.df) <- c("legend.size.min", "legend.size.max")
# Add legend nodes and data
addCyNodes(c("legend.size.min", "legend.size.max"))
loadTableData(legend.df)
# Style and position
setNodeColorBypass(c("legend.size.min", "legend.size.max"),"#000000")
setNodePropertyBypass(c("legend.size.min", "legend.size.max"),
c("E,W,l,5,0", "E,W,l,5,0"), # node_anchor, label_anchor, justification, x-offset, y-offset
"NODE_LABEL_POSITION")
setNodeLabelBypass(c("legend.size.min", "legend.size.max"), legend.df$legend.label)
setNodePropertyBypass("legend.size.max",
as.numeric(max.size)/2 + as.numeric(min.size)/2 + 10, # vertical spacing
"NODE_Y_LOCATION")
setNodeFontSizeBypass(c("legend.size.min", "legend.size.max"), c(20,20))

How to update a Julia plot?

When updating a figure in Julia, how to do it without the plot window grabbing the focus?
Let's say I have the following code:
using Plots
pyplot()
n = 100
x = collect(range(0, pi, length = n))
for i = 1:30
y = sin.(x) .+ 0.1 * randn(100)
plot(x, y, show=true)
sleep(0)
end
When run, the window that displays the plot will grab the focus every time the plot is updated, preventing me from doing anything useful.
How can I update the plot without the window being activated? This would be used for example for monitoring a program in the background.
The easy solution would be to open an empty figure window, arrange it on your desktop however the way you want and reuse it for the next plots. Reusing the same figure window is the default in Plots.jl. Here is how the solution looks.
using Plots
pyplot() # or another backend
plot() # this will open the plot window app and steal the focus once
# arrange the window however the way you want, put it in another monitor etc.
for i = 1:30
plot(rand(3,3), show=true, reuse=true) # reuse=true is not necessary since it is already the default
sleep(0.1)
end
Since the same application window will be used again, the plot window will no longer steal focus.
As far as I know, the very first window will steal the focus (I think this is not really an issue in your use case), since it is created by another application process. This is the default behavior in most desktop environments. Some desktop environments may allow to change this default.
As a side note, instead of a for loop to regularly update your plot, you can use Timer events in Julia, which makes things easier and likely to be more efficient.

Plotly Multi Column Horizontal Legend

I am trying to create horizontal bar chart in in R using the plotly package. Due to the length of the legend items I would like for them to show horizontally at the top or bottom of the visual in 2 columns. Is it possible to dictate the number of columns for the legend?
I've been able to place the legend below the x axis successfully using Layout(legend = list(orientation='h')) however regardless of where I put the legend (using the x and y arguments) it is always just one long list. I've seen a github project for creating a multi column legend in js but not r.
Thanks,
This is not possible in a normal way. I think it has its own logic that determines how many place there it is and how many columns it will display then.
So I guess if you make your plot width smaller you could reach the goal that it will just display 2 column.
Also you can try to play around with the margin attribute (https://plot.ly/r/reference/#layout-margin) by setting r and l to 10 e.g.
An other idea could be to make the font-size in legend (https://plot.ly/r/reference/#layout-legend-font-size) bigger, so that it just uses two columns. Hope it helps.
I read the same github page and I thought that it is not possible, but seems to be! I only checked in Python, but I hope this will help in your endeavors in R as well as everyone in Python looking for information. Sadly, there is not a lot of information on Plotly here compared to other packages.
This solved my problem
Setting orientation='h' is not enough. You also have to put the legend items in different legendgroups, if you want them in different columns. Here is an example with legend labels:
fig = go.Figure([
go.Scatter(x=best_neurons_df['Test Size'],
y=best_neurons_df['Training Accuracy Max'],
# You can write anything as the group name, as long as it's different.
legendgroup="group2",
name='Training',
mode='markers',
go.Scatter(x=best_neurons_df['Test Size'],
y=best_neurons_df['Validation Accuracy Max'],
# You can write anything as the group name, as long as it's different.
legendgroup="group1",
layout=dict(title='Best Model Dependency on Validation Split',
xaxis=dict(title='Validation Set proportion'),
yaxis=dict(title='Accuracy'),
margin=dict(b=100, t=100, l=0, r=0),
legend=dict(x=1, y=1.01,xanchor='right', yanchor='bottom',
title='',
orientation='h', # Remember this as well.
bordercolor='black',
borderwidth=1
))
Example image

layout inside layout in R

I'm using R to create a heatmap from a matrix using heatmap.2 - and i want to group these images into one big image - What i usually use to achieve this is layout() - but this doesn't work, as heatmap.2 uses layout, and apparently layout does not work recursively.
Does anyone have any suggestions on how to group together 2 images without layout, or how to make layout support recursive calls?
mat = matrix(nrow=3,nrow=3,1:9)
layout(matrix(nrow=2,ncol=1))
heatmap.2(mat) ## overrides the layout and produces only one plot that takes whole screen
heatmap.2(mat) ## still only one image
thanks.
What follows is a hack that is almost certainly not a perfect solution, but it may get you started.
Create your own version of the heatmap.2 function called hm3. In the code for hm3, comment out all the lines between:
if (missing(lhei) || is.null(lhei))
and the layout call:
layout(lmat, widths = lwid, heights = lhei, respect = FALSE)
it's a big chunk of code, maybe 30 lines. Now the following code produces two heat maps with dendrograms and keys side by side:
x <- as.matrix(mtcars)
lhei <- c(1.5, 4,1.5,4)
lwid <- c(1.5, 4,1.5,4)
layout(rbind(c(4,3,8,7),c(2,1,6,5)),
widths = lwid, heights = lhei, respect = FALSE)
hm3(x)
hm3(x)
Clearly, this will require considerable tweaks to make it look nice (and a larger plotting area; I've squished everything to be a reasonable size to post here).
This is entirely untested. It is likely that using any of the options in the hm3 function that control the appearance of the plot will cause things to go slightly haywire. But this may be a good starting point for your own experimentation to address those issues.
What are you planning on doing with the results?
If you just want to compare 2 heatmaps side by side on the screen then rather than combine them into one single plot you can open 2 plotting devices and arrange them side by side to compare (much simpler than creating a single graph):
heatmap.2(mat1)
dev.new()
heatmap.2(mat2)
Now drag one to the side of the other using your mouse.
If you want to include the combined graphic in a publication then it may be easiest to create the 2 plots and just set them side by side in whatever program you are using to create the article. If you need them in one file you can still save the 2 heatmaps (or other plots) as 2 files then use tools such as imagemagick, gimp, or inkscape to combine the 2 files into 1 with the graphs side by side.

Plot to specific plot in multiple-plot window?

If I create a multi-plot window with par(mfrow=...), is it possible to send data to a specific plot (i.e. "the one in the lower left corner") or is the plotting always necessarily sequential? Is there a package for R that does something like this?
For those that are interested, this problem arises out of the fact that R is a single-threaded application and is not ideal for real-time visualization. I have multiple real-time data streams coming into R from an outside source that produces the data asynchronously (and therefore the data streams don't always come in the same order). This results in R flipping around the order of the data visualization plots every time it updates.
You could use split.screen():
par(bg = "white") # erase.screen() will appear not to work
# if the background color is transparent
# (as it is by default on most devices).
split.screen(c(2,1)) # split display into two screens
split.screen(c(1,3), screen = 2) # now split the bottom half into 3
screen(1) # prepare screen 1 for output
plot(10:1)
screen(4) # prepare screen 4 for output
plot(10:1)
Have a look at help(layout). This allows you to specify the what, where and in which sizes.
Once plotted, I don't think you re-plot just partially. But you you can use dev.set() et al to switch between different 'plot devices' (ie windows); see help(dev.list).
Note that the suggested answer here is to use split.screen(). It may work, but according to the split.screen help file: "The recommended way to use these functions is to completely draw a plot and all additions (i.e. points and lines) to the base plot, prior to selecting and plotting on another screen. The behavior associated with returning to a screen to add to an existing plot is unpredictable and may result in problems that are not readily visible."
In an answer to my question, there is a more useful solution, using the par(mfg) option:
Change plot panel in multipanel plot in R
Another option is that of implementing a little GUI e.g. with RGtk2 or RTclTk.
I generally do this for graphs that I want to change in realtime and it works great.
For instance, with RGtk2 and cairoDevice you could just do something like (I assume you have a Glade interface)
# Helper function to get a widget from the Glade interface
getWidget <- function(name)
{
return (interface$getWidget(name))
}
interface <- gladeXMLNew("interface.glade", root="mainWindow")
# Our cairo devices (to draw graphics).
# plot1, plot2, and plot3 are GtkDrawingArea widgets
asCairoDevice(getWidget("plot1"))
# dev.cur() will give the device number of the last device we created
# You'll use this to switch device when you draw in different plots
# Storing the device number is important because you may have other
# devices open from other unrelated plots
# (so never assume they'll just start from 1 and be sequential!!!)
plot1.dev <- as.integer(dev.cur())
asCairoDevice(getWidget("plot2"))
plot2.dev <- as.integer(dev.cur())
asCairoDevice(getWidget("plot3"))
plot3.dev <- as.integer(dev.cur())
# To draw in a specific plot you just do
dev.set(plot2.dev)
plot(....)
This has many other advantages, like that of being able to positions the graphs easily where you want (using Glade Interface Designer) and having the possibility of user interaction through specific buttons (e.g. you may have a "pause acquisition" button).

Resources