{"id":5779,"library":"laspy","title":"laspy","description":"Laspy is a native Python library for reading, modifying, and creating ASPRS LAS and LAZ (compressed) LIDAR files, supporting specifications 1.0 through 1.5. It provides a Pythonic API via NumPy arrays for efficient point cloud data manipulation. The library is actively maintained with frequent releases, typically several times a year.","status":"active","version":"2.7.0","language":"en","source_language":"en","source_url":"https://github.com/laspy/laspy","tags":["GIS","LiDAR","LAS","LAZ","point cloud","geospatial"],"install":[{"cmd":"pip install laspy","lang":"bash","label":"Base installation"},{"cmd":"pip install laspy[lazrs]","lang":"bash","label":"With LAZ/COPC support (lazrs backend, multi-threaded)"},{"cmd":"pip install laspy[laszip]","lang":"bash","label":"With LAZ support (laszip-python backend, supports waveforms)"},{"cmd":"pip install laspy[lazrs,laszip]","lang":"bash","label":"With both LAZ backends"},{"cmd":"pip install laspy[cli]","lang":"bash","label":"With command-line interface"}],"dependencies":[{"reason":"Core dependency for array-based point data manipulation.","package":"numpy","optional":false},{"reason":"Optional backend for LAZ compression/decompression, generally faster due to multi-threading. Required for COPC support.","package":"lazrs","optional":true},{"reason":"Optional backend for LAZ compression/decompression, official implementation, supports waveform data.","package":"laszip-python","optional":true},{"reason":"Optional, for Coordinate Reference System (CRS) / Spatial Reference System (SRS) handling.","package":"pyproj","optional":true},{"reason":"Optional, enables CopcReader to handle COPC files from HTTP servers.","package":"requests","optional":true},{"reason":"Required for the optional command-line interface (CLI) features.","package":"rich","optional":true},{"reason":"Required for the optional command-line interface (CLI) features.","package":"typer","optional":true}],"imports":[{"symbol":"laspy","correct":"import laspy"},{"note":"The `laspy.file.File` class was removed in `laspy` 2.0.0 and replaced with `laspy.read()` which returns a `LasData` object.","wrong":"from laspy.file import File; infile = File('file.las', mode='r')","symbol":"File","correct":"laspy.read('file.las')"}],"quickstart":{"code":"import laspy\nimport numpy as np\nimport os\n\n# Create a dummy LAS file for demonstration\nheader = laspy.LasHeader(point_format=3, version=\"1.4\")\nheader.offsets = np.array([0, 0, 0])\nheader.scales = np.array([0.01, 0.01, 0.01])\n\nlas_data = laspy.LasData(header)\n\nn_points = 100\nlas_data.x = np.random.rand(n_points) * 100\nlas_data.y = np.random.rand(n_points) * 100\nlas_data.z = np.random.rand(n_points) * 50\nlas_data.classification = np.random.randint(0, 5, n_points)\n\noutput_filename = \"output.las\"\nlas_data.write(output_filename)\nprint(f\"Created {output_filename} with {len(las_data.points)} points.\")\n\n# Read a LAS/LAZ file\ntry:\n    with laspy.open(output_filename) as fh:\n        print(f\"Reading {fh.header.point_count} points from {output_filename}\")\n        las = fh.read()\n\n        # Access point data (scaled and raw)\n        print(f\"X (scaled): {las.x[:5]}\") # Scaled coordinates\n        print(f\"X (raw): {las.X[:5]}\")   # Raw integer coordinates\n        print(f\"Classification: {las.classification[:5]}\")\n\n        # Access header information\n        print(f\"LAS Version: {las.header.version}\")\n        print(f\"Point Format ID: {las.header.point_format.id}\")\n        print(f\"Offset: {las.header.offsets}\")\n        print(f\"Scale: {las.header.scales}\")\n\n        # Filter points (e.g., classification == 2)\n        ground_points = las.points[las.classification == 2]\n        print(f\"Number of ground points (classification=2): {len(ground_points)}\")\n\n        # Create a new LAS file with filtered points\n        new_las = laspy.create(point_format=las.header.point_format, file_version=las.header.version)\n        new_las.points = ground_points\n        filtered_output_filename = \"filtered_output.las\"\n        new_las.write(filtered_output_filename)\n        print(f\"Created {filtered_output_filename} with {len(new_las.points)} filtered points.\")\n\nfinally:\n    # Clean up dummy files\n    if os.path.exists(output_filename):\n        os.remove(output_filename)\n    if os.path.exists(filtered_output_filename):\n        os.remove(filtered_output_filename)\n","lang":"python","description":"This quickstart demonstrates how to create a simple LAS file from scratch, read an existing LAS file using `laspy.open()` and `LasData.read()`, access point data and header attributes, and filter points. It also shows how to write new or modified `LasData` objects to a new file. Note the distinction between scaled (lowercase) and raw (uppercase) dimension access."},"warnings":[{"fix":"Migrate code to use `laspy.read()` for loading files into `LasData` objects or `laspy.open()` for chunked I/O. Access point data directly via `las_data.x` or `las_data.X` and header via `las_data.header`. Refer to the migration guide for detailed changes.","message":"laspy 2.0.0 introduced a significant API overhaul. The `laspy.file.File` class and its `open()` method were replaced by `laspy.read()` and `laspy.open()` returning `LasData` objects or readers/writers. Direct `get_*`/`set_*` methods on file objects were removed. The LAZ backend shifted from `lazperf` to `laszip-python` bindings or `lazrs`. Python 2.7 support was dropped.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Be mindful of which attribute (scaled or raw) you are accessing or modifying. For precise manipulation of raw values, use the uppercase attributes.","message":"When accessing point dimensions, `laspy` differentiates between scaled float values (lowercase attributes like `las.x`, `las.y`, `las.z`) and raw integer values (uppercase attributes like `las.X`, `las.Y`, `las.Z`). While both support assignment, assigning to scaled dimensions can introduce rounding errors.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Install with `pip install laspy[cli]` to enable CLI commands like `laspy info`, `laspy compress`, `laspy decompress`, `laspy convert`, and `laspy copc query`.","message":"The command-line interface (CLI) is an optional feature and requires additional dependencies (`rich` and `typer`). It must be installed using the `[cli]` extra.","severity":"gotcha","affected_versions":">=2.5.0"},{"fix":"Upgrade `laszip-python` and `lazrs` packages alongside `laspy` to their latest versions to ensure compatibility with LAS 1.5 and Python 3.14.","message":"Support for LAS 1.5 specification and Python 3.14 was added in version 2.7.0. Users relying on LAZ compression/decompression for these new features will need to ensure `laszip-python` and/or `lazrs` are updated to compatible versions.","severity":"breaking","affected_versions":">=2.7.0"},{"fix":"Always explicitly set `header.offsets` and `header.scales` when creating a new `LasHeader` for a new file. These values define how raw integer coordinates are converted to scaled float coordinates.","message":"When creating a new LAS file from scratch, it is crucial to properly initialize the `LasHeader` with appropriate `offsets` and `scales`. If not specified, default values may not be suitable for your data, or some software might not read the file correctly.","severity":"gotcha","affected_versions":">=2.0.0"}],"env_vars":null,"last_verified":"2026-04-14T00:00:00.000Z","next_check":"2026-07-13T00:00:00.000Z"}