Add one legend to layout plot in Julia - plot

I would like to create one legend for a layout plot in Julia. Here is some reproducible code:
using Plots
plot(rand(100, 4), layout = 4, color = [:red :blue :green :yellow])
Output:
As you can see it shows nicely a legend to each subplot, but I would like to have one shared legend, using :shared doesn't work. So I was wondering if anyone knows how to add a shared legend to a layout plot in Julia?

Maybe this answer can give an idea. I can do it by a trick (creating a transparent plot for the legend). The only problem is that I don't know how I can move the legend (actually, the transparent plot) to the location I want:
colors = [:red :blue :green :yellow]
p = [
plot(col, legend=false, color=colors[idx])
for (idx, col) in enumerate(eachcol(data))
]
p1 = plot((1:4)', legend=true, framestyle=:none, color=colors)
plot(
p...,
p1,
layout = #layout[
[
grid(2, 2)
p
] p1
],
size = (1000, 1000)
)
result of savefig:
If I change the layout like the following:
layout = #layout[
p1 [
grid(2, 2)
p
]
]
# And change the order of the plots
plot(
p1,
p...,
⋮
)
Then I get this:
Note that I cropped the redundant area of the image above.

Related

Color bar legend for values on vertices of igraph in R

I am new in R and I am starting to work on graph visualization over there using igraph. The example below create a simple network of 10 vertices and color them according to color values (which in this case for simplicity I set up to be the same as ids of vertices).
library(igraph)
vertices <- 1:10
first <- 1:10
second <- c(2:10,1)
edges = cbind(first,second)
color = 1:10
net = graph_from_data_frame(edges,vertices=vertices ,directed=F )
V(net)$color = color
plot(net)
However from this plot it is not clear which colors correspond to
which numbers:
To deal with this I have tried to create various
legends I was able to find in the documentation and online. Take for
instance the code below:
legend("bottom", legend=levels(as.factor(color)), bty = "n", cex =
1.5, pt.cex = 3, pch=20, col = color , horiz = FALSE , inset = c(0.1,
-0.3)
But in this case, the result is messy, obscure the picture, and do not provide a continuous color bar that would map the range of values on the nodes to color spectrum. Other options I was able to find are not better.
Do you know how to make a legend in a form of a continuous color bar placed below or to the right from the picture (so that it do not cover any part of it)? Ideally the color bar should show the whole continuous spectrum of colors and a few values corresponding to the colors (at least the extreme ones)?
Do you happen to know how to achieve this?
Thank you for your help!
You should check out this answer by kokkenbaker,although it is a bit cumbersome, it might be just what you need.
How to add colorbar with perspective plot in R
Thanks to ealbsho93 I was able to produce the following solution. It create a pallete, then map the values on the vertices on the graph to the pallete and displays it. It is not straightforward, but the result looks much better (see below)
rm(list=ls())
library(igraph)
library(fields)
vertices <- 1:10
first <- 1:10
second <- c(2:10,1)
edges = cbind(first,second)
net = graph_from_data_frame(edges,vertices=vertices ,directed=F )
#Here we create a sample function on the vertices of the graph
color_num = 10:1
#create a color palette of the same size as the number of vertices.
jet.colors <- colorRampPalette( rainbow( length( unique(color_num) ) ) )
color_spectrum <- jet.colors( length( unique(color_num ) ) )
#and over here we map the pallete to the order of values on vertices
ordered <- order(color_num)
color <- vector(length = length(ordered),mode="double")
for ( i in 1:length(ordered) )
{
color[ ordered[i] ] <- color_spectrum [ i ]
}
V(net)$color = color
#Display the graph and the legend.
plot(net)
image.plot(legend.only=T, zlim=range(color_num), col=color_spectrum )
If there is a better solution, please let me know. Othervise, this one seems to be OK to use.

Quenstions about rgl layout3d plot3d

I am trying to add a overall title to a 3d plot with multiple subplots using the rgl package from R,and i am also trying to set the distance between two sub scenes. In 2D plot, we can use title("my title",outer=TRUE) to gave an overall title, and "mar" to set the margin. So, what is the corresponding parameters?
Here are my code:
rgl.viewpoint(0,0,fov=0)
par3d(windowRect=c(50,50,700,700),zoom=0.8)
mat<-matrix(c(1,2,3,4,5,6),3,2,byrow = TRUE)
height<-c(2,2,2)
width<-c(1,1)
layout3d(mat, height = height,width=width,sharedMouse = TRUE)
for (i in 1:6) {
next3d()
shade3d(shapes[[i]], col = col[i])
}
I want to put a title in the picture and adjust the distance between two subplots.
There's no concept of outer regions in rgl. What you need to do is to add another region to your layout, and put the title there. For example,
library(rgl)
open3d()
mat<-matrix(c(7,7,1,2,3,4,5,6),4,2,byrow = TRUE)
height<-c(1,2,2,2)
width<-c(1,1)
layout3d(mat, heights = height, widths=width, sharedMouse = TRUE)
for (i in 1:6) {
next3d()
shade3d(cube3d(), col = i)
}
next3d()
text3d(0,0,0,"My title")

Increase space between subplots in Plots.jl

How can I increase the space between subplots in Plots.jl?
Minimal non-working example:
julia> using Plots; pyplot()
Plots.PyPlotBackend()
julia> data = [rand(100), rand(100)];
histogram(data, layout=2, title=["Dataset A" "Dataset B"], legend=false)
ylabel!("ylabel")
If you make the figure small enough, the y label of the second plot collides with the first plot.
In the attributes part of Plots.jl documentation, there is a section called Subplot. There, you will find the keywords margin, top_margin, bottom_margin, left_margin and right_margin that might help you.
Minimal working example would be, then:
using Plots, Measures
pyplot()
data = [rand(100), rand(100)];
histogram(data, layout = 2,
title = ["Dataset A" "Dataset B"], legend = false,
ylabel = "ylabel", margin = 5mm)
Note the using Measures part, by the way. I hope this helps.
Another workaround would be using the bottom_margin keyword argument holding the pyplot backend like this:
using Plots
pyplot()
x1 = rand(1:30, 20);
x2 = rand(1:30, 20);
# subplot 1
p1 = plot(
x1,
label="x1 value",
title="x1 line plot",
ylabel="x1",
bottom_margin=50*Plots.mm,
);
# subplot 2
p2 = plot(
x2,
label="x2 value",
title="x2 line plot",
xlabel="sample",
ylabel="x2",
);
plot(
p1,
p2,
layout=grid(
2,1,
)
)
An alternative is to use the empty figure object _ to occupy the space. It works well when a long legend name overlaps with another subplot with PGFPlotsX backend,
pgfplotsx()
p1 = plot(1:10, label = "a long label name")
p2 = plot(1:10)
plot(p1, p2)
we can use _ in #layout to leave more space for the legend of the first subplot,
plot(p1, p2, layout=#layout([a{0.5w} _ b{0.3w}]))
It can even handle more complicated cases. For example, you might just want to increase the space between two specific subplots instead of all subplots. For example, I use the setting
layout = #layout([grid(2, 1){0.3w} _ grid(2, 1){0.3w} b{0.33w}])
to leave more space via _ for the legend for the left two subplots grid(2,1), but do not touch other subplots.

Adding legend to venn diagram

I am using library VennDiagram to plot venn diagrams. But this function does not have a functionality to add legend and set names are displayed on or close to the sets themselves.
library(VennDiagram)
x <- list(c(1,2,3,4,5),c(4,5,6,7,8,9,10))
venn.diagram(x,filename="test.png",fill=c("#80b1d3","#b3de69"),
category.names=c("A","B"),height=500,width=500,res=150)
And with many sets, overplotting names is an issue and I would like to have a legend instead. The function is built on grid graphics and I have no idea how grid plotting works. But, I am attempting to add a legend anyway.
Looking into the venn.diagram function, I find that final plotted object is grob.list and it is a gList object and its plotted using grid.draw().
png(filename = filename, height = height, width = width,
units = units, res = resolution)
grid.draw(grob.list)
dev.off()
I figured out that I could create a legend by modifying the venn.diagram function with the code below.
cols <- c("#80b1d3","#b3de69")
lg <- legendGrob(labels=category.names, pch=rep(19,length(category.names)),
gp=gpar(col=cols, fill="gray"),byrow=TRUE)
Draw the object lg
png(filename = filename, height = height, width = width,
units = units, res = resolution)
grid.draw(lg)
dev.off()
to get a legend
How do I put the venn diagram (gList) and the legend (gTree,grob) together in a usable way? I am hoping to get something like base plot style:
or the ggplot style
If you are allowed to use other packages than VennDiagram, I suggest the following code using the eulerr package:
library(eulerr)
vd <- euler(c(A = 5, B = 3, "A&B" = 2))
plot(vd, counts = TRUE,lwd = 2,
fill=c("#80b1d3","#b3de69"),
opacity = .7,
key = list( space= "right", columns=1))
with key you define the legend location and appearance.
If you want to continue using the VennDiagram package and learn a bit of grid on the way:
Prepare diagram and legend
library(VennDiagram)
x <- list(c(1,2,3,4,5),c(4,5,6,7,8,9,10))
diag <- venn.diagram(x,NULL,fill=c("#80b1d3","#b3de69"),
category.names=c("A","B"),height=500,width=500,res=150)
cols <- c("#80b1d3","#b3de69")
lg <- legendGrob(labels=c("A","B"), pch=rep(19,length(c("A","B"))),
gp=gpar(col=cols, fill="gray"),
byrow=TRUE)
Transform the diagram to a gTree
(I'd love to find a better way if anyone knows one)
library(gridExtra)
g <- gTree(children = gList(diag))
Plot the two gTrees side by side
gridExtra::grid.arrange(g, lg, ncol = 2, widths = c(4,1))
Or one above the other
grid.arrange(g, lg, nrow = 2, heights = c(4,1))
I have found a solution as well, but the venn diagram region is not square aspect ratio. And the legend is not spaced ideally.
library(gridGraphics)
png("test.png",height=600,width=600)
grab_grob <- function(){grid.echo();grid.grab()}
grid.draw(diag)
g <- grab_grob()
grid.arrange(g,lg,ncol=2,widths=grid::unit(c(0.7,0.3),"npc"))
dev.off()

R par(omd) does not contain within mfrow

I would like two plots to show up in two seperate spaces in the plot so I do:
par(mfrow=c(1,2))
plot(1:10,1:10)
Now I would like the second plot to be about 25% shorter than the first plot so I adjust omd:
tmp <- par()$omd
tmp[4] <- 0.75
par(omd=tmp)
plot(1:10,1:10)
The problem is that the second plot shows up ontop of the first plot. How do I avoid this margin issue?
Maybe try using layout instead?
layout(matrix(c(1, 1, 0, 2), ncol = 2L), widths = c(1,1),heights = c(0.5,1))
par(mar = c(3,2,2,2))
plot(1:10,1:10)
par(mar = c(3,2,2,2))
plot(1:10,1:10)
I guess maybe you'd want to set the heights to c(0.2,0.8) to get a 25% reduction?
Edit
But I don't think that omd does what you think it does. It changes the region inside the outer margins, which will always include both plot regions when setting par(mfrow = c(1,2)). What you really want to change, I think is plt, which alters the size of the current plotting region (using quartz, as I'm on a mac):
quartz(width = 5,height = 5)
par(mfrow=c(1,2))
vec <- par("plt")
plot(1:10,1:10)
par(plt = vec * c(1,1,1,0.75))
plot(1:5,1:5)

Resources