Initialize y-axis to be centered at 0 - plot

I'm generating some line plots that show percent error results. It would be nice if the y-axis was centered at 0 when the plots first load. I know I can manually set the bounds for the y-axis, but it would be tedious to have to set them manually for each figure.
Is there a way to set the figures to center at 0 along the y-axis?
Here's some code that may provide additional details -
from bokeh.plotting import figure, output_file, show
from bokeh.io import gridplot, hplot
# prepare some data
x = [1, 2, 3, 4, 5]
y1 = [-10, -9, 23, 4, -6]
y2 = [-15, -4, 26, 32, -45]
y3 = [-42, -20, -13, -34, -59]
y4 = [-23, -34, -32, -43, -53]
# output to static HTML file
output_file("lines.html", title="line plot example")
# create a new plot with a title and axis labels
p = figure(title="simple line example", x_axis_label='x', y_axis_label='y')
p.line(x, y1, line_width=2)
p.line(x, y2, line_width=2)
p2 = figure(title="simple line example", x_axis_label='x', y_axis_label='y')
p2.line(x, y3, line_width=2)
p2.line(x, y4, line_width=2)
p = hplot(p, p2)
show(p)
This generates two plots. The one on the right shows the problem I'm running into. Since all of the values are negative, the y-axis bounds are narrowed to approximately -10 to -60. I would like that chart to be bound at -60 to 60, so that it's aligned at 0.
Update:
I ended up just defining a function that will return the absolute max of the y values. Then, I am doing the following to set the limits:
axisLimit = getAxisRange(list1, list2) #get absolute max from the two lists
p.y_range = Range1d(start=-1*axisLimit, end=axisLimit)

There's no Bokeh method to center a plot around an axis like you describe. What did you did in your update seems like a good solution. You're always welcome to open an issue on the Bokeh project tracker at https://github.com/bokeh/bokeh/issues

Related

Using second axis to display sample size for grouped data. Can't get spacing right so dot plot aligns with grouped bars in base R

I have grouped data, where every one of the bars has a different sample size, ranging from 0 samples to >600. I would like to have 2 more panels of this same graph for different data, and that would make it very crowded/hard to read if I simply wrote the sample size above each of the bars.
I decided to make a second axis and plot sample size as a dot plot over the bar chart. However I can't get it so the dots align over the bars. I've tried adjusting the width of the bars and spacing in between grouped bars and the sets of bars. And the spacing set for the dot plot should be the same as these widths/spaces (see verts). But its evidently not (see photo linked below). Does anyone have an idea of what is going wrong? Is there any fix or should I move on to trying a different way to communicate the sample sizes?
Here is a pared-down version of the code I am using to draw the figure and a picture of what it looks like right now.
#From https://statisticsglobe.com/r-draw-plot-with-two-y-axes
par(mar = c(5, 4, 4, 4) + 0.3) # Additional space for second y-axis
barplot(t(mxAe), beside=T,
space=c(0,0.75), width=c(0.75,0.75), # Spacing of bars
las=2, col= c("#DDCC77", "#44AA99") ,
ylim=c(0,100) ,
xlim=c(0.5,45),
main="")
par(new = TRUE) # Add new plot
plot(x=mxAe2$place,y=mxAe2$Tot, pch = 16,
cex= 0.5, col = 1, axes = FALSE,
xlab = "", ylab = "") # Create second plot without axes
axis(side = 4, at = pretty(range(0,800))) # Add second axis
abline(v=verts, col="gray30", lty=3) # Add vertical lines along dot plot points
verts <- c(1,1.75,3,3.75,5,5.75,7,7.75,9,9.75,11,11.75,
13, 13.75,15,15.75,17,17.75, 19, 19.75,21,21.75,
23,23.75,25,25.75,27,27.75,29,29.75,31,31.75,
33,33.75,35,35.75,37,37.75,39,39.75,41,41.75,43,43.75) #Position of dots
Reproducible code:
df_mxAe <- data.frame(group1 <- c(9,0,30),group2 <- c(5,20,90))
dotx <- c(1.375,2.125,3.625,4.375,5.875,6.625)
doty <- c(200, 400, 0, 600, 50, 100)
par(mar = c(5, 4, 4, 4) + 0.3) # Additional space for second y-axis
barplot(t(df_mxAe), beside=T, space=c(0,1), width=c(0.75,0.75),
las=2 ,
col= c("#DDCC77", "#44AA99") ,
ylim=c(0,100),
xlim=c(0.5,6.625),
main="") # Create first plot
par(new = TRUE) # Add new plot
plot(x=dotx,y=doty, pch = 18,
cex= 0.5, col = 1, axes = FALSE, xlim=c(0.5,6.625),
xlab = "", ylab = "") # Create second plot without axes
axis(side = 4, at = pretty(range(0,800))) # Add second axis
abline(v=dotx, col="gray30", lty=3) # Add vertical lines along dot plot points
I think that given your setup, your vents should maybe look more like this:
verts <- NULL
k <- 1
for(i in 1:22){
x <- c(.375, .375+.75)
verts <- c(verts, k+x)
k <- max(verts) + .375 + .75
}
verts
# [1] 1.375 2.125 3.625 4.375 5.875 6.625 8.125 8.875 10.375 11.125 12.625 13.375 14.875 15.625 17.125 17.875 19.375 20.125 21.625 22.375
# [21] 23.875 24.625 26.125 26.875 28.375 29.125 30.625 31.375 32.875 33.625 35.125 35.875 37.375 38.125 39.625 40.375 41.875 42.625 44.125 44.875
# [41] 46.375 47.125 48.625 49.375
Since the first bar starts at 1 and has a width of .75, you want the line to be half-way between the start and end of the bar, which would be 1.375. The second bar starts at 1.75 and goes to 2.5. Again, half-way between those two numbers is 2.125. After the second bar ends at 2.5 there is a .75 space, which means the third bar (first in the second group) starts at 2.5+.75 = 3.25. So, the line through the third bar should be at 3.25 + .375 = 3.625, etc...

Trouble adding color bar to Hive Plot in R

I'm working with a hive plot and want to know how to get a vertical color bar placed in the upper left quadrant of the plot, (not one that is off to the side of the plot). Problem is, whenever I run this code I'm not seeing anything pop up. I believe that could be because the methods I've been trying are all for normal plots, not hive plots.
colorplot.l <- seq(1,100,1)
require("grid")
require("HiveR")
test2 <- ranHiveData(nx = 2)
plotHive(test2, ch = 5, axLabs = c("axis 1", "axis 2"), rot = c(-90, 90),
axLab.pos = c(20, 20), axLab.gpar = gpar(col = "pink", fontsize = 14, lwd = 2),
arrow = c("radius units", 0, 20, 60, 25, 40))
colorbar.plot(0,100,colorplot.l, horizontal=FALSE)
Am I doing something wrong or is there another way specifically for a hive plot? Most packages I find don't work with this.
Any help or insight is appreciated.
Creating a viewport with the grid package you can add a color bar to your hive plot:
library(grid)
# A viewport on the upper left corner of the plot
legendViewport <- viewport(x=0.05, y=0.85, height=0.2, width=0.05)
pushViewport(legendViewport)
mypalette <- colorRampPalette(c("red","blue","green"))
# Render the color bar
grid.raster(mypalette(20),
width=unit(1,"npc"), height=unit(1,"npc"), int=FALSE)
Hope it can help you.

Shifting x-axis to the right (metafor, R)

I am working on a forest plot in R using the metafor package and am trying to shift the whole x-axis (alim) to the right to accommodate ilab columns.
Am still not allowed to post images so my current plot now appears as something like this where the text and x-axis overlaps:
|ilab text| |mean [ci.lb, ci.ub]|
|---measure values + ci---|
And I want something like this
|ilab text| |mean [ci.lb, ci.ub]|
|---measure values + ci---|
Although the forestplot package seemed to allow this with its graph.pos function, I couldn't seem to find a similar function in metafor.
I have two questions:
1) Is the x-axis position set on default in metafor?
2) Can this default be overwritten, and if so, how?
Thanks!
Wen
Found the answer: the key is to adjust the xlim, alim and ilab.xpos parameters in relation to 0 (the start of the x-axis) as a reference point.
For example, if this code gives you an overlap,
forest(x, ci.lb = lower, ci.ub = upper,
xlim = c(-350, 170), xlab = "Proportion (%)", at = c(0, 20, 40, 60, 80, 100),
alim = c(0, 100),
ilab = cbind(period, population), ilab.xpos = c(-275, -175), ilab.pos = c(4, 4), cex = 0.75)
You can adjust ilab text further to the left of the x axis by adjusting ilab.xpos() values further away from 0 (e.g. from -175 in the above code to -200). This has to be within the limits of your xlim.

Plotting multiple curves same graph and same scale

This is a follow-up of this question.
I wanted to plot multiple curves on the same graph but so that my new curves respect the same y-axis scale generated by the first curve.
Notice the following example:
y1 <- c(100, 200, 300, 400, 500)
y2 <- c(1, 2, 3, 4, 5)
x <- c(1, 2, 3, 4, 5)
# first plot
plot(x, y1)
# second plot
par(new = TRUE)
plot(x, y2, axes = FALSE, xlab = "", ylab = "")
That actually plots both sets of values on the same coordinates of the graph (because I'm hiding the new y-axis that would be created with the second plot).
My question then is how to maintain the same y-axis scale when plotting the second graph.
(The typical method would be to use plot just once to set up the limits, possibly to include the range of all series combined, and then to use points and lines to add the separate series.) To use plot multiple times with par(new=TRUE) you need to make sure that your first plot has a proper ylim to accept the all series (and in another situation, you may need to also use the same strategy for xlim):
# first plot
plot(x, y1, ylim=range(c(y1,y2)))
# second plot EDIT: needs to have same ylim
par(new = TRUE)
plot(x, y2, ylim=range(c(y1,y2)), axes = FALSE, xlab = "", ylab = "")
This next code will do the task more compactly, by default you get numbers as points but the second one gives you typical R-type-"points":
matplot(x, cbind(y1,y2))
matplot(x, cbind(y1,y2), pch=1)
points or lines comes handy if
y2 is generated later, or
the new data does not have the same x but still should go into the same coordinate system.
As your ys share the same x, you can also use matplot:
matplot (x, cbind (y1, y2), pch = 19)
(without the pch matplopt will plot the column numbers of the y matrix instead of dots).
You aren't being very clear about what you want here, since I think #DWin's is technically correct, given your example code. I think what you really want is this:
y1 <- c(100, 200, 300, 400, 500)
y2 <- c(1, 2, 3, 4, 5)
x <- c(1, 2, 3, 4, 5)
# first plot
plot(x, y1,ylim = range(c(y1,y2)))
# Add points
points(x, y2)
DWin's solution was operating under the implicit assumption (based on your example code) that you wanted to plot the second set of points overlayed on the original scale. That's why his image looks like the points are plotted at 1, 101, etc. Calling plot a second time isn't what you want, you want to add to the plot using points. So the above code on my machine produces this:
But DWin's main point about using ylim is correct.
My solution is to use ggplot2. It takes care of these types of things automatically. The biggest thing is to arrange the data appropriately.
y1 <- c(100, 200, 300, 400, 500)
y2 <- c(1, 2, 3, 4, 5)
x <- c(1, 2, 3, 4, 5)
df <- data.frame(x=rep(x,2), y=c(y1, y2), class=c(rep("y1", 5), rep("y2", 5)))
Then use ggplot2 to plot it
library(ggplot2)
ggplot(df, aes(x=x, y=y, color=class)) + geom_point()
This is saying plot the data in df, and separate the points by class.
The plot generated is
I'm not sure what you want, but i'll use lattice.
x = rep(x,2)
y = c(y1,y2)
fac.data = as.factor(rep(1:2,each=5))
df = data.frame(x=x,y=y,z=fac.data)
# this create a data frame where I have a factor variable, z, that tells me which data I have (y1 or y2)
Then, just plot
xyplot(y ~x|z, df)
# or maybe
xyplot(x ~y|z, df)

R graphics: Add labels to stacked bar chart

I am looking for a way to add labels, i.e. absolute values, into a stacked bar chart using the basic plot functions of R. The labels should be inside the stacked bars.
Thank you!
barplot will return the mid x position of the bars, so you could do
mydata <- matrix(c(10, 21, 22, 33, 45, 23, 22, 43, 33), nrow=3)
# b will contain the x midpoints of the bars
b <- barplot(mydata)
# This will write labels in the middle of the bars, horizontally and vertically
text(b, colMeans(mydata), c("Label1", "Label2", "Label3"))
# This will write labels in the middle of the middle block
text(b, mydata[1,]+mydata[2,]/2, c("LabelA", "LabelB", "LabelC"))
EDIT: re-reading your question, I think this is what you want (or maybe not, but I'll write it anyways :D)
# Find the top y position of each block
ypos <- apply(mydata, 2, cumsum)
# Move it downwards half the size of each block
ypos <- ypos - mydata/2
ypos <- t(ypos)
text(b, ypos, mydata)
How about the simple function text()?
You can simply add a string where ever you want, eg:
text (x = ..., y = ..., labels = c("foo bar 1000"))
Maybe you can use or inspect the barp function of the plotrix package

Resources