I'm building a screener using plotly dash based on some plots generated through Microsoft Excel. One of those charts is the Avg-max-min, below an example of this type of graph.
I have no idea on how to "translate" this kind of graph in to a plotly figure, I've tried this so far, but I did not succeed:
fig = go.Figure(data=go.Scatter(
x=[0, 1, 2],
y=[6, 10, 2],
error_y=dict(
type='data', # value of error bar given in data coordinates
array=[1, 2, 3],
visible=True)
))
I think I've got really close to the real solution, is basically doing a errorbar plot without lines.
It doesn't seem to me that there is a prebuilt function to do so unless you are happy with box plots.
Data
import pandas as pd
import plotly.graph_obj as go
df = pd.DataFrame({"x": [0, 0, 0, 1, 1, 2],
"y":[1,2,4, 1, 10, 4]})
# here I calculate min, max and mean for every x
grp = df.groupby("x").agg({"y":{"min", "max", "mean"}})
grp.columns = ["_".join(col) for col in grp.columns]
grp = grp.reset_index()
Plot
fig = go.Figure()
# first I add a trace for every x
fig.add_trace(go.Scatter(x=grp["x"],
y=grp["y_min"],
mode="markers",
showlegend=False,
marker=dict(color="blue",
size=10)))
fig.add_trace(go.Scatter(x=grp["x"],
y=grp["y_mean"],
mode="markers",
showlegend=False,
marker=dict(color="blue",
size=20)))
fig.add_trace(go.Scatter(x=grp["x"],
y=grp["y_max"],
mode="markers",
showlegend=False,
marker=dict(color="blue",
size=10)))
# then I add a vertical line for
# every x where y_min!=y_max
for i, row in grp.iterrows():
if row["y_min"]!=row["y_max"]:
fig.add_shape(
dict(type="line",
x0=row["x"],
x1=row["x"],
y0=row["y_min"],
y1=row["y_max"],
line=dict(
color="blue",
width=2)
)
)
fig.update_layout(title="Avg-Max-Min Graph", title_x=0.5)
fig.show()
Related
I want to identify 3d cylinders in an rgl plot to obtain one attribute of the nearest / selected cylinder. I tried using labels to simply spell out the attribute, but I work on data with more than 10.000 cylinders. Therefore, it gets so crowded that the labels are unreadable and it takes ages to render.
I tried to understand the documentation of rgl and I guess the solution to my issue is selecting the cylinder in the plot manually. I believe the function selectpoints3d() is probably the way to go. I believe it returns all vertices within the drawn rectangle, but I don't know how to go back to the cylinder data? I could calculate which cylinder is closest to the mean of the selected vertices, but this seems like a "quick & dirty" way to do the job.
Is there a better way to go? I noticed the argument value=FALSE to get the indices only, but I don't know how to go back to the cylinders.
Here is some dummy data and my code:
# dummy data
cylinder <- data.frame(
start_X = rep(1:3, 2)*2,
start_Y = rep(1:2, each = 3)*2,
start_Z = 0,
end_X = rep(1:3, 2)*2 + round(runif(6, -1, 1), 2),
end_Y = rep(1:2, each = 3)*2 + round(runif(6, -1, 1), 2),
end_Z = 0.5,
radius = 0.25,
attribute = sample(letters[1:6], 6)
)
# calculate centers
cylinder$center_X <- rowMeans(cylinder[,c("start_X", "end_X")])
cylinder$center_Y <- rowMeans(cylinder[,c("start_Y", "end_Y")])
cylinder$center_Z <- rowMeans(cylinder[,c("start_Z", "end_Z")])
# create cylinders
cylinder_list <- list()
for (i in 1:nrow(cylinder)) {
cylinder_list[[i]] <- cylinder3d(
center = cbind(
c(cylinder$start_X[i], cylinder$end_X[i]),
c(cylinder$start_Y[i], cylinder$end_Y[i]),
c(cylinder$start_Z[i], cylinder$end_Z[i])),
radius = cylinder$radius[i],
closed = -2)
}
# plot cylinders
open3d()
par3d()
shade3d(shapelist3d(cylinder_list, plot = FALSE), col = "blue")
text3d(cylinder$center_X+0.5, cylinder$center_Y+0.5, cylinder$center_Z+0.5, cylinder$attribute, color="red")
# get attribute
nearby <- selectpoints3d(value=TRUE, button = "right")
nearby <- colMeans(nearby)
cylinder$dist <- sqrt(
(nearby["x"]-cylinder$center_X)**2 +
(nearby["y"]-cylinder$center_Y)**2 +
(nearby["z"]-cylinder$center_Z)**2)
cylinder$attribute[which.min(cylinder$dist)]
If you call selectpoints3d(value = FALSE), you get two columns. The first column is the id of the object that was found. Your cylinders get two ids each. One way to mark the cylinders is to use "tags". For example, this modification of your code:
# dummy data
cylinder <- data.frame(
start_X = rep(1:3, 2)*2,
start_Y = rep(1:2, each = 3)*2,
start_Z = 0,
end_X = rep(1:3, 2)*2 + round(runif(6, -1, 1), 2),
end_Y = rep(1:2, each = 3)*2 + round(runif(6, -1, 1), 2),
end_Z = 0.5,
radius = 0.25,
attribute = sample(letters[1:6], 6)
)
# calculate centers
cylinder$center_X <- rowMeans(cylinder[,c("start_X", "end_X")])
cylinder$center_Y <- rowMeans(cylinder[,c("start_Y", "end_Y")])
cylinder$center_Z <- rowMeans(cylinder[,c("start_Z", "end_Z")])
# create cylinders
cylinder_list <- list()
for (i in 1:nrow(cylinder)) {
cylinder_list[[i]] <- cylinder3d(
center = cbind(
c(cylinder$start_X[i], cylinder$end_X[i]),
c(cylinder$start_Y[i], cylinder$end_Y[i]),
c(cylinder$start_Z[i], cylinder$end_Z[i])),
radius = cylinder$radius[i],
closed = -2)
# Add tag here:
cylinder_list[[i]]$material$tag <- cylinder$attribute[i]
}
# plot cylinders
open3d()
par3d()
shade3d(shapelist3d(cylinder_list, plot = FALSE), col = "blue")
text3d(cylinder$center_X+0.5, cylinder$center_Y+0.5, cylinder$center_Z+0.5, cylinder$attribute, color="red")
# Don't get values, get the ids
nearby <- selectpoints3d(value=FALSE, button = "right", closest = FALSE)
ids <- nearby[, "id"]
# Convert them to tags. If you select one of the labels, you'll get
# a blank in the list of tags, because we didn't tag the text.
unique(tagged3d(id = ids))
When I was trying this, I found that using closest = TRUE in selectpoints3d seemed to get too many ids; there may be a bug there.
I want to plot a animated 3D scatterplot and save it as gif. I followed the code provided by the R Graph Gallery example: https://www.r-graph-gallery.com/3-r-animated-cube.html.
library(rgl)
library(magick)
options(rgl.printRglwidget = TRUE)
# Let's use the iris dataset
# iris
# This is ugly
colors <- c("royalblue1", "darkcyan", "oldlace")
iris$color <- colors[ as.numeric( as.factor(iris$Species) ) ]
# Static chart
plot3d( iris[,1], iris[,2], iris[,3], col = iris$color, type = "s", radius = .2 )
# We can indicate the axis and the rotation velocity
play3d( spin3d( axis = c(0, 0, 1), rpm = 20,dev = cur3d()),startTime = 0, duration = 10 )
# Save like gif
movie3d(
movie="3dAnimatedScatterplot",
spin3d( axis = c(0, 0, 1), rpm = 20,dev = cur3d()),
startTime = 0,
duration = 10,
dir = ".",
type = "gif",
clean = T,
fps=10,
convert=T
)
plot3d was successed output a 3d scatter plot.
Static 3d scatter plot
But the final output: 3dAnimatedScatterplot.gif,just a black image
3dAnimatedScatterplot.gif
when I set clean=F, all frame images are black. So, I guess the play3d() was not working.
Can anyone provide any help to me ? Thanks a lot !
Most likely snapshot3d isn't working for you. Try it with the option webshot = FALSE instead of the default webshot = TRUE. That uses a different mechanism for saving the image.
I am trying the create a plotly gauge graph for a flexdashboard which should change value depending on the chosen filter in crosstalk::filter_select().
I have tried and tried but cannot get the filter to work. This is an example with mtcars of what I am trying to do. I noticed that if the SharedData object has only one value, then it works, but otherwise plotly does not show any data.
mtcars_data <- tibble::rownames_to_column(mtcars, "Car")
shared_mtcars <- SharedData$new(mtcars_data)
row1 <- bscols(filter_select("Car", "Car", shared_mtcars, ~Car, multiple = F)
)
fig <- plot_ly(shared_mtcars,
domain = list(x = c(0, 1), y = c(0, 1)),
value = ~mpg,
title = list(text = "MPG"),
type = "indicator",
mode = "gauge+number")
bscols(row1, fig, widths = 12)
This code results in a graph with no data. If I subset mtcars_data to take the first row or the first two rows (which happen to have the same value for mpg) then it works. If I subset rows 1 and 3, it doesn't.
I might be missing something - in that case would really appreciate any feedback.
Follow up Heatmap question Creating a heatmap / ordering columns for yearly data in R
Heatmaply
Heatmaply2
The rownames change but my data does not change with this, can I ask for any help on how to have each respective row of data move with it's name?
Is there an easier way to make the graph / png wider as I have been messing around with the margins and all I seem to do is make it narrower.
I've attached a second image to show when I highlight a particular cell e.g. Skin Diseases in Jan a different value to what is in the .csv file, is this right? (Seeing as the colors match up should I just run with it?)
library(heatmaply)
x <-read.csv("Heatmap.csv", check.names = FALSE)
rownames(x) <- c('All Others', 'Circulatory Diseases', 'Digestive Diseases', 'Ear Diseases', 'Endocrine/Metabolic','Eye Diseases', 'Genitourinary Diseases', 'Ill-defined Condition', 'Infectious & Parasitic', 'Injury/ Poisoning', 'Mental & Behavioural', 'Musculoskeletal', 'Neoplasms', 'Nervous System', 'Pregnancy/Childbirth', 'Respiratory', 'Skin Diseases')
x <- x[,2:13, drop=FALSE]
x <- as.matrix(scale(x))
heatmaply(x,colors = heat.colors(200), k_col =1, k_row = 2, dendrogram = FALSE, margins = c(100, 160),
scale_fill_gradient_fun = ggplot2::scale_fill_gradient2(low = "blue", high = "red", midpoint = 50, limits = c(0, 100)))
I am trying to follow help and Internet examples to create a very simple animation of a 3d-line in R. This is just a test and my final goal is to use this functionality to visually verify results of some geometrical transformations on 3d-movement data that I am analysing. So basically I need nothing more than a ‘3d-player’ interface that allows for usual interaction (rotation, zoom, play, stop, slide).
I figured out that rgl package does the job and I am able to use it for the sphere/points animation. But now I need to use it on lines and I get very strange results. In the example below there are 4 points and two lines (cyan and red) that connect the same points but the red line is for some reason in the ‘wrong’ place. The animation doesn’t make sense neither. Now, I am thinking may be it is impossible to do >> to animate more than one vertex with more than one attribute? But I don’t see this in documentation and obviously it is possible because line is animated! I spent quite a long time trying to figure out what is going on and will appreciate any help/advise/directions. many thanks
Ps: Tthe code below is a chunk in the markdown file and I am using Rstudio.
require(rgl)
require(rglwidget)
p11=c(0,0,0)
p21=c(50,50,0)
p12=c(50,0,0)
p22=c(10,50,50)
saveopts <- options(rgl.useNULL = TRUE)
did=list()
did[[1]]=plot3d(rbind(p11,p21,p12,p22), type="s", alpha = 1, lwd = 5, col = c('brown','darkgreen','orange','green'))
did[[2]]=spheres3d(c(100,100,100), alpha = 1, lwd = 5, col = "blue",radius=2)
did[[3]]=lines3d(rbind(p11,p21),lwd=8, col='cyan',alpha=.9)
did[[4]]=planes3d(0, 0, 1, 0, alpha=.4, col='green')
did[[5]]=lines3d(rbind(p11,p21),lwd=2, col='red')
aspect3d(1, 1, 1)
did[[6]]=grid3d(c("x-", "z-"),at = NULL,col = "gray",lwd = .5,lty = 1,n = 5)
sceneT = rglwidget(elementId = "plot3dT",width=500, height=300) #%>%
rgl.ids()
rgl.attrib(id=did[[3]],attrib = c(1:length(did[[3]])))
playwidget(sceneT,list(
vertexControl(values = rbind(c(0,0,0,0,0,0),c(50,50,50,50,50,50)),
vertices = 1:6, attributes = "z", objid = did[[4]], param = 1:2,interp =T),
vertexControl(values = r1,
vertices = 1:2, attributes = c('x',"y","z",'x',"y","z"), objid = did[[5]], param = 1:2,interp =T)),
start = 1, stop = 2, step = .1, precision = 3)
options(saveopts)