Skip to main content
Yanked

This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 0.1.2 instead.
Reason given by maintainers: Viewer broken: bundled three.js core missing from the wheel. Use 0.1.2 or later.

planx-3d-city

PyPI version Python version support License: MIT Code style: Ruff

Turn GeoJSON, GeoDataFrames and DEMs into an interactive Three.js 3D city you can open in any browser.

📦 PyPI Package • 💻 GitHub • 🐛 Issue Tracker

planx-3d-city is the headless, QGIS-free counterpart of the PlanX 3D City QGIS plugin. It takes buildings (with heights or floor counts), roads, green areas, water, trees and an optional DEM, writes the scene data the PlanX viewer reads, and packages the viewer itself (three.js and every other library bundled, nothing loaded from a CDN) into a folder or ZIP that works offline and can be published on any static host.

The viewer gives you massing typologies, facade and roof materials, sun and shadow studies, sky view factor, viewsheds, wind screening, guided camera tours, street life, and export to CityJSON, 3D Tiles, glTF/GLB, PNG and MP4.

📦 Installation

# Core: NumPy is the only dependency
pip install planx-3d-city

# With the geospatial stack (GeoPandas, Shapely, rasterio, pyproj)
pip install "planx-3d-city[geo]"

# Development toolchain (pytest, pytest-cov, ruff, mypy)
pip install "planx-3d-city[dev]"

# Editable install from a clone
git clone https://github.com/YusufEminoglu/planx_3d_city_sdk.git
cd planx_3d_city_sdk
pip install -e ".[geo,dev]"

Requirements: Python 3.9+ on Windows, macOS or Linux. WGS84, Web Mercator and every UTM zone are handled in pure Python and plain GeoTIFFs are read and written with NumPy, so the core works without GDAL. Install [geo] to pass GeoDataFrames, use other CRSs (pyproj) or read other raster formats (rasterio).

⚡ Quickstart

import planx_3d_city as px

# A synthetic 600 m x 600 m city with terrain, blocks, buildings, roads, trees and a stream.
scene = px.sample_scene()
result = px.export_viewer(scene, "sample_city")
print(result.path)            # sample_city/ : src/, assets/, data/, serve.py, index.html ...

# Preview it on http://127.0.0.1:<port>/src/ (Ctrl+C to stop)
px.serve("sample_city")

Your own data

import planx_3d_city as px

scene = px.CityScene(title="Konak waterfront", asset_theme="Mediterranean")

# GeoJSON paths, dicts, GeoDataFrames, shapely geometries or feature lists all work.
# WGS84 input is projected to the local UTM zone automatically.
scene.add_buildings("buildings.geojson", height_field="HEIGHT_M", floors_field="KAT")
scene.add_layer("roads", "roads.geojson")
scene.add_layer("green", "parks.geojson")        # added to blocks, function=GREEN
scene.add_layer("water", "sea.geojson")          # added to blocks, function=WATER
scene.add_layer("waterlines", "streams.geojson")
scene.add_layer("trees", "trees.geojson")
scene.set_dem("dem.tif")                          # reprojected and cropped to the scene

scene.export("konak_viewer", zip_path="konak_viewer.zip")

With GeoPandas:

import geopandas as gpd
import planx_3d_city as px

gdf = gpd.read_file("buildings.gpkg")              # any CRS with an EPSG code
scene = px.CityScene(title="District").add_buildings(gdf, floors_field="floors")
px.export_viewer(scene, "district_viewer")

OpenStreetMap

import planx_3d_city as px

# (min_lon, min_lat, max_lon, max_lat); Overpass requests time out after timeout_s + 10 s.
osm = px.import_osm_bbox((27.125, 38.415, 27.140, 38.425), timeout_s=60)
print(osm.counts)                                  # {'buildings': ..., 'roads': ..., ...}
scene = osm.to_scene(title="Konak (OSM)")
px.export_viewer(scene, "konak_osm")

Areas are capped at 5 km on the longer side by default (max_km=) to keep requests to the shared Overpass service polite. OSM data is © OpenStreetMap contributors (ODbL).

🖥️ Command line

planx-3d-city info                                    # layer roles, themes, terrain modes
planx-3d-city sample my_city --serve                  # sample city, then open it
planx-3d-city export site --buildings b.geojson --roads r.geojson \
    --green parks.geojson --dem dem.tif --theme Mediterranean --zip site.zip
planx-3d-city osm konak --bbox 27.125,38.415,27.140,38.425 --timeout 60
planx-3d-city serve site --port 8080

export accepts one flag per layer role (--buildings, --roads, --blocks, --parcels, --trees, --waterlines, --lights, --benches, --busstops, ...), plus --green and --water, --dem, --plan-texture, --crs, --height-field, --floors-field, --title, --theme, --atmosphere, --terrain-mode and --tour. python -m planx_3d_city works the same way.

🧱 What gets written

my_city/
├── index.html                 redirects to src/?portable=1 (static hosting entry point)
├── serve.py                   launcher: free local port, no caching, opens the browser
├── Start-PlanX-Viewer.bat/.ps1
├── .nojekyll, .gitlab-ci.yml  GitHub Pages / GitLab Pages
├── src/                       the viewer app (ES modules)
├── assets/                    three.js r160, three-mesh-bvh, geotiff.js, mp4-muxer, textures
└── data/
    ├── planx_manifest.json    schema planx-3d-city-manifest/v1 (same as the QGIS plugin)
    ├── vector/*.geojson       one file per layer role, in one metric CRS
    ├── dem/mydem.tif          optional DEM (float32, DEFLATE)
    └── texture/siteplan.tif   optional draped plan texture

Browsers block JavaScript modules and fetch on file:// URLs, so serve the folder over HTTP (serve.py, planx-3d-city serve, or any static host) instead of double-clicking src/index.html. While served by PreviewServer, the viewer auto-saves your tuned settings to data/planx_scene_state.json, so a later export keeps the look.

🧭 Layer roles and attributes

Role Geometry Useful attributes
buildings Polygon height (m) or floors / building:levels; function; planx_color, planx_facade, planx_massing, planx_roof_shape
roads LineString highway / road_type, lanes, oneway, width
blocks Polygon function (PARK, GREEN, WATER, RESIDENTIAL, ...); aliases green, parks, water
roi Polygon study area; sets the scene extent
trees Point height
waterlines LineString width
parcels, hardscape, sidewalks, pedestrian_paths, bike_lanes, fences lines / polygons
lights, benches, trashbins, busstops, mosques, tumulus Point angle fields via options

Viewer options go to CityScene(**options) or scene.set_options(...): asset_theme, atmosphere_preset, topography_mode, day_of_year, latitude, dem_z_scale, tree_render_mode, zoning_max_height, building_floors_field, road_access_field, ...

🛠️ More examples

import planx_3d_city as px

# Population estimate on buildings (metric CRS)
fc = px.sample_layers()["buildings"]
print(px.calculate_building_gfa_and_population(fc, default_floors=4))

# Style selected buildings
px.apply_style(fc, {"planx_massing": "Podium Tower", "planx_color": "#d9c3a5"},
               lambda f: f["properties"]["floors"] >= 7)

# A DEM from a NumPy array
import numpy as np
z = np.random.default_rng(0).normal(50, 2, (200, 200)).astype("float32")
dem = px.RasterArray.from_bounds(z, (500000, 4500000, 500600, 4500600), crs="EPSG:32635")
scene = px.CityScene(crs="EPSG:32635").set_dem(dem)

# Package an existing QGIS-plugin export (web/data) with the bundled viewer
px.export_viewer("path/to/plugin/web", "portable_copy")

See examples/quickstart.py for a runnable script.

🧪 Development & testing

pip install -e ".[geo,dev]"
python -m pytest --cov=planx_3d_city
python -m ruff check .
python -m ruff format --check src tests
python -m mypy src
python -m build && python -m twine check --strict dist/*

📜 License

MIT © Yusuf Eminoğlu. The bundled JavaScript libraries are MIT-licensed; see THIRD_PARTY_LICENSES.md. If you use this software in research, please cite it using CITATION.cff.

Metadata

Release files for planx-3d-city 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for planx-3d-city 0.1.1
File Size Uploaded Provenance Actions
planx_3d_city-0.1.1.tar.gz 1.5 MB With provenance Details for planx_3d_city-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for planx-3d-city 0.1.1
File Interpreter ABI Platform Actions
planx_3d_city-0.1.1-py3-none-any.whl Python 3 none any Details for planx_3d_city-0.1.1-py3-none-any.whl

Total release size: 3.0 MB

Release files / planx_3d_city-0.1.1.tar.gz

Download URL planx_3d_city-0.1.1.tar.gz
Size 1.5 MB
Tags Source
SHA-256 checksum
How to use checksums
ce871f3a438a6bff6c9b7e7ecc5d756c85c852358e756f729b50ce4f1afa67fa
BLAKE2b-256 checksum
How to use checksums
c029d8ba3e272ea4b0af30f15ce02e956f5a84063022aef80ad4620c41e598cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

Release files / planx_3d_city-0.1.1-py3-none-any.whl

Download URL planx_3d_city-0.1.1-py3-none-any.whl
Size 1.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
d64632a6ab9748da78d97ac55aac428f574f35f259af4188b782e7528f75f9dc
BLAKE2b-256 checksum
How to use checksums
d3a13523248f29ddfef109ca37bed84a7ec5bb9f9df473b74eacfacf422fb353
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

Security for planx-3d-city 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for planx_3d_city-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page