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')
Related
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)
I am trying to extract a vector from a nested list based on the value of another variable\element within the same nested list. Hopefully my example will explain what I'm trying to do.
To begin, I have a list of lists like so:
## Create the inner lists
# Inner list 1
listInner1 <- list(
value = c(0.25),
index = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
left = c(),
right = c()
)
listInner1$left$index <- c(1, 2, 3, 4, 5)
listInner1$left$good <- TRUE
listInner1$right$index <- c(6, 7, 8, 8, 10)
listInner1$right$good <- TRUE
# Inner list 2
listInner2 <- list(
value = c(1.5),
index = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
left = c(),
right = c()
)
listInner2$left$index <- c(1, 2, 3)
listInner2$left$good <- TRUE
listInner2$right$index <- c(4, 5, 6, 7, 8, 9, 10)
listInner2$right$good <- TRUE
# Inner list 3
listInner3 <- list(
value = c(0.5),
index = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
left = c(),
right = c()
)
listInner3$left$index <- c(1, 2, 3, 4, 5)
listInner3$right$index <- c( 6, 7, 8, 9, 10)
listInner3$left$left$index <- c(2, 4, 6, 8, 10)
listInner3$left$right$index <- c(1, 3, 5 ,7, 9)
listInner3$left$left$good <- TRUE
listInner3$left$right$good <- TRUE
# put all inner lists into single list object
listMiddle <- list(listInner1, listInner2, listInner3)
# one more list for fun
listMaster <- list(listMiddle)
As you can see, some of the left and right elements of the nested lists contain the element good = TRUE and some don't.
What I'm trying to do is if a particular nested list contains the element good = TRUE then to extract the element index from that same nested list.
For example, manually creating my desired output for the above example would look something like this:
ans <- list(
index.1 = c(1, 2, 3, 4, 5),
index.2 = c(6, 7, 8, 8, 10),
index.3 = c(1, 2, 3),
index.4 = c(4, 5, 6, 7, 8, 9, 10),
index.5 = c(2, 4, 6, 8, 10),
index.6 = c(1, 3, 5 ,7, 9)
)
The object ans contains all the index vectors that are contained within a nested list that also contains good = TRUE.
Any suggestions as to how I could do this?
Here is an option where we bind the nested elements to a more easily approachable format with rrapply, then, we get the index of 'good' columns, extract the corresponding 'index' elements from that position index by looping over in map2 (based on the the TRUE values), transpose the list , keep only the elements having greater than 0 length, flatten the list and set the names (if needed)
library(purrr)
library(rrapply)
library(stringr)
library(dplyr)
out <- rrapply(listMaster, how = 'bind')
i1 <- grep('good', names(out))
map2(out[i1-1], out[i1], `[`) %>%
transpose %>%
map( ~ keep(.x, lengths(.x) > 0)) %>%
flatten %>%
setNames(str_c('index.', seq_along(.)))
-output
$index.1
[1] 1 2 3 4 5
$index.2
[1] 6 7 8 8 10
$index.3
[1] 1 2 3
$index.4
[1] 4 5 6 7 8 9 10
$index.5
[1] 2 4 6 8 10
$index.6
[1] 1 3 5 7 9
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
How can we custom the position of the panels/subplot in ggplot2?
Concretely I have a grouped times series and I want to produce 1 subplot per time series with custom positions of the subplot, not necessarily in a grid.
The facet_grid() or facet_wrap() functions do not provide a full customization of the position of the panel as it uses grid.
library(tidyverse)
df = data.frame(group = LETTERS[1:5],
x = c(1,2,3,1.5,2.5),
y =c(2,1,2,3,3),
stringsAsFactors = F)%>%
group_by(group)%>%
expand_grid(time = 1:20)%>%
ungroup()%>%
mutate(dv = rnorm(n()))%>%
arrange(group,time)
## plot in grid
df%>%
ggplot()+
geom_line(aes(x=time,y=dv))+
facet_grid(~group)
## plot with custom x, y position
## Is there an equivalent of facet_custom()?
df%>%
ggplot()+
geom_line(aes(x=time,y=dv))+
facet_custom(~group, x.subplot = x, y.subplot = y)
FYI: This dataset is only an example. My data are EEG data where each group represents an electrode (up to 64) and I want to plot the EEG signals of each electrode accordingly to the position of the electrode on the head.
Well, I guess this would not really be a 'facet plot' any more. I therefore don't think there is a specific function out there.
But you can use the fantastic patchwork package for that, in particular the layout option in wrap_plots.
As the main package author Thomas describes in the vignette, the below option using area() may be a bit verbose, but it would give you full programmatic options about positioning all your plots.
library(tidyverse)
library(patchwork)
mydf <- data.frame(
group = LETTERS[1:5],
x = c(1, 2, 3, 1.5, 2.5),
y = c(2, 1, 2, 3, 3),
stringsAsFactors = F
) %>%
group_by(group) %>%
expand_grid(time = 1:20) %>%
ungroup() %>%
mutate(dv = rnorm(n())) %>%
arrange(group, time)
## plot in grid
mylist <-
mydf %>%
split(., .$group)
p_list <-
map(1:length(mylist), function(i){
ggplot(mylist[[i]]) +
geom_line(aes(x = time, y = dv)) +
ggtitle(names(mylist)[i])
}
)
layout <- c(
area(t = 1, l = 1, b = 2, r = 2),
area(t = 2, l = 3, b = 3, r = 4),
area(t = 3, l = 5, b = 4, r = 6),
area(t = 4, l = 3, b = 5, r = 4),
area(t = 5, l = 1, b = 6, r = 2)
)
wrap_plots(p_list, design = layout)
#> result not shown, it's the same as below
For a more programmatic approach, one option is to create the required "patch_area" object manually.
t = 1:5
b = t+1
l = c(1,3,5,3,1)
r = l+1
list_area <- list(t = t, b = b, l = l, r = r)
class(list_area) <- "patch_area"
wrap_plots(p_list, design = list_area)
Created on 2020-04-22 by the reprex package (v0.3.0)
To explain what I want to do exactly, I will use the following example:
a = list(x = 5, y = c(11, 12, 13))
b = list(x = 4.7, y = c(112, 5, 2))
c = list(x = 77, y = c(5, 1, 1))
d = list(x = 5, y = c(22, 11, 43))
test_list = list(a, b, c, d)
I have a nested list: test_list. I would like to search vector 5 only in element x in the tested_list, and return the indices of the list, e.g., here as c(1,4).
Thanks a lot.
I would try with lapply like here:
a = list(x = 5, y = c(11, 12, 13))
b = list(x = 4.7, y = c(112, 5, 2))
c = list(x = 77, y = c(5, 1, 1))
d = list(x = 5, y = c(22, 11, 43))
test_list = list(a, b, c, d)
which(unlist(lapply(test_list, function(x) {
x$x == 5
})))
First you choose x then for 5 then unlist and then check which are TRUE.
Try:
which(vapply(test_list, function(x) x[["x"]] == 5, logical(1)))
Similarly, using purrr:
which(map_lgl(test_list, ~ pluck(., "x") == 5))
[1] 1 4
As 'x' is of length 1 in each list element, it may be better to do the comparison at once after extracting the element
which(sapply(test_list, `[[`, 'x')==5)
#[1] 1 4