cityjson / cjio Goto Github PK
View Code? Open in Web Editor NEWCityJSON/io: Python CLI to process and manipulate CityJSON files
License: MIT License
CityJSON/io: Python CLI to process and manipulate CityJSON files
License: MIT License
While trying to export a file (attached here) from .json to .obj, I got the following warning:
RuntimeWarning: invalid value encountered in true_divide
n = n / sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2])
helsinki_lod1.json.zip
because there is no "lod" property for those.
many would put "version": "1.0.1"
better error should be returned
Convert the cityjson into gltf
CJIO does not validate files in which LOD are not numbers but strings. Integers and floats are ok.
Accordingly to this issue on the CityJSON Github, it should validate it.
Using cjio version 0.5.5.
When I try to export into .obj file:
cjio tudelft_campus.json export tudelft_campus.obj
I get this error message:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.6/bin/cjio", line 11, in
load_entry_point('cjio==0.5.5', 'console_scripts', 'cjio')()
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/click/core.py", line 764, in call
return self.main(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/click/core.py", line 1164, in invoke
return _process_result(rv)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/click/core.py", line 1102, in _process_result
**ctx.params)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cjio/cjio.py", line 92, in process_pipeline
cm = processor(cm)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cjio/cjio.py", line 254, in processor
if format.lower() == '3dtiles' or not isinstance(cm, list):
AttributeError: 'NoneType' object has no attribute 'lower'
Am I doing something wrong?
tudelft_campus_subsetEWI_Building.json.zip
Thank you!
When you partition a dataset the output partitioned datasets don't have a reference system defined.
$ cjio /data/citymodels/Zurich/Building_LoD2_V10.json subset --bbox 2681133 1246440 2682862 1247462 save example_data/zurich_subset.json
Parsing /data/citymodels/Zurich/Building_LoD2_V10.json
Subset of CityJSON
Traceback (most recent call last):
File "/home/balazs/.local/share/virtualenvs/cjio-xu4bWm9P/bin/cjio", line 11, in <module>
load_entry_point('cjio', 'console_scripts', 'cjio')()
File "/home/balazs/.local/share/virtualenvs/cjio-xu4bWm9P/lib/python3.6/site-packages/click/core.py", line 764, in __call__
return self.main(*args, **kwargs)
File "/home/balazs/.local/share/virtualenvs/cjio-xu4bWm9P/lib/python3.6/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/home/balazs/.local/share/virtualenvs/cjio-xu4bWm9P/lib/python3.6/site-packages/click/core.py", line 1164, in invoke
return _process_result(rv)
File "/home/balazs/.local/share/virtualenvs/cjio-xu4bWm9P/lib/python3.6/site-packages/click/core.py", line 1102, in _process_result
**ctx.params)
File "/home/balazs/.local/share/virtualenvs/cjio-xu4bWm9P/lib/python3.6/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/home/balazs/Development/cjio/cjio/cjio.py", line 92, in process_pipeline
cm = processor(cm)
File "/home/balazs/Development/cjio/cjio/cjio.py", line 468, in processor
s = s.get_subset_bbox(bbox, exclude=exclude)
File "/home/balazs/Development/cjio/cjio/cityjson.py", line 606, in get_subset_bbox
re.add(self.j['CityObjects'][each])
TypeError: unhashable type: 'dict'
Also export the relevant texture files when subseting a file. The texture files are then saved into the <output file name>_textures
folder in the same directory as the output file.
like compress(), so that the duplicates can be controlled
I've installed via 'pip3 cjio'
cjio test.json export test.obj
Parsing test.json
OBJ export skipped: Python module 'mapbox_earcut' missing (to triangulate faces)
Install it: https://github.com/skogler/mapbox_earcut_python
Might be related to this error as well.
cjio test.json remove_textures export test.obj
Parsing test.json
Remove all textures
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/bin/cjio", line 8, in
sys.exit(cli())
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 764, in call
return self.main(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 1164, in invoke
return _process_result(rv)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 1102, in _process_result
**ctx.params)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/cjio/cjio.py", line 96, in process_pipeline
cm = processor(cm)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/cjio/cjio.py", line 406, in processor
cm.remove_textures()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/cjio/cityjson.py", line 839, in remove_textures
if self.j["appearance"] is None or len(self.j["appearance"]) == 0:
KeyError: 'appearance'
When running merge you always get the info of the first file. So in this case:
cjio random10_1.json merge random10_2.json info
the result is:
{
"cityjson_version": "1.0",
...
"cityobjects_total": 10,
...
}
{
"cityjson_version": "1.0",
...
"cityobjects_total": 20,
...
}
and in this case:
cjio random10_1.json merge random10_2.json save merged.json
the result is:
{
"cityjson_version": "1.0",
...
"cityobjects_total": 10,
...
}
So my question is whether there is any point in having the info of the first file in the output? In the first case it looks messy and redundant and in the second case it makes it look like the merge was unsuccessful, which was not the case.
Right now it doesn't merge 2 CO having the same ID. But in practice say we have 2 datasets with the same objects, one is LoD1 and the other LoD2, and we would like to merge them into the same dataset.
So a smarter merge is necessary.
Analysing the geom for duplicates is probably out of scope, but just different LoD1 would help.
Currently validate
only prints that the file is invalid and prints the whole cityobject. It would be better to show why is the file invalid. Same is true for warnings.
Some software quietly adds a BOM to a file. While this is illegal in the JSON specs, the truth is it still happens a lot with JSON files. The consequence here is it causes cjio to crash. I got the error:
Error: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column 1 (char 0)
Perhaps, it's better to flag it as an issue but not to crash? That's what the R library jsonlite does for example, it ignores the BOM and warns but continues.
When running
cjio no_bld.json merge buildings.json save LOD2.json
I get the following error;
Parsing no_bld.json
v0.6 is not the latest version, and not everything will work.
Upgrade the file with 'upgrade_version' command: 'cjio input.json upgrade_version save out.json'
Merging files
{
"cityjson_version": "0.6",
"epsg": null,
"extensions": false,
"cityobjects_total": 214,
"cityobjects_present": [
"Building"
],
"vertices_total": 13766,
"transform/compressed": true,
"geom_primitives_present": [
"MultiSurface"
],
"materials": false,
"textures": true
}
Traceback (most recent call last):
File "C:\OSGeo4W64\apps\Python36\lib\runpy.py", line 193, in _run_module_as_main
"main", mod_spec)
File "C:\OSGeo4W64\apps\Python36\lib\runpy.py", line 85, in run_code
exec(code, run_globals)
File "C:\OSGeo4W64\apps\Python36\Scripts\cjio.exe_main.py", line 9, in
File "C:\OSGeo4W64\apps\Python36\lib\site-packages\click\core.py", line 764, in call
return self.main(*args, **kwargs)
File "C:\OSGeo4W64\apps\Python36\lib\site-packages\click\core.py", line 717, in main
rv = self.invoke(ctx)
File "C:\OSGeo4W64\apps\Python36\lib\site-packages\click\core.py", line 1164, in invoke
return _process_result(rv)
File "C:\OSGeo4W64\apps\Python36\lib\site-packages\click\core.py", line 1102, in _process_result
**ctx.params)
File "C:\OSGeo4W64\apps\Python36\lib\site-packages\click\core.py", line 555, in invoke
return callback(*args, **kwargs)
File "C:\OSGeo4W64\apps\Python36\lib\site-packages\cjio\cjio.py", line 96, in process_pipeline
cm = processor(cm)
File "C:\OSGeo4W64\apps\Python36\lib\site-packages\cjio\cjio.py", line 265, in processor
cm.merge(lsCMs)
File "C:\OSGeo4W64\apps\Python36\lib\site-packages\cjio\cityjson.py", line 997, in merge
self.j["appearance"]["vertices-texture"] += cm.j["appearance"]["vertices-texture"]
TypeError: unsupported operand type(s) for +=: 'dict' and 'list'
$ cjio info.json subset --cotype Building,TINRelief,Road info
From #23
@cfrank0214 could you please attach the test.json
file to a reply so we can take a look? You'll probably need to zip it first.
cjio test.json remove_textures export test.obj
Parsing test.json
Remove all textures
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/bin/cjio", line 8, in
sys.exit(cli())
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 764, in call
return self.main(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 717, in main
rv = self.invoke(ctx)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 1164, in invoke
return _process_result(rv)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 1102, in _process_result
**ctx.params)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/click/core.py", line 555, in invoke
return callback(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/cjio/cjio.py", line 96, in process_pipeline
cm = processor(cm)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/cjio/cjio.py", line 406, in processor
cm.remove_textures()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/cjio/cityjson.py", line 839, in remove_textures
if self.j["appearance"] is None or len(self.j["appearance"]) == 0:
KeyError: 'appearance'
Works the same way as the semantics but at the moment the materials are ignored.
Validating MultiSolids msolid_buildings.zip fails with the vague 'is not valid under any of the given schemas'
error. val3dity does validate the same file (although the geometry is invalid).
The same file as CompositeSolid (replaced MultiSolid to CompositeSolid) validates with cjio.
csolid_buildings.zip
The MultiSolids were made by hand from MultiSurfaces of the attached file in #36
cjio_dbexport has a Travis build+deploy setup, we can use the same. Having a single file executable could help a lot in adoption, since the user doesn't even need to have python installed. For linux, mac, windows
This file is converted to invalid glb when using the develop branch
DenHaag_01.zip
It crashes cjio for @hugoledoux .
Conversion with CityJSON2glTF works.
Use http://github.khronos.org/glTF-Validator/ for validation.
Tested by test_vertex_indexer
in 08cbd05
In order to overcome #32 , the output of validate() needs to be parsed when using the API.
The idea is to keep the core minimal and ideally using only the standard library. This makes it much much more easy to integrate cjio with other libraries,apps. Extra/interface functions eg. format conversion, reprojection would go into plugins and the user would only install what they exactly need. What do you think @hugoledoux ?
Evaluate if using gc.collect()
after reading cityjson files helps with performace. Particulary with large files.
I'm trying to convert CityJSON to glb with cjio version 0.6.
I've tried to convert the sampe dataset Neighbourhood 'Delfshaven'. Buildings in LoD2
The command:
cjio 3-20-DELFSHAVEN.json export --format glb 3-20-DELFSHAVEN.glb
produces
Parsing 3-20-DELFSHAVEN.json
Exporting CityJSON to glb /home/mattes/vmware/share/Daten/LOD2/3-20-DELFSHAVEN.glb
/home/mattes/.local/lib/python3.8/site-packages/cjio/geom_help.py:39: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
if((n==x3).all()):
Traceback (most recent call last):
File "/home/mattes/.local/bin/cjio", line 11, in <module>
load_entry_point('cjio==0.6', 'console_scripts', 'cjio')()
File "/home/mattes/.local/lib/python3.8/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/home/mattes/.local/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/mattes/.local/lib/python3.8/site-packages/click/core.py", line 1290, in invoke
return _process_result(rv)
File "/home/mattes/.local/lib/python3.8/site-packages/click/core.py", line 1224, in _process_result
value = ctx.invoke(self.result_callback, value, **ctx.params)
File "/home/mattes/.local/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/mattes/.local/lib/python3.8/site-packages/cjio/cjio.py", line 103, in process_pipeline
cm = processor(cm)
File "/home/mattes/.local/lib/python3.8/site-packages/cjio/cjio.py", line 266, in processor
exporter(cm)
File "/home/mattes/.local/lib/python3.8/site-packages/cjio/cjio.py", line 164, in exporter
glb = cm.export2gltf()
File "/home/mattes/.local/lib/python3.8/site-packages/cjio/cityjson.py", line 1562, in export2gltf
glb = convert.to_glb(self.j)
File "/home/mattes/.local/lib/python3.8/site-packages/cjio/convert.py", line 188, in to_glb
tri = geom_help.triangulate_face(face, vertexlist)
File "/home/mattes/.local/lib/python3.8/site-packages/cjio/geom_help.py", line 88, in triangulate_face
xy = to_2d(p, n)
File "/home/mattes/.local/lib/python3.8/site-packages/cjio/geom_help.py", line 39, in to_2d
if((n==x3).all()):
AttributeError: 'bool' object has no attribute 'all'
Hello guys,
thanks very much for the cjio tool!
I have pip3-installed it and would like to convert some cityjson.
However the cjio cli tool seems to not be callable from shell. But I can import cjio as a module in my python script. Is there some docs how to use it for the conversion?
[I'm using ubuntu 18.04 ]
Thanks very much in advance!
In case the cjio/schemas directory contents is ['__pycache__', '0.9', '1.0.0']
, cityjson.fetch_schemas() doesn't return the path to '1.0.0' but to '_pycache_'.
When a Geometry is created and populated in LoD1, the geometries of the CityObjects in the CityJSON file contain the 'semantics' key and the values set to 'null'.
In The Netherlands PDOK makes cityjson files availabe of NL:
https://brt.kadaster.nl/basisvoorziening-3d/
For example the part with my home town haarlem is this one:
https://download.pdok.nl/kadaster/basisvoorziening-3d/v1_0/2018/volledig/25az1.volledig.zip
The ZIP is 553Mb, unzipped it is 2.7Gb(!)
Trying to cut out a small peace (to load in in QGIS with the cityjson plugin):
cjio 25az1.json subset --bbox 104607 490148 104703 490257 save myarea.json
My (rather beefy Linux) laptop (16Gb, 8 threads) kills the process after a lot of swapping...
So my question:
Any hint on how to handle this opendata is appreciated :-)
Expected to get the boundary defs with get_surface_boundaries('roofsurface') but it expect the output of get_surfaces()... Should be more intuitive.
When creating an empty CityJSON and adding one CityObject to it, print(CityJSON)
still returns and empty CityJSON, because it doesn't read the contents of the .cityobjects
.
{
"cityjson_version": "1.0",
"epsg": null,
"bbox": [
9000000000.0,
9000000000.0,
9000000000.0,
-9000000000.0,
-9000000000.0,
-9000000000.0
],
"transform/compressed": false,
"cityobjects_total": 0,
"cityobjects_present": [],
"materials": false,
"textures": false
}
In geom_helper numpy was set to be conditional, because of PyInstaller issues on Windows. Numpy is "only" needed for triangulation (eg. OBJ output), so I think not big deal for now, but it needs to be put back.
PyInstaller issues when running the compiled executable:
Traceback (most recent call last):
File "site-packages\numpy\core\__init__.py", line 24, in <module>
File "c:\python38\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 621, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\numpy\core\multiarray.py", line 14, in <module>
File "c:\python38\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 621, in exec_module
exec(bytecode, module.__dict__)
File "site-packages\numpy\core\overrides.py", line 7, in <module>
ImportError: DLL load failed while importing _multiarray_umath: The specified module could not be found.
Expected this to work:
ground = geom.get_surfaces('groundsurface')
ground
Out[20]: {1: {'surface_idx': [[0, 4]], 'type': 'GroundSurface'}}
geom.get_surface_boundaries(ground)
Traceback (most recent call last):
File "/home/balazs/.local/share/virtualenvs/cjio-xu4bWm9P/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 3296, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-21-c8e7cbab9dea>", line 1, in <module>
geom.get_surface_boundaries(ground)
File "/home/balazs/Development/cjio/cjio/models.py", line 351, in get_surface_boundaries
raise TypeError("surface must be a single surface")
TypeError: surface must be a single surface
But instead this is the required workflow:
ground_boundaries = []
for g in ground.values():
ground_boundaries.append(geom.get_surface_boundaries(g))
if --format XXX
must be used then it shouldn't be an option but an argument, no?
cjio tudelft_campus.json export obj tudelft_campus.obj
Originally posted by @hugoledoux in #34 (comment)
When creating a Geometry instance through the API with geom = Geometry(lod=1)
, and empty semantics
is automatically added to the geometry.
Eg. "semantics": {"surfaces": [], "values": [[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]]}
This is unnecessary in this case and increases the size and complexity of the file. Do not do it.
Validating a CompositeSurface fails with the vague 'is not valid under any of the given schemas'
error. val3dity does validate the same file (although the geometry is invalid).
The file is created from msurface_buildings.zip , by replacing MultiSurface
with CompositeSurface
as geometry type.
The compositesurface file:
csurface_buildings.zip
Hi, I am a Windows 10 user but I don't know how to install cjio. Can someone help me with this?
When I open commandprompt and type: "pip install cjio" it says: pip' is not recognized as an internal or external command,
operable program or batch file.
Hi!
When I used subset box to cut the CityJSON file, the bounding box extension is kept as the original input CityJSON file, instead of being replaced by the new bounding box extension.
I've been looking into the implementation of #1 and I think it would make our life easier if we followed the CityJSON specification more closely with the class implementations. It would include for example creating a CityObject class with its methods for operating on it, eg update the path to the texture file. Once we have the classes properly set up, extending cjio would be a "breeze" as it would mainly require adding new methods to the classes. But all this would require refactoring the current codebase to accomodate the changes. What do you think @hugoledoux?
The API casts the coordinates to tuples, not lists. Tuples should be allowed as they are bit more efficient on the memory.
(False,
False,
["(0.0, 0.0, 0.0) is not of type 'array'",
"(0.0, 0.0, 10.0) is not of type 'array'",
"(0.0, 10.0, 0.0) is not of type 'array'",
"(0.0, 10.0, 10.0) is not of type 'array'",
"(10.0, 0.0, 0.0) is not of type 'array'",
"(10.0, 0.0, 10.0) is not of type 'array'",
"(10.0, 10.0, 0.0) is not of type 'array'",
"(10.0, 10.0, 10.0) is not of type 'array'"],
[])
Subset a file by a polygon from a .geojson
a Geometry
stores a single
geometric representation of the CityObject
, for example LoD1. Thus a single
CityObject
can contain multiple Geometry
objects.
I tried to convert a cityjson file to obj and got the error message:
OBJ export skipped: Python module 'mapbox_earcut' missing (to triangulate faces)
After investigating on mapbox_earcut, I got to this page:
and tried to install it, but the installation procedure is not well (if at all) described. Could you give me a hand? I got as far as getting cmake to configure the mapbox_earcut:
-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PythonInterp: /usr/bin/python3.6 (found version "3.6.9")
-- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython3.6m.so
-- Performing Test HAS_CPP14_FLAG
-- Performing Test HAS_CPP14_FLAG - Success
-- pybind11 v2.2.2
-- Performing Test HAS_FLTO
-- Performing Test HAS_FLTO - Success
-- LTO enabled
-- Configuring done
-- Generating done
What is the last step to get cijo getting to recognise the mapbox_earcut? Any other way of getting the mapbox_earcut into cijo?
Thanks!
The following code finds a different nr of COs in grid_idx[15] at each run.
from os import path
import json
from cjio import cityjson
from cjio import tiling
p = './cjio/example_data/delft.json'
dout = './cjio/tmp/data'
with open(p, 'r') as f:
cm = cityjson.CityJSON(file=f)
bbox = cm.update_bbox()
grid_idx = tiling.create_grid(bbox, 2)
for idx, bbox in grid_idx.items():
print(idx, bbox)
print("cm", len(cm.j['CityObjects']))
s = cm.get_subset_bbox((bbox[0], bbox[1], bbox[3], bbox[4]), invert=False)
print("s", len(s.j['CityObjects']))
print("---------------")
pout = path.join(dout,'{}.json'.format(idx))
with open(pout, 'w') as fo:
json_str = json.dumps(s.j, indent=2)
fo.write(json_str)
Ẁhile this below, always returns 83.
bbox = cm.update_bbox()
grid_idx = tiling.create_grid(bbox, 2)
bbox = grid_idx[15]
s = cm.get_subset_bbox((bbox[0], bbox[1], bbox[3], bbox[4]), invert=False)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.