Library / SDK
daavoo/pyntcloud avatar
daavoo/pyntcloud

pyntcloud: A PyntCloud Object Over pandas and the Scientific Stack

pyntcloud is a Python library for working with 3D point clouds.

1,503 stars229 forksPythonMIT

At a glance

What is it?
pyntcloud wraps point cloud IO, scalar field derivation, voxel structures and sampling behind a single PyntCloud class. It is a small, MIT-licensed library whose last tagged release is v0.3.1 from July 2022, so adopt it for the operations it documents and verify the rest yourself.
Who is it for?
Adopt pyntcloud if you have a PLY or NPZ point cloud and want voxel downsampling, RGB to HSV conversion or a quick Open3D and PyVista round trip without writing the plumbing yourself, and if you are willing to pin the version and read the source when a method is undocumented. Do not adopt it if you need a maintained triangulation or normal estimation pipeline, or if you expect the release cadence to track Open3D.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 68 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap pyntcloud fills between raw numpy arrays and a full 3D framework

A point cloud in Python is usually just an N by 3 float array, and that is also the problem. Once you load a PLY you have coordinates and possibly colour, normals and intensity, and every downstream step (converting colour spaces, binning into voxels, subsampling) means writing index arithmetic that has nothing to do with the question you are trying to answer. pyntcloud's stated purpose is to make point clouds fun again, and the shape of the library reflects that: one core class, PyntCloud, and a set of named operations you call on it. The intended audience is someone working in the Python scientific stack who already has numpy and pandas in the environment and wants point cloud handling to look like the rest of their code. It is not a renderer and not a deep learning framework, despite the 3d-deep-learning and deep-learning topics on the repository. The README lists examples, a ReadTheDocs site and a pip install, and that is the whole surface it advertises.

What the PyntCloud object actually holds and how fields and structures differ

The design separates two kinds of state. Scalar fields are per-point columns: the README's example calls cloud.add_scalar_field("hsv") to add three new fields derived from the existing RGB values. Structures are not per-point at all. The call cloud.add_structure("voxelgrid", n_x=32, n_y=32, n_z=32) returns an identifier, voxelgrid_id, which is a handle to a derived object rather than a column on the cloud. That distinction matters because it is what lets get_sample take a structure and a sampling rule and produce a new cloud: cloud.get_sample("voxelgrid_nearest", voxelgrid_id=voxelgrid_id, as_PyntCloud=True) keeps the nearest point to each occupied voxel centre. So the data flow in the documented example is file, then scalar fields, then a structure, then a sample, then a file. The as_PyntCloud=True flag is the part worth noticing: without it you are presumably getting a plainer result, and the README only shows the PyntCloud-returning form. The voxelgrid_nearest rule is a decimation, not a resampling of the geometry. It selects existing points, so the output is a subset of the input, and the density of the result depends on how many voxels were occupied rather than on n_x, n_y, n_z directly.

Getting it running: install, load, derive, voxelise, sample, write

Installation is a single command, pip install pyntcloud. The README gives one end-to-end example, and it is worth reproducing the keys rather than paraphrasing them. You start with from pyntcloud import PyntCloud, then cloud = PyntCloud.from_file("some_file.ply"). The scalar field call is cloud.add_scalar_field("hsv"), which the README describes as converting RGB to HSV and adding three new scalar fields. The structure call is cloud.add_structure("voxelgrid", n_x=32, n_y=32, n_z=32), and the three arguments are the voxel counts along each axis, so the grid is defined in index space, not in world units. The sample call is cloud.get_sample("voxelgrid_nearest", voxelgrid_id=voxelgrid_id, as_PyntCloud=True). Writing is new_cloud.to_file("out_file.npz"), and the README explicitly frames NPZ as numpy's format. For interop, the pattern is PyntCloud.from_instance("open3d", original_triangle_mesh) to come in from Open3D and cloud.to_instance("open3d", mesh=True) to go out, with the same shape for PyVista. The README notes that mesh=True is the default on to_instance. What the README does not give is the full list of accepted strings for add_scalar_field, add_structure or get_sample. Those names are the API, and you will be reading the documentation site or the source to find the rest.

The release history is the main thing to weigh before committing

The most recent tagged release is v0.3.1 from 31 July 2022. Before that, v0.3.0 in May 2022 is labelled Use laspy 2.0, and v0.2.0 in April 2022. Three releases inside roughly three months, then a long gap to the present, with repository activity continuing into 2026 according to the last push timestamp. That combination is common in research-adjacent tooling and it has a practical consequence: the released artifact and the default branch may not be the same code. If you pip install pyntcloud you get the tagged release, and if a behaviour you read about on the default branch is not in that tag, the install will not have it. The laspy 2.0 note is a reminder that a dependency bump was itself a release event, which tells you the library sits on top of other packages whose own major versions move. MIT licensing is permissive and imposes no copyleft obligation on your code, but it also means no warranty, and the licence says nothing about the maintenance question. None of this is a reason to avoid the library. It is a reason to pin the version in your requirements file and to treat the documentation site as the reference rather than assuming the API is stable across minor versions.

Where pyntcloud is the wrong tool

The documented operations are loading, scalar field derivation, voxel structures, voxel-based sampling and format conversion. Anything outside that set is not covered by the material here, and it would be a mistake to assume it exists. If your pipeline needs surface reconstruction, normal estimation or registration, you are looking at Open3D's own algorithms, and pyntcloud's role shrinks to moving data in and out through from_instance and to_instance. There is a subtler failure mode in the voxel path. The grid is specified as n_x, n_y, n_z, which is a count of cells, so the effective cell size is the bounding box extent divided by that count. Two clouds with the same n_x, n_y, n_z but different extents produce different physical resolutions, and a cloud with a few distant outliers will have its bounding box stretched, making the occupied cells coarse for the dense region. The README does not describe an origin or cell-size parameter for add_structure, so if you need a fixed metric voxel size you will have to check the source for whether one exists. The nearest-point rule has a related property: it never averages or interpolates, so it cannot smooth noise, and it can drop a thin feature entirely if no voxel centre happens to claim it.

Open3D and PyVista as the comparison, and what the conversion costs

The honest alternative for most of this work is Open3D, and the difference is one of scope rather than quality. Open3D is the library pyntcloud converts to and from, and the README shows the triangle mesh path in both directions: o3d.io.read_triangle_mesh("diamond.ply") into PyntCloud.from_instance("open3d", original_triangle_mesh), and back out with cloud.to_instance("open3d", mesh=True). Open3D brings its own IO, its own geometry types and its own algorithms; pyntcloud brings a pandas-shaped table of points with named operations on it. If you are already inside Open3D, adding pyntcloud to the stack means a conversion step in each direction and two representations of the same data to keep straight. PyVista occupies a third position: it is built around visualisation and mesh structures, and the README's PyVista example uses pv.read("diamond.ply") and then the same from_instance and to_instance pattern with mesh=True. The mesh=True default is the detail to watch. A point cloud converted to a mesh is a different object with different guarantees, and the README does not state what triangulation is used or what happens for a cloud with no connectivity. Choose based on which representation you want to live in, not on which library has more features, because the conversion boundary is where the surprises are.

Editorial conclusion

Adopt pyntcloud if you have a PLY or NPZ point cloud and want voxel downsampling, RGB to HSV conversion or a quick Open3D and PyVista round trip without writing the plumbing yourself, and if you are willing to pin the version and read the source when a method is undocumented. Do not adopt it if you need a maintained triangulation or normal estimation pipeline, or if you expect the release cadence to track Open3D. Verify first that PyntCloud.from_file returns the fields you expect for your own file, that add_structure with n_x, n_y, n_z gives a voxel count you can afford in memory, and that get_sample with voxelgrid_nearest returns the point count you need.

Official sources

  1. daavoo/pyntcloud on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes