How to make a 3D histogram with Plotly in R? - r

library(plotly)
fig1 <- plot_ly(data=DATA, x=~X, name="X",
type="histogram", histnorm="probability")
fig2 <- plot_ly(data=DATA, x=~Y, name="Y",
type="histogram", histnorm="probability")
subplot(fig1, fig2)
Suppose I have a dataset, DATA, and I already drew 2D histograms for both variable X and Y. Now I want to plot a 3D histogram of X and Y. Does anyone know how to do it? The description of Plotly with R includes creating 3D histograms, but I can't find the tutorial under either 3D Charts or Histograms. And the wild guess below just gives me a rotated 2D histogram.
fig <- plot_ly(data=DATA, x=~X, y=~Y,
type="histogram",
histnorm="probability"
) %>%
layout(scene=list(xaxis=list(title="X",zeroline=TRUE),
yaxis=list(title="Y",zeroline=TRUE),
zaxis=list(title="Frequency",zeroline=TRUE)
)
)
fig

Below you can find some preliminary ideas for drawing a 3D histogram with plotly.
See this link to understand how the add_3Dbar function works.
# The matrix with frequencies from a 3 x 4 cross table
z_mtx <- cbind(c(2,4,6,5), c(1,5,9,6), c(2,4,2,3))
# Define a function to add 3D bars
add_3Dbar <- function(p, x,y,z, width=0.4) {
w <- width
add_trace(p, type="mesh3d",
x = c(x-w, x-w, x+w, x+w, x-w, x-w, x+w, x+w),
y = c(y-w, y+w, y+w, y-w, y-w, y+w, y+w, y-w),
z = c(0, 0, 0, 0, z, z, z, z),
i = c(7, 0, 0, 0, 4, 4, 2, 6, 4, 0, 3, 7),
j = c(3, 4, 1, 2, 5, 6, 5, 5, 0, 1, 2, 2),
k = c(0, 7, 2, 3, 6, 7, 1, 2, 5, 5, 7, 6),
facecolor = rep(toRGB(viridisLite::inferno(6)), each = 2))
}
# Draw the 3D histogram
fig <- plot_ly()
for (k1 in 1:nrow(z_mtx)) {
for (k2 in 1:ncol(z_mtx)) {
fig <- fig %>% add_3Dbar(k1,k2,z_mtx[k1,k2])
}
}
fig

Related

How can I match coordinates with their associated values in R

I have 250 points that I generated within a rectangle (-4,4)x(-6,6). If the popints are within a certain space they are blue and if they are outside of that space they are red.
The code I used for this is here, where i defined the confined space with squares:
library(sf)
border <- matrix(c(
-6, -4,
-6, 4,
6, 4,
6, -4,
-6, -4
), ncol = 2, byrow = TRUE) |>
sfheaders::sfc_polygon()
# sample random points
rand_points <- st_sample(border, size = 250)
squares1 <- matrix(c(
-4, 0,
-4, 3,
-1, 3,
-1, 0,
-4, -0
), ncol = 2, byrow = TRUE) |>
sfheaders::sfc_polygon()
squares2 <- matrix(c(
-2, -4,
-2, -1,
1, -1,
1, -4,
-2, -4
), ncol = 2, byrow = TRUE) |>
sfheaders::sfc_polygon()
squares3 <- matrix(c(
2, -2,
2, 1,
5, 1,
5, -2,
2, -2
), ncol = 2, byrow = TRUE) |>
sfheaders::sfc_polygon()
squares <- c(squares1, squares2, squares3)
red_vals <- st_difference(rand_points, squares)
blue_vals <- st_intersection(rand_points, squares)`
plot(border)
plot(negative_vals, add = TRUE, col = "red")
plot(positive_vals, add = TRUE, col = "blue")
My goal is to match the points' coordinates with their expected value. Example:
In the table, the third column is for the blue points and the fourth column for the red. If the point at that coordinate is blue it gets a +1 and if it is not blue at that coordinate -1, and vice versa for the red points.
So far, I have attained the coordinates of all the points.
y <- c(red_vals)
x <- c(blue_vals)
cdata <- c(x, y)
coord <- st_coordinates(cdata)`
I am now stuck on trying to figure out how I can classify x and y to their respective coordinates and indicate this in a dataframe.
Any help is appreciated.
You could do:
red_vals <- rand_points[rowSums(st_intersects(rand_points, squares, F)) == 0]
blue_vals <- st_intersection(rand_points, squares)
df <- rbind(cbind(st_coordinates(red_vals), PosGroup = 1, NegGroup = -1),
cbind(st_coordinates(red_vals), PosGroup = -1, NegGroup = 1)) |>
as.data.frame()
head(df)
#> X Y PosGroup NegGroup
#> X1 -5.2248158 0.03710509 1 -1
#> X2 -5.8932331 -1.41421992 1 -1
#> X3 -0.0609895 0.26541100 1 -1
#> X4 1.7345333 -3.04312404 1 -1
#> X5 -4.6801643 0.24656851 1 -1
#> X6 1.3190239 3.36491623 1 -1
Obviously the first few values are all red dots.
We can see that the points are correct by using this data frame to draw points in ggplot:
library(ggplot2)
df %>%
ggplot() +
geom_sf(data = squares) +
geom_point(aes(X, Y, color = factor(PosGroup)), pch = 1, size = 3) +
theme_classic() +
scale_color_brewer(palette = "Set1", direction = -1)

Border subplots in in subplot in R with Layout

I have a question. I know it is not clear. However, I have 8 figures in 4 subplots. I want to border a line for each two of them and put the number around them. I attached a figure as follows. Could you please help me with that? I used the following simple example to plot this figures:
m1 <- matrix(c(
1, 2, 3, 4,
5, 6, 7, 8), nrow = 2, ncol = 4, byrow = TRUE)
layout(m1, widths = c(2.2, 1.5,2.2, 1.5))
par(mar=c(1,7,4,2))

How to plot a two-columned grid of time series with custom titles using R?

I have the following code (although without data, sadly):
detrend_plot <- cbind(l_p_lng,l_vol_lng,l_p_oil,l_rgdpe, ldiff_p_lng,ldiff_vol_lng,ldiff_p_oil,ldiff_rgdpe)
plot.ts(detrend_plot, main="",)
which gives the following plot:
What I want to do is to add custom titles, individual y-axis labels, and x-axis labels. I know that this is possible using GGPLOT, although my knowledge of it is sparse. Has anyone encountered a similar problem? I don't think this is possible using the regular plot.ts( ) function.
I don't think you can pass multiple titles and labels to plot.ts directly, but you can just loop over your columns with vectors of labels for each:
set.seed(1)
z <- ts(matrix(rt(200 * 8, df = 3), 200, 8), start = c(1961, 1), frequency = 12)
## vectors of x, y, and main labels
xl <- sprintf('x label %s', 1:8)
yl <- sprintf('y label %s', 1:8)
ml <- sprintf('main label %s', 1:8)
par(mfrow = c(4, 2), mar = c(5, 5, 1, 1), oma = c(0, 0, 1, 2))
lapply(1:8, function(ii) {
x <- z[, ii, drop = FALSE]
plot(x, xlab = xl[ii], ylab = yl[ii], main = ml[ii])
})
You can also pass vectors of arguments (eg, for x- or y-axis limits) using lists:
ylim <- list(c(-10, 10))
ylim <- rep(ylim, 8)
par(mfrow = c(4, 2), mar = c(5, 5, 1, 1), oma = c(0, 0, 1, 2))
lapply(1:8, function(ii) {
x <- z[, ii, drop = FALSE]
plot(x, xlab = xl[ii], ylab = yl[ii], main = ml[ii], col = ii, ylim = ylim[[ii]])
})
To get a figure closer to the default plot.ts look, you can just set top and bottom margins to 0 and adjust the axes (which is what plot.ts is doing under the hood). This method is a bit more verbose than plot.ts but will allow for more customization:
par(mfrow = c(4, 2), mar = c(0, 5, 0, 1), oma = c(5, 0, 3, 2))
lapply(1:8, function(ii) {
x <- z[, ii, drop = FALSE]
plot(x, xlab = xl[ii], ylab = yl[ii], col = ii, axes = FALSE)
axis(2, las = 1)
box()
if (ii %in% 7:8) {
axis(1)
title(xlab = 'Year', xpd = NA)
}
if (ii %in% 1:2)
title(main = c('Group 1', 'Group 2')[ii], xpd = NA, line = 1)
})

How do I manually assign the location of bars along the x-axis using barplot()?

I have a list of means.
means=c(anc3mean,l3mean,anc5mean,l5mean,anczmean,z12mean);means
[1] 0.07025897 0.42328670 0.05697524 0.53915431 0.01893219 0.10878638
I have created a barplot from those means.
bars=barplot(means,ylim=c(0,.8))
I would like to have the "bars" be centered at the values 1, 2, 4, 5, 7, 8 along the x axis.
I have tried the following:
bars=barplot(means,ylim=c(0,.8),at=c(1,2,4,5,7,8))
This does not work however because "at" is not an argument for "barplot()".
Any help would be greatly appreciated.
You could insert "empty" elements
# x position of the means
loc <- c(1, 2, 4, 5, 7, 8)
# Fill with empty elements
hght <- setNames(rep(0, max(loc)), 1:max(loc))
hght[loc] <- means
# Plot
x = barplot(hght, ylim = c(0, 0.8))
axis(1, at = x, labels = names(hght))
If you don't want the x-axis, simply remove the axis(...) line.
Sample data
means <- c(0.07025897, 0.42328670, 0.05697524, 0.53915431, 0.01893219, 0.10878638)

Set X Axis Range on Plotly Frequency Graph

Consider the following graph:
library(dplyr)
library(plotly)
x <- c(1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 5, 6, 8, 8, 8, 10, 10)
y <- as.data.frame(table(x))
y %>%
plot_ly(x = ~ x,
y = ~ Freq,
type = 'bar')
I would like to take this graph and produce a similar graph in which the values 7 and 9 are listed with a frequency of zero. Is there a way to get a frequency count of a sequence like seq(0, 10, 1) where 7 and 9 would appear as a frequency of 0 or is there a way that I can set the x axis on my plotly graph to be from 0 to 10 even though I don't have all the numbers in my data?
I have tried
y %>%
plot_ly(x = ~ x,
y = ~ Freq,
type = 'bar') %>%
layout(xaxis = list(autotick = FALSE, tick0 = 0, tickd = seq(0, 10, 1))
and also
layout(xaxis = list(autotick = FALSE, tick0 = 0, tickd = c(0,10))
but neither one seems to change anything.
I would like my desired output to look like this:
Note that This is just a small sample and my actual data will be much larger. Because of this, something like looping through the data and counting every number would be too slow.
A simple solution is to convert x as a factor with levels from 1 to 10.
library(dplyr)
library(plotly)
x <- c(1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 5, 6, 8, 8, 8, 10, 10)
x <- factor(x, levels=1:10)
y <- as.data.frame(table(x))
y %>%
plot_ly(x = ~ x,
y = ~ Freq,
type = 'bar')

Resources