pyvista-miniply 0.5.2


pip install pyvista-miniply

  Latest version

Released: Sep 03, 2026

Project Links

Meta
Author: PyVista Developers
Requires Python: >=3.10

Classifiers

License
  • OSI Approved :: MIT License

Operating System
  • Microsoft :: Windows
  • POSIX

Intended Audience
  • Science/Research

Programming Language
  • Python :: 3.10
  • Python :: 3.11
  • Python :: 3.12
  • Python :: 3.13
  • Python :: 3.14

pypi MIT

pyvista-miniply is a Python library for rapidly reading PLY files. It is a Python wrapper around the fast C++ PLY reading library provided by miniply. Thanks @vilya!

The main advantage of pyvista-miniply over other PLY reading libraries is its performance. See the benchmarks below for more details.

Installation

The recommended way to install pyvista-miniply is via PyPI:

pip install pyvista-miniply

Optionally with PyVista:

pip install pyvista-miniply[pyvista]

You can also clone the repository and install it from source:

git clone https://github.com/pyvista/pyvista-miniply.git
cd pyvista-miniply
git submodule update --init --recursive
pip install .

Usage

Load in the vertices, indices, normals, UV, and color information from a PLY file:

>>> import pyvista_miniply
>>> vertices, indices, normals, uv, color = pyvista_miniply.read("example.ply")
>>> vertices
array([[ 5.0000000e-01, -5.0000000e-01, -5.5511151e-17],
       [ 4.0000001e-01, -5.0000000e-01, -4.4408922e-17],
       [ 3.0000001e-01, -5.0000000e-01, -3.3306692e-17],
       ...,
       [-4.2500001e-01,  5.0000000e-01,  4.7184480e-17],
       [-4.7499999e-01,  4.4999999e-01,  5.2735593e-17],
       [-5.0000000e-01,  4.2500001e-01,  5.5511151e-17]], dtype=float32)
>>> indices
array([[   0,  442,  441],
       [ 442,  122,  443],
       [ 443,  121,  441],
       ...,
       [1677,  438, 1679],
       [1679,  439, 1676],
       [1677, 1679, 1676]], dtype=int32)
>>> normals
array([[-1.110223e-16,  0.000000e+00, -1.000000e+00],
       [-1.110223e-16,  0.000000e+00, -1.000000e+00],
       [-1.110223e-16,  0.000000e+00, -1.000000e+00],
       ...,
       [-1.110223e-16,  0.000000e+00, -1.000000e+00],
       [-1.110223e-16,  0.000000e+00, -1.000000e+00],
       [-1.110223e-16,  0.000000e+00, -1.000000e+00]], dtype=float32)
>>> uv
array([[0.        , 0.        ],
       [0.1       , 0.        ],
       [0.2       , 0.        ],
       ...,
       [0.92499995, 1.        ],
       [0.975     , 0.95      ],
       [1.        , 0.92499995]], dtype=float32)
>>> color
array([[  0,   0,   0],
       [  0,   0,   0],
       [  0,   0,   0],
       ...,
       [254, 254, 254],
       [254, 254, 254],
       [255, 255, 255]], dtype=uint8)

You can also read in the PLY file as a PyVista PolyData and immediately plot it.

 >>> import pyvista_miniply
 >>> mesh = pyvista_miniply.read_as_mesh("example.ply")
 >>> mesh
 PolyData (0x7f0653579c00)
   N Cells:    200
   N Points:   121
   N Strips:   0
   X Bounds:   -5.000e-01, 5.000e-01
   Y Bounds:   -5.000e-01, 5.000e-01
   Z Bounds:   -5.551e-17, 5.551e-17
   N Arrays:   2

>>> mesh.plot()
https://github.com/pyvista/pyvista-miniply/raw/main/demo.png

When pyvista-miniply is installed alongside pyvista >= 0.49, pyvista.read automatically dispatches .ply files through pyvista-miniply via the pyvista.readers.override entry point, no manual registration is required:

>>> import pyvista as pv
>>> mesh = pv.read("example.ply")  # now powered by pyvista-miniply

PyVista reads .ply natively, so this entry point replaces a built-in reader and is declared in the pyvista.readers.override group, which states that intent. On pyvista 0.48 the group is unknown and ignored: pyvista.read keeps using the built-in PLY reader, and pyvista_miniply.read_as_mesh can still be called directly.

Benchmark

The main reason behind writing yet another PLY file reader for Python is to leverage the highly performant miniply library.

There is already a benchmark demonstrating how miniply outperforms in comparison to competing C and C++ libraries at ply_io_benchmark when reading PLY files. The benchmark here shows how pyvista-miniply performs relative to other Python PLY file readers.

Here are the timings from reading in a 1,000,000 point binary PLY file on an Intel i9-14900KF:

Library

Time (seconds)

pyvista-miniply

0.027

open3d

0.102

PyVista (VTK)

0.214

meshio

0.249

plyfile

4.039

Benchmark source:

import time
from timeit import timeit

import numpy as np
import pyvista as pv
import pyvista_miniply
import plyfile
import meshio
import open3d

number = 10

filename = "tmp.ply"
mesh = pv.Plane(i_resolution=999, j_resolution=999).triangulate()
mesh.clear_data()
mesh.save(filename)

telap = timeit(lambda: pyvista_miniply.read(filename), number=number)
print(f"pyvista_miniply: {telap/number:.3f}")

telap = timeit(lambda: open3d.io.read_point_cloud(filename), number=number)
print(f"open3d:          {telap/number:.3f}")

telap = timeit(lambda: pv.read(filename), number=number)
print(f"VTK/PyVista:     {telap/number:.3f}")

telap = timeit(lambda: meshio.read(filename), number=number)
print(f"meshio:          {telap/number:.3f}")

# plyfile
number = 3  # less because it takes a while
telap = timeit(lambda: plyfile.PlyData.read(filename), number=number)
print(f"plyfile:         {telap/number:.3f}")

Comparison with VTK and PyVista

Here’s an additional benchmark comparing VTK/PyVista with pyvista-miniply:

import numpy as np
import time
import pyvista as pv
import matplotlib.pyplot as plt
import pyvista_miniply

times = []
filename = 'tmp.ply'
for res in range(50, 800, 50):
    mesh = pv.Plane(i_resolution=res, j_resolution=res).triangulate().subdivide(2)
    mesh.clear_data()
    mesh.save(filename)

    tstart = time.time()
    pv_mesh = pv.read(filename)
    vtk_time = time.time() - tstart

    tstart = time.time()
    ply_mesh = pyvista_miniply.read_as_mesh(filename)
    ply_reader_time =  time.time() - tstart

    assert np.allclose(pv_mesh['Normals'], ply_mesh['Normals'])
    assert np.allclose(pv_mesh.points, ply_mesh.points)
    assert np.allclose(pv_mesh._connectivity_array, ply_mesh._connectivity_array)

    times.append([mesh.n_points, vtk_time, ply_reader_time])
    print(times[-1])


times = np.array(times)
plt.figure(1)
plt.title('PLY load time')
plt.plot(times[:, 0], times[:, 1], label='VTK')
plt.plot(times[:, 0], times[:, 2], label='pyvista-miniply')
plt.xlabel('Number of Points')
plt.ylabel('Time to Load (seconds)')
plt.legend()

plt.figure(2)
plt.title('PLY load time (Log-Log)')
plt.loglog(times[:, 0], times[:, 1], label='VTK')
plt.loglog(times[:, 0], times[:, 2], label='pyvista-miniply')
plt.xlabel('Number of Points')
plt.ylabel('Time to Load (seconds)')
plt.legend()
plt.show()
https://github.com/pyvista/pyvista-miniply/raw/main/bench0.png https://github.com/pyvista/pyvista-miniply/raw/main/bench1.png

License and Acknowledgments

This project relies on miniply and credit goes to the original author for the excellent C++ library. That work is licensed under the MIT License.

The work in this repository is also licensed under the MIT License.

Support

If you are having issues, please feel free to raise an Issue.

Extras:
Dependencies:
numpy