I wanted to plot the venn diagram with two sets in which one set falls completely within another. I could draw a diagram with R package Venndiagram like this
library(VennDiagram)
grid.newpage();
venn.plot <- draw.pairwise.venn(area1 =467 ,area2 =273 ,cross.area = 273,
category = c("Set1", "Set2"),fill = c("darkorange", "dodgerblue1"),
lty = rep("solid", 2),lwd = c(2,2),col = c("black","black"),cex = 2,cat.cex = 2,cat.pos = c(310, 135),
cat.dist = 0.09,cat.just = list(c(-1, -1), c(1, 1)),
ext.pos = 30,ext.dist = -0.05,
ext.length = 0.85,ext.line.lwd = 2,ext.line.lty = "dashed");
grid.draw(venn.plot);
This may sound like esoteric tricks, but how to adjust the position of the circles, say, instead of two concentric circles, let the inner circle touch the the outer one?
Something like this one here. I added one non overlapping element.
I could not find an argument in the Venndiagram package allowing me to adjust the position of the circles.
You can try this with plotrix:
library(plotrix)
area1 = 467
area2 = 273
r1 = round(sqrt(area1/pi))
r2 = round(sqrt(area2/pi))
xc = 8
yc = 8
plot(0:40,0:40,type="n",xlab="",ylab="",main="Venn Diagram", xaxt='n', yaxt='n')
draw.circle(xc+r1,yc+r1,r1,border="black", col="orange",lty=1,lwd=1)
draw.circle(xc+2*r1-r2,yc+r1,r2,border="black", col="steelblue",lty=1,lwd=1)
text(xc+2*r1-r2,yc+r1, '272', cex=3)
text(xc+(r1-r2)/2+1,yc+r1, '195', cex=3)
text(xc+r1,yc+2*r1+7, 'Set1', cex=3)
text(xc+r1+r2,1, 'Set2', cex=3)
Related
Sometimes there is a need to display points on the graph on top of the axes so that the result looks something like this:
Previously, when I used R, it took a certain amount of alchemy to get the desired result: first the size of the rendering field was set, then the position of the axis, and at the end data points were drawn on top of all this:
f <- rnorm(10, mean=5, sd=1)
plot(x = f, y = c(rep(0, 10)), xlim = c(-1, 11), ylim = c(0, 1),
axes = FALSE, box = FALSE, xaxs = "i", ylab="")
abline(h=0)
axis(side = 1, at = seq(0, 10, 2), pos = 0, tck = -0.02)
points(x = f, y = c(rep(0, 10)), cex=1.0, pch = 21,
col="black", bg="white", lwd = 1)
Now I'm trying to translate my entire workflow to Julia and I want to find some alternative for such visualization. I usually use Plots.jl with GR backend. The trick I used in R does not work in this case: when adding a layer above, it is still cut off by the canvas borders set at the beginning:
c = vcat(1.0, 3.0, 4.0, 6.0, 7.0, 9.0, 12.0, 21.0)
plot(c, zeros(length(c)), seriestype = :scatter,
markersize=5, markershape=:circle, color = :white, label = "", ylims=(0,Inf))
plot!(c, zeros(length(c)), seriestype = :scatter,
markersize=5, markershape=:circle, color = :white, label = "")
Result:
What is the most rational way to get such graphics with Julia?
You should be able to plot on the x-axis by using framestyle=:origin or framestyle=:zerolines
scatter(c, zeros(length(c)),
markersize=5, markershape=:circle,
color = :red, label="", framestyle=:zerolines)
and if you want to show just the x-axis
scatter(c, zeros(length(c)), markersize=5,
markershape=:circle, color = :red, legend=false,
framestyle=:origin, yaxis=false, grid=false, aspect_ratio=1.0)
I have drawn the following plot using the circlizepackage. The red circle is the unit circle drawn afterwards, using plotrix. I want to plot the first track outside the red unit circle. For this reason I changed canvas.xlim and canvas.ylim to c(-1.2, 1.2). However, this does not work. Any ideas how to increase the circle radius for the circlize plot?
NOTE: Alternatively, it would be sufficient for me, if the tracks would be outside of the unit circle instead of inside.
library(circlize)
set.seed(2)
n = 10
a = data.frame(factor = "dummy",
x = rnorm(n, 100, sd=10))
circos.par(track.height = 0.2,
canvas.xlim=c(-1.2, 1.2), # bigger canvas?
canvas.ylim=c(-1.2, 1.2)) # bigger canvas?
circos.initialize(factors = a$factor,
x = a$x, xlim = c(0, 360))
lim <- c(-1.2, 1.2)
plot(NULL, asp=1, xlim=lim, ylim=lim)
circos.trackHist(a$factor, a$x, col = "blue", bg.col = grey(.95))
plotrix::draw.circle(0,0,1, border="red", lwd=2) # unit circle
I don't know how to adjust xlim and ylim to make two plots fit. But if you just want to put the red circle inside the track, you can use draw.sector() function directly:
circos.initialize(factors = a$factor,
x = a$x, xlim = c(0, 360))
circos.trackHist(a$factor, a$x, col = "blue", bg.col = grey(.95))
draw.sector(0, 360, rou1 = circlize:::get_most_inside_radius(),
border = "red")
Here circlize:::get_most_inside_radius() returns the distance between the bottom border of the last track to the center of the circle.
I am trying to plot rose diagrams/ circular histograms on specific coordinates on a map analogous to drawing pie charts on a map as in the package mapplots.
Below is an example generated with mapplots (see below for code), I'd like to replace the pie charts with rose diagrams
The package circular lets me plot the rose diagrams, but I am unable to integrate it with the mapplots package. Any suggestions for alternative packages or code to achieve this?
In response to the question for the code to make the map. It's all based on the mapplots package. I downloaded a shapefile for the map (I think from http://www.freegisdata.org/)
library(mapplots)
library(shapefiles)
xlim = c(-180, 180)
ylim = c(-90, 90)
#load shapefile
wmap = read.shapefile ("xxx")
# define x,y,z for pies
x <- c(-100, 100)
y <- c(50, -50)
z1 <- c(0.25, 0.25, 0.5)
z2 <- c(0.5, 0.2, 0.3)
z <- rbind(z1,z2)
# define radii of the pies
r <- c(5, 10)
# it's easier to have all data in a single df
plot(NA, xlim = xlim, ylim = ylim, cex = 0.75, xlab = NA, ylab = NA)
draw.shape(wmap, col = "grey", border = "NA")
draw.pie(x,y,z,radius = r, col=c("blue", "yellow", "red"))
legend.pie (x = -160, y = -70, labels = c("0", "1", "2"), radius = 5,
bty = "n", cex = 0.5, label.dist=1.5, col = c("blue", "yellow", "red"))
the legend for the pie size can then be added using legend.bubble
Have a look at this example, you can use the map as background an plot your rose diagrams withPlotrix or ggplot2. In either case you would want to overlay multiple of these diagrams on top of your map which is easy to do in ggplot, just have a look at the example.
I discovered subplot() in the package Hmisc, which seems to do exactly what I wanted. Below is my solution (without the map in the background, which can be plotted using mapplots). I am open to suggestions on how to improve this though...
library(Hmisc)
library (circular)
dat <- data.frame(replicate(2,sample(0:360,10,rep=TRUE)))
lat <- c(50, -40)
lon <- c(-100, 20)
# convert to class circular
cir.dat <- as.circular (dat, type ='angles', units = 'degrees', template = 'geographic', modulo = 'asis', zero = 'pi/2', rotation = 'clock')
# function for subplot, plots relative frequencies, see rose.diag for how to adjust the plot
sub.rose <- function(x){
nu <- sum(!is.na(x))
de <- max(hist(x, breaks = (seq(0, 360, 30)), plot = FALSE)$counts)
prop <- nu/de
rose.diag(x, bins = 12, ticks = FALSE, axes = FALSE,
radii.scale = 'linear',
border = NA,
prop = prop,
col = 'black'
)
}
plot(NA, xlim = xlim, ylim = ylim)
for(i in 1:length(lat)){
subplot(sub.rose(cir.dat[,i]), x = lon[i], y = lat[i], size = c(1, 1))
}
I'm using base R plotting functions to produce a pie chart and I want to change the line thickness of the outlines of each pie segment. ?pie seems to indicate that I can add optional graphic parameters, but adding lwd= does not appear to work. Anyone have any clues as to how I might be able to do this. I'm not yet proficient in producing pie charts in ggplot, and would like to stick with base R plotting (if possible).
library(RColorBrewer)
x1 <- data.frame(V1 = c(200, 100)) ## generate data
row.names(x1) <- c("A", "B")
x1$pct <- round((x1$V1/sum(x1$V1))*100, 1)
lbls1 <- paste(row.names(x1), "-(",x1$pct, '%)', sep='') ## add some informative stuff
pie(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1, lwd= 3)
Notice lwd= does not increase line thickness like it would in other base plotting.
Anyone have any clues?
The call to polygon and lines within pie does not pass ... or lwd
...
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i])
P <- t2xy(mean(x[i + 0:1]))
lab <- as.character(labels[i])
if (!is.na(lab) && nzchar(lab)) {
lines(c(1, 1.05) * P$x, c(1, 1.05) * P$y)
....
You can get around this by setting par(lwd = 2) (or whatever) outside and prior to your call to pie
i.e.
# save original settings
opar <- par(no.readonly = TRUE)
par(lwd = 2)
pie(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1)
par(lwd = 3)
# reset to original
par(opar)
At the moment, the function inside pie that does the actual drawing is polygon and here is how it is called:
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i])
Notice there is no lwd argument and more critically no ... argument to accept arguments that might not have been hard coded.
Create a new pie2 function. First type pie, copy the code and make a few changes:
pie2 <-
function (x, labels = names(x), edges = 200, radius = 0.8, clockwise = FALSE,
init.angle = if (clockwise) 90 else 0, density = NULL, angle = 45,
col = NULL, border = NULL, lty = NULL, main = NULL, lwd=1,...)
{
................
polygon(c(P$x, 0), c(P$y, 0), density = density[i], angle = angle[i],
border = border[i], col = col[i], lty = lty[i], lwd=lwd )
.................
}
pie2(x1$V1, labels=lbls1, col=tail(brewer.pal(3, 'PuBu'), n=2),
main=paste('My 3.1415'), cex=1.1, lwd=5)
I'd like to do a vertical histogram. Ideally I should be able to put multiple on a single plot per day.
If this could be combined with quantmod experimental chart_Series or some other library capable of drawing bars for a time series that would be great. Please see the attached screenshot. Ideally I could plot something like this.
Is there anything built in or existing libraries that can help with this?
I wrote something a year or so ago to do vertical histograms in base graphics. Here it is, with a usage example.
VerticalHist <- function(x, xscale = NULL, xwidth, hist,
fillCol = "gray80", lineCol = "gray40") {
## x (required) is the x position to draw the histogram
## xscale (optional) is the "height" of the tallest bar (horizontally),
## it has sensible default behavior
## xwidth (required) is the horizontal spacing between histograms
## hist (required) is an object of type "histogram"
## (or a list / df with $breaks and $density)
## fillCol and lineCol... exactly what you think.
binWidth <- hist$breaks[2] - hist$breaks[1]
if (is.null(xscale)) xscale <- xwidth * 0.90 / max(hist$density)
n <- length(hist$density)
x.l <- rep(x, n)
x.r <- x.l + hist$density * xscale
y.b <- hist$breaks[1:n]
y.t <- hist$breaks[2:(n + 1)]
rect(xleft = x.l, ybottom = y.b, xright = x.r, ytop = y.t,
col = fillCol, border = lineCol)
}
## Usage example
require(plyr) ## Just needed for the round_any() in this example
n <- 1000
numberOfHists <- 4
data <- data.frame(ReleaseDOY = rnorm(n, 110, 20),
bin = as.factor(rep(c(1, 2, 3, 4), n / 4)))
binWidth <- 1
binStarts <- c(1, 2, 3, 4)
binMids <- binStarts + binWidth / 2
axisCol <- "gray80"
## Data handling
DOYrange <- range(data$ReleaseDOY)
DOYrange <- c(round_any(DOYrange[1], 15, floor),
round_any(DOYrange[2], 15, ceiling))
## Get the histogram obects
histList <- with(data, tapply(ReleaseDOY, bin, hist, plot = FALSE,
breaks = seq(DOYrange[1], DOYrange[2], by = 5)))
DOYmean <- with(data, tapply(ReleaseDOY, bin, mean))
## Plotting
par(mar = c(5, 5, 1, 1) + .1)
plot(c(0, 5), DOYrange, type = "n",
ann = FALSE, axes = FALSE, xaxs = "i", yaxs = "i")
axis(1, cex.axis = 1.2, col = axisCol)
mtext(side = 1, outer = F, line = 3, "Length at tagging (mm)",
cex = 1.2)
axis(2, cex.axis = 1.2, las = 1, line = -.7, col = "white",
at = c(75, 107, 138, 169),
labels = c("March", "April", "May", "June"), tck = 0)
mtext(side = 2, outer = F, line = 3.5, "Date tagged", cex = 1.2)
box(bty = "L", col = axisCol)
## Gridlines
abline(h = c(60, 92, 123, 154, 184), col = "gray80")
biggestDensity <- max(unlist(lapply(histList, function(h){max(h[[4]])})))
xscale <- binWidth * .9 / biggestDensity
## Plot the histograms
for (lengthBin in 1:numberOfHists) {
VerticalHist(binStarts[lengthBin], xscale = xscale,
xwidth = binWidth, histList[[lengthBin]])
}
Violin plots might be close enough to what you want. They are density plots that have been mirrored through one axis, like a hybrid of a boxplot and a density plot. (Much easier to understanding by example than description. :-) )
Here is a simple (somewhat ugly) example of the ggplot2 implementation of them:
library(ggplot2)
library(lubridate)
data(economics) #sample dataset
# calculate year to group by using lubridate's year function
economics$year<-year(economics$date)
# get a subset
subset<-economics[economics$year>2003&economics$year<2007,]
ggplot(subset,aes(x=date,y=unemploy))+
geom_line()+geom_violin(aes(group=year),alpha=0.5)
A prettier example would be:
ggplot(subset,aes(x=date,y=unemploy))+
geom_violin(aes(group=year,colour=year,fill=year),alpha=0.5,
kernel="rectangular")+ # passes to stat_density, makes violin rectangular
geom_line(size=1.5)+ # make the line (wider than normal)
xlab("Year")+ # label one axis
ylab("Unemployment")+ # label the other
theme_bw()+ # make white background on plot
theme(legend.position = "none") # suppress legend
To include ranges instead of or in addition to the line, you would use geom_linerange or geom_pointrange.
If you use grid graphics then you can create rotated viewports whereever you want them and plot to the rotated viewport. You just need a function that will plot using grid graphics into a specified viewport, I would suggest ggplot2 or possibly lattice for this.
In base graphics you could write your own function to plot the rotated histogram (modify the plot.histogram function or just write your own from scratch using rect or other tools). Then you can use the subplot function from the TeachingDemos package to place the plot wherever you want on a larger plot.