rmaia / pavo

tools for the analysis of color data in R
http://pavo.colrverse.com
GNU General Public License v2.0
69 stars 17 forks source link

Add 2D marginal projections to 3D plots #118

Open Bisaloo opened 6 years ago

Bisaloo commented 6 years ago

Basically, implement the following R+python code in pure R.

Output:

tetra_margins

Rmarkdown code --- title: "Tetrahedron with 2D projections" author: "Hugo Gruson" date: "August 7, 2018" output: html_document --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, engine.path = '/usr/bin/python3') library(reticulate) use_python("/usr/bin/python3") ``` ```{r} library(pavo) data(flowers) vis_flowers = vismodel(flowers) tcs_flowers = colspace(vis_flowers) ``` ```{r} tetraplot(tcs_flowers) ``` ```{r} u = data.frame(x = 0 , y = 0 , z = 3/4) s = data.frame(x = -sqrt(3/2)/2, y = -1/(2*sqrt(2)), z = -1/4) m = data.frame(x = 0 , y = 1/sqrt(2) , z = -1/4) l = data.frame(x = sqrt(3/2)/2, y = -1/(2*sqrt(2)), z = -1/4) verts = rbind(u, s, m, l, u, m, u, s, l) rownames(verts) = NULL verts = as.data.frame(verts) ``` ```{python} from mpl_toolkits.mplot3d import Axes3D import matplotlib.pylab as plt import pandas as pd fig = plt.figure() ax = fig.gca(projection = '3d') ax.scatter(r.tcs_flowers["x"], r.tcs_flowers["y"], r.tcs_flowers["z"]) ax.plot(r.tcs_flowers["x"], r.tcs_flowers["z"], 'r.', zdir = "y", zs = 1) ax.plot(r.tcs_flowers["x"], r.tcs_flowers["y"], "k.", zdir = "z", zs = -0.5) ax.plot(r.tcs_flowers["y"], r.tcs_flowers["z"], "g.", zdir = "x", zs = -1) ax.plot(r.verts["x"], r.verts["y"], r.verts["z"]) plt.show() plt.savefig("tetra_margins.png") ```
Bisaloo commented 6 years ago

I figured out how to do this in pure R. I'm currently adding this feature to tetraplot. I couldn't find anything in the git repo about why we use persp/perspbox instead of high level functions such as scatter3D and lines3D. Is there a reason? Do you remember?

thomased commented 6 years ago

Yeah I'm fairly certain it used to be scatter3d etc. based (around ~Sep last year), but Raf rewrote it to fix various issues with perspectives & flexibility, that I can't quite recall. Maybe just hold off on the rewrite for a sec, until he's back in town.

Bisaloo commented 6 years ago

Okay, found it: https://github.com/rmaia/pavo/commit/491e5a777d8d8338018720ddb9844b5acf913aa6

My guess is that he indeed changed to be able to implement the perspective argument. I haven't thought about it much for the moment but it may indeed be impossible with high level functions.

rmaia commented 6 years ago

IIRC we changed fromscatterplot3d to persp so we could have better control of plotting attributes (like being able to plot the lines of the tetrahedron in front of the points according to perspective). To do that, we needed to make the plot but not plot any of the image components yet, just to get the perspective transformations, and then add elements one by one (according to how "far behind" they were). If memory serves, scatterplot3d had some janky controls that would plot an empty figure regardless and close the connection - so if you were, for example, making a multi-panel image or saving a pdf, you'd always end up with this blank panel.

We chose to use persp because it did what we needed and was part of the graphics package, and doesn't bring an additional dependency and all its child dependencies. I'm open to alternatives but generally try to minimize how much is frontloaded with the package.

Also have you checked out the type = "l" argument in tetraplot? I think it does something that relies on a projection of the points on the XY plane, maybe that could be a starting point.

Bisaloo commented 6 years ago

Maybe that wasn't the case before but scatter3D and its relative (lines3D etc.) have a add switch that works pretty well. In #119, I managed to pretty much emulate the current behaviour of tetraplot but using scatter3D and lines3D, which makes the code so much easier and intuitive. persp and perspbox are good for fine control but quite hard to work with (good job btw) so if we can avoid them, that'd be good IMO.

As I said, my main concern is the perspective arg in tetraplot. I didn't reproduce its functionality yet in #119 and that may be the tricky part.

We chose to use persp because it did what we needed and was part of the graphics package, and doesn't bring an additional dependency and all its child dependencies. I'm open to alternatives but generally try to minimize how much is frontloaded with the package.

scatter3D and lines3D are both in the same package as persp and perspbox, so no additional dependencies.

Also have you checked out the type = "l" argument in tetraplot? I think it does something that relies on a projection of the points on the XY plane, maybe that could be a starting point.

I had a look but it only works for default values of phi and theta

Bisaloo commented 6 years ago

I think the best way would be for me to finish #119 so you can see if that's okay with you. It's almost ready anyways so it doesn't matter much if I put a bit more time in it even if we end up closing it without merging.

rmaia commented 6 years ago

I thought persp is in graphics (built in) while scatter3D was in plot3D which has a bunch of dependencies? Anyway tetraplot is pretty clunky and ripe for an overhaul so I trust your judgement and am open to changing it!

Bisaloo commented 6 years ago

I thought persp is in graphics (built in) while scatter3D was in plot3D which has a bunch of dependencies?

Oh, you're right. Yet, for some reason, we are already importing plot3D.

rmaia commented 6 years ago

Oh, you're right. Yet, for some reason, we are already importing plot3D.

whoops. you're right. perspbox is from plot3d. That makes the decision a lot easier! :)

Bisaloo commented 6 years ago

Hum, okay, it doesn't look possible to reproduce the perspective feature using only high-level functions. I'll try to amend my PR to just add the marginal projections and not touch the rest.