Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scatter3d #30

Merged
merged 34 commits into from
Sep 30, 2022
Merged

Add scatter3d #30

merged 34 commits into from
Sep 30, 2022

Conversation

nvaytet
Copy link
Member

@nvaytet nvaytet commented Sep 26, 2022

Can now make 3d scatter plots using

import plopp as pp
import scipp as sc
import numpy as np

nclusters = 100
npercluster = 1000

position = np.zeros((nclusters, npercluster, 3))
values = np.zeros((nclusters, npercluster))

for n in range(nclusters):
    center = 500.0 * (np.random.random(3) - 0.5)
    r = 20.0 * np.random.normal(size=[npercluster, 3])
    position[n, :] = r + center
    values[n, :] = np.linalg.norm(r, axis=1) + n

da = sc.DataArray(
    data=sc.array(dims=['row'], values=values.flatten(), unit='K'),
    coords={
        'position': sc.vectors(dims=['row'], unit='m',
                               values=position.reshape(nclusters*npercluster, 3))
    })

pp.scatter3d(da, pos='position')

Screenshot at 2022-09-28 17-15-35

You can also use 3 separate coordinates instead of a vector3 coord:

time = np.linspace(0, 10, 50)
x = np.cos(time)
y = np.sin(time)

da = sc.DataArray(
    data=sc.array(dims=['row'], values=time),
    coords={
        'x': sc.array(dims=['row'], unit='m', values=x),
        'y': sc.array(dims=['row'], unit='m', values=y),
        'time': sc.array(dims=['row'], unit='s', values=time)
    })

pp.scatter3d(da, x='x', y='y', z='time', pixel_size=0.2)

Screenshot at 2022-09-28 17-17-42

Additional notes / things to check:

  • Camera buttons should work
  • Added tests for most things
  • Made common ColorMapper class for 2d images and 3d scatter plots
  • For now, Scene3d only makes PointClouds but in principle, it could accept more in the future? (meshes or other).

Fixes #13

@nvaytet nvaytet marked this pull request as draft September 26, 2022 21:13
@nvaytet nvaytet marked this pull request as ready for review September 28, 2022 15:14
@jl-wynen
Copy link
Member

The camera buttons in the first plot don't work exactly correctly. The camera is almost but not quite aligned with the axis you are looking along. This might just be a problem with numerical precision.

@nvaytet
Copy link
Member Author

nvaytet commented Sep 29, 2022

I think it might be because they are lining up with the center of the box, not the origin of the rgb axes. Because the data is random, the center of the box is close to zero but not exactly zero.

Copy link
Member

@jl-wynen jl-wynen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we make sure that plots look ok on different machines given that there are so many hard coded values. I assume, you picked them based on how things look on your machine?

@@ -1,3 +1,2 @@
matplotlib
pythreejs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this not needed here anymore?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the requirement to the docs.in. We decided pythreejs should be a soft requirement for plopp.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But isn't it needed in the tests as well? Are these requirement files meant for users as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point about the tests.... how did the CI even pass?

cam_pos_norm = np.linalg.norm(self.camera.position)
box_mean_size = np.linalg.norm(box_size)
self.camera.near = 0.01 * box_mean_size
self.camera.far = 5.0 * cam_pos_norm
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do these numbers come from?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same as in Scipp. It is 1% of the range spanned by the data for the near value. It's basically to say at what distance from the camera do the objects start to disappear, so it makes sense to have it as a fraction of the extent of the data points.
The same does for the far which means when objects start disappearing when they are far away.
Those numbers have worked well for Scipp users, I think.

dtype='float32'))
})

pixel_ratio = 1.0 # config['plot']['pixel_ratio']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a left over from debugging?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and no. There is no config in plopp yet. I didn't want to mess with the pixel_ratio just now, so I just set it to 1, and left the commented code as a reminder. I will change to a TODO.

self.geometry.attributes["color"].array = colors.astype('float32')

def _update_colorbar(self):
dpi = 96
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this interact with user chosen dpi for the rest of the figure?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no other dpi for the rest of the figure. Pythreejs uses pixels for figure size, no dpi.

def _get_cmap(name, nan_color=None):

try:
cmap = copy(cm.get_cmap(name))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as scipp/scipp#2824

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to match scipp

except ValueError:
cmap = LinearSegmentedColormap.from_list("tmp", [name, name])
# cmap.set_under(config['plot']['params']["under_color"])
# cmap.set_over(config['plot']['params']["over_color"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uncomment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, no config yet.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to a TODO

The name of the coordinate that is to be used for the Y positions.
z:
The name of the coordinate that is to be used for the Z positions.
dim:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dim is not a good name. Maybe coord?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, dim is not the best. Maybe pos, or positions, or vectors ?

@nvaytet nvaytet merged commit f948504 into main Sep 30, 2022
@nvaytet nvaytet deleted the add_scatter3d branch September 30, 2022 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add 3d scatter plots
2 participants