Giter VIP home page Giter VIP logo

arcpy_metadata's Introduction

Arcpy Metadata Editor (arcpy_metadata)

Whether you create it or not, metadata is a critical part of GIS analysis. ArcGIS includes a built-in GUI metadata editor, but has scant access to metadata properties from Python. The arcpy_metadata package provides this access, allowing large Python packages that generate their own geospatial outputs in ArcGIS to properly document the data.

Code Issues

Getting arcpy_metadata

arcpy_metadata is pure Python and its only dependency is arcpy (installed with ArcGIS). It's available on the Python Package Index so you can get arcpy_metadata via pip (pip install arcpy_metadata).

If you don't have or don't know how to use pip, you can install arcpy_metadata by cloning/downloading this repository and running setup.py install in the root folder

Using arcpy_metadata

Creating the Metadata Editor

Edit existing metadata for Shapefiles, Rasters, FeatureClasses, RasterDatasets, MosaicDatasets or Layers

import arcpy_metadata as md
metadata = md.MetadataEditor(path_to_some_feature_class)  # currently supports Shapefiles, FeatureClasses, RasterDatasets and Layers

Edit or create an XML file directly

import arcpy_metadata as md
metadata = md.MetadataEditor(metadata_file="path/to/metadata_file.xml")  # currently supports Shapefiles, FeatureClasses, RasterDatasets and Layers

Choose your log level

metadata = md.MetadataEditor(path_to_some_feature_class, loglevel="DEBUG")  # use any of CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET, dafault is INFO

Get text items (returns string)

title = metadata.title
abstract = metadata.abstract

Change text items

metadata.title = "The new title"
metadata.abstract = "This is the abstract"

Get list items (returns list)

tags = metadata.tags
for tag in tags:
    print tag

Change list items

metadata.tags = ["tag1", "tag2"]
metadata.tags[1] = "another tag"
metadata.tags.append("new tag")
metadata.tags.insert(0, "first tag")
metadata.tags.remove("tag1")
metadata.tags.pop()

Get numeric items (return int or float)

min_scale = metadata.min_scale
max_scale = metadata.max_scale

Change numeric items

metadata.min_scale = 500000
metadata.max_scale = 500

Get date items (returns date object)

last_update = metadata.last_update
last_update_year = metadata.last_update.year

Change date items (excepts datetime objects and formated string (yyyymmdd, yyyy-mm-ddThh:mm:ss)

from datetime import date
today = date.today()
metadata.last_update = today
metadata.last_update = "20160221"

Get contact items (returns contact object)

contact = metadata.point_of_contact
contact_name = metadata.point_of_contact.contact_name
contact_email = metadata.point_of_contact.email

Change contact items (all contact items are string)

metadata.point_of_contact.contact_name = "First and Last Name"
metadata.point_of_contact.email = "[email protected]"

Edited nested lists

# make sure you have the right number of elements
# add new ones
while metadata.online_resource < 3:
    metadata.online_resource.new()
# or delete spare once
while metadata.online_resource > 3:
	metadata.online_resource.pop()
	
metadata.online_resource[0].name = "First download link"
metadata.online_resource[0].link = "http://somelink"
metadata.online_resource[0].function = "download"
metadata.online_resource[1].name = "Second download link"
metadata.online_resource[1].link = "http://someotherlink"
metadata.online_resource[1].function = "download"
metadata.online_resource[2].name = "Third download link"
metadata.online_resource[2].link = "http://yetanotherdownloadlink"
metadata.online_resource[2].function = "download"

Remove all items from the geoprocessing history

metadata.rm_gp_history()

Saving the changes back to the file

metadata.save() # save the metadata back to file.
metadata.cleanup() # remove all temporary files.

or

metadata.finish()  # save() and cleanup() as one call

If you want to enable automatic updates of your metadata (feature classes only) call.

metadata.finish(True) 

Supported items

Item description Internal name Type Location in ArcCatalog Path in ArcGIS XML file
Title title String Overview/ Item Description/ Title dataIdInfo/idCitation/resTitle
Abstract abstract String Overview/ Item Description/ Description dataIdInfo/idAbs
Purpose purpose String Overview/ Item Description/ Summery dataIdInfo/idPurp
Tags tags List Overview/ Item Description/ Tags dataIdInfo/searchKeys/keyword
Place Keywords place_keywords List Overview/ Topics & Keywords/ Place Keyword dataIdInfo/placeKeys/keyword
Extent Description extent_description String Resource/ Extents/ Extent/ Description dataIdInfo/dataExt/exDesc
Temporal Extent Description temporal_extent_description String dataIdInfo/dataExt/tempDesc
Temporal Extent Instance temporal_extent_instance Date Resource/ Extents/ Temporal Instance Extent/ Instance Date dataIdInfo/dataExt/tempEle/exTemp/TM_Instant/tmPosition
Temporal Extent Start Date temporal_extent_start Date Resource/ Extents/ Temporal Period Extent/ Begin Date dataIdInfo/dataExt/tempEle/exTemp/TM_Period/tmBegin
Temporal Extent End Date temporal_extent_end Date Resource/ Extents/ Temporal Period Extent/ End Date dataIdInfo/dataExt/tempEle/exTemp/TM_Period/tmEnd
Minimum Scale min_scale Integer Item Description/ Appropriate Scale Range/ Min Scale Esri/scaleRange/minScale
Maximum Scale max_scale Integer Item Description/ Appropriate Scale Range/ Max Scale Esri/scaleRange/maxScale
Scale Resolution scale_resolution Integer Resource/ Details/ Scale Resolution dataIdInfo/dataScale/equScale/rfDenom
Last Update last_update Date Overview/ Citation/ Dates/ Revised dataIdInfo/idCitation/date/reviseDate
Update Frequency Description update_frequency_description String Resource/ Maintenance/ Custom Frequency dataIdInfo/resMaint/usrDefFreq/duration
Credits credits String Overview/ Item Description/ Credits dataIdInfo/idCredit
Citation citation String Overview/ Citation/ Other Details dataIdInfo/idCitation/otherCitDet
Limitation limitation String Overview/ Item Description/ Use Limitation dataIdInfo/resConst/Consts/useLimit
Supplemental Information supplemental_information String Resource/ Supplemental Information dataIdInfo/suppInfo
Source source String Resource/ Lineage/ Data Source/ Source Description dqInfo/dataLineage/dataSource/srcDesc
Points of contact point_of_contact ContactObj Resource/ Details/ Points of Contact/ Contact/ dataIdInfo/idPoC
Maintenance Contacts maintenance_contact ContactObj Resource/ Maintenance/ Maintenance Contact/ dataIdInfo/maintCont
Citation Contacts citation_contact ContactObj Overview/ Citation Contact/ Contact/ dataIdInfo/idCitation/citRespParty
Language language String Resource/ Detail/ Languages/ Language dataIdInfo/dataLang
Metadata Language metadata_language String Metadata/ Detail/ Language dataIdInfo/mdLang
Alternate Title alternate_title String Overview/Citation/Titles/Alternate Title dataIdInfo/idCitation/resAltTitle
Identifier Code (1) identifier_code1 String Overview/Citation/Identifier/Code dataIdInfo/idCitation/citId/identCode
Identifier Code (2) identifier_code2 String Overview/Citation/Identifier/Authority Citation/Identifier/Code dataIdInfo/idCitation/citId/identAuth/citId/identCode
Identifier Code (3) identifier_code3 String Overview/Citation/Identifier/Authority Citation/Identifier/Authority Citation/Identifier/Code dataIdInfo/idCitation/citId/identAuth/citId/identAuth/citId/identCode
Identifier Code (4) identifier_code4 String Resource/Lineage/Data Source/Reference System/Authority Citation/Identifier/Code dqInfo/dataLineage/dataSource/srcRefSys/identAuth/citId/identCode
Metadata File Identifier file_identifier String Metadata/Details/File Idnetifier mdFileID
Dataset URI dataset_uri String Metadata/Details/Dataset URI dataSetURI
Resource Label resource_label String Resource/Fields/Details/Label eainfo/detailed/enttyp/enttypl
Format format String Resource/Distribution/Distribution Format/Format Name distInfo/distFormat/formatName

Contact items

Item description Internal name Type Relative path in ArcGIS XML file
Contact Name contact_name String ./rpIndName
Position position String ./rpPosName
Organization organization String ./rpOrgName
Email email String ./rpCntInfo/eMailAdd
Address address String ./rpCntInfo/cntAddress/delPoint
City city String rpCntInfo/./cntAddress/City
State state String rpCntInfo/./cntAddress/adminArea
Zip zip String rpCntInfo/./cntAddress/postCode
Country country String ./rpCntInfo/cntAddress/country
Phone Nb phone_nb String ./rpCntInfo/cntPhone/voiceNum
Fax Nb fax_nb String ./rpCntInfo/cntPhone/faxNum
Hours hours String ./rpCntInfo/cntHours
Instructions instructions String ./rpCntInfo/cntInstr
Website Link link String ./rpCntInfo/cntOnlineRes/linkage
Protocol protocol String ./rpCntInfo/cntOnlineRes/protocol
Profile profile String ./rpCntInfo/cntOnlineRes/appProfile
Website Name or_name String ./rpCntInfo/cntOnlineRes/orName
Website Description or_desc String ./rpCntInfo/cntOnlineRes/orDesc

Online Resource Items

Item description Internal name Type Relative path in ArcGIS XML file
Link link String ./linkage
Protocol protocol String ./protocol
Profil profile String ./appProfile
Name name String ./orName
Description description String ./orDesc
Function function String ./orFunct/OnFunctCd

Don't see the item you need? Read more about how to extend arcpy_metadata to work with other metadata elements it doesn't yet handle in CONTRIBUTING.md.

Python and ArcGIS Support

arcpy_metadata runs on Python 2 and 3, which means it can, at a basic level, be used both with ArcMap and ArcGIS Pro. ArcGIS Pro doesn't yet have some of the metadata export functions that arcpy_metadata relies on though, so, as of version 0.5, you must specify a path to a metadata XML file, or use a dataset that already has its metadata in an accessible XML format (e.g. Shapefile), in order to use arcpy_metadata in ArcGIS Pro. All features work in ArcMap/Python 2.

Under the hood

arcpy_metadata uses the strategy of exporting the metadata from the layer, then edits the xml export based on your method calls. When you're done, use finish() to save your data back to the source.

Known limitations

Does not yet support all metadata items.

arcpy_metadata only works with 32-bit Python. We use arcpy.XSLTransform_conversion() to extract metadata from geodatabases. 64bit arcpy python bindings for background processing do not support tools inside the metadata conversion toolset.

How to contribute

Contributions are well come! Please fork and submit pull requests. If you are missing a particular metadata attribute, you can easiy add them here. Don't forget to also add them to the test cases to make sure everything works as expected

Acknowledgements

arcpy_metadata was initially a project of the UC Davis Center for Watershed Sciences and has received significant contributions from the World Resources Institute. It was created as part of a larger project funded by the California Department of Fish and Wildlife Biogeographic Data Branch and further developed for Global Forest Watch. We thank our funders for their support and their commitment to high quality geospatial data.

arcpy_metadata's People

Contributors

adamkerz avatar drwelby avatar lilawren avatar nickrsan avatar quantifiedcode-bot avatar ryankdalton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arcpy_metadata's Issues

FGDB Tests not passing on 10.7

I wanted to put a note here that I can't get all of the tests to pass on my new machine running 10.7. It fails during the XSLTransform - I confirmed the xsl file exists in the same location in the ArcGIS install folder, and non FGDB tests work correctly. I can't export using XSLTransform outside of arcpy_metadata either, so this may be a wontfix even if it's occurring on other people's machines, but wanted to note it here in case it's happening to anyone else.

TypeError: unhashable type: 'dict'

I have a simple shapefile I am trying to load into the MetadataEditor:

shp = "<C:/<...>/feature.shp"
metadata = md.MetadataEditor(shp)

When I run this, I get the following error:

TypeError: unhashable type: 'dict'

Any suggestions as to how to resolve this?

Convert to using logging instead of simple custom logging code

We can do a two step conversion to using logging - first, we can add a logging configuration using the logging module and convert logwrite and logwarning to use the logger, then we can actually comb the code for calls and remove those old loggers.

Upload 0.5.1 to pypi

Hi Nick,
I noticed there was a bug with the logger. I fixed it, can you upload latest version to pypi?

Thanks

Thomas

Tags and Place Keywords overwriting one another

It seems that the tags and place keywords properties overwrite each other, depending on which one is updated first. For example,

metadata = md.MetadataEditor(item)
metadata.place_keywords = ["Colorado","Arizona"]  #Place Keywords
metadata.tags = ['Lands','Veg1000','Mapping','Wetlands']  #Tags #overwrites place keywords
metadata.finish()
metadata = md.MetadataEditor(item)
metadata.tags = ['Lands','Veg1000','Mapping','Wetlands']  #Tags #overwrites place keywords
metadata.place_keywords = ["Colorado","Arizona"]  #Place Keywords #overwrites tags
metadata.finish()

Setting up arcpy_metadata on Windows 7

Hi,
I wonder if I can setup the arcpy_metadata on my windows 7 machine as where ArcGIS 10.2.2 and python 2.7 32-bit installed ?
Please advise,

Thanks,
Sami

facing issue when using dictionary in my code

I want read n update existing metadata replacing some value from external csv file based on fc name as common id between Featureclasses and csv file(3 columns). but whenever I use dict in my code. it is throwing error

import arcpy_metadata as md
import datetime
import arcpy
import os

workspace ='C:\xxx\AssetID_to_Shapefile_Script_Output_V1'

csvpath=r"C:\xxx\test_metadata\test\meta_batch14.csv"


d = {}
with open(csvpath) as f:
    for line in f:
        (key, AccesWidth,drwgNo) = line.split(',')
        d[(key)] = AccesWidth  #EaseWidth
print d




walk = arcpy.da.Walk(workspace, datatype="FeatureClass")
for dirpath, dirnames, filenames in walk:
    for filename in filenames:
        fc=(os.path.join(dirpath, filename))

        
        metadata = md.MetadataEditor(fc)
        print (fun_csvtodict(csvpath))
        fcname=filename[:-4]

        print fcname+'\n' +'\t'+ metadata.abstract



metadata.finish()  
print "~~~~~~~~~~~~~~~~~~~~~~~Finished~~~~~~~~~~~~~~~~~"

NameError: name 'metadata' is not defined

ImportError: No module named 'version'

Getting a ImportError: No module named 'version' error when running the tests.

May need to change arcpy_metadata__init__.py

from arcpy_metadata.version import author
from arcpy_metadata.version import version

Reduce dependencies from ArcPy

Arcpy is actually only needed to extract metadata from GDB items. Everything else can be done without this module since metadata are access directly using the XML file.
If metadata for a feature class are edited, arcpy can be loaded on demand using importlib.
This way, users without an arcpy install can still make use of the core functionalities of this module.

from importlib import import_module
arcpy = import_module('arcpy')

ModuleNotFoundError

Greetings. When I run setup.py in ArcGIS Pro using the command prompt, I get the following error. Any thoughts?
Thank you,
Lara

Traceback (most recent call last):
File "", line 3, in
ModuleNotFoundError: No module named 'arcpy_metadata'

image

test_layer_file fails

test_layer_file fails with the following traceback on Python 2.7:

Error
Traceback (most recent call last):
File "C:\Users\nrsantos\Code\arcpy_metadata\tests\test_metadata_editor.py", line 103, in test_layer_file
self._run_example(os.path.join(test_data_folder, r"layer.lyr"))
File "C:\Users\nrsantos\Code\arcpy_metadata\tests\test_metadata_editor.py", line 41, in _run_example
metadata = md.MetadataEditor(feature_class) # also has a feature_layer parameter if you're working with one, but edits get saved back to the source feature class
File "C:\Users\nrsantos\Code\arcpy_metadata\arcpy_metadata\metadata_editor.py", line 74, in init
self.data_type = desc.dataElement.dataType
AttributeError: DescribeData: Method dataElement does not exist

Coding problem

Hi, at first I would like to thanks for this very usefull tool in everyday issues. Unfortunately there are problems when using this tool for migrate, or multiple set of metadata when strings with metadata information contains symbols in different coding (for example ANSI1250 and symbols like "č", "ž", "é". etc.

Is there any solution for this problem?

Thank you very much!

Metadata abstract writen with wrong font

Hi there and thank you for your work,

I am using arcpy_metadata to mainly fill the layers' abstract section, this is the part of my code that does the work

if ext == "shp":
    
    metadata = md.MetadataEditor(metadata_file = shp + ".xml")
    title = ""
    metadata.title = title

    if title == old_shp_name:
        metadata.title = shp

    metadata.abstract = MD_ABS
    metadata.save()

NB: arcpy_metadata has been imported as md and MD_ABS is the abstract parameter I fill beforehand

This works most of the time, but sometimes I get the abstract written with the same font as the subtitle Abstract in ArcCatalog as you can see below (French version)
image

while it should be displayed like this
image

I don't understand why at some point it occurs, but when it does looks like I have to reboot to correct this until it comes back again !

Problem (beside the font) : when I try to update the metadata directly from ArcCatalog it crashes every time

Should I add something in my code to prevent the font from changing ?
Any thoughts are very welcome

Thank you again

Max

Edit : I add 2 xml, one good and one evil, to me I don't see any difference but it might help

abstract_font_issue.zip

How to add text with hyperlink

I want to put hyperlink on some text in abstract section. I tried choosing html tags for hyperlink but didnt work. pls show pointers how can I achieve

example:
Abstract: This Layer has bee downloaded from here

Add locals element

Add locals metadata element to allow storing translated title and abstract

Attribute Error

I keep on getting the following error:
AttributeError: module 'arcpy' has no attribute 'XSLTransform_conversion'

any ideas?

Several Python errors .Append()

Hi,

During running the following simple test below, I ran into the following errors:


import arcpy_metadata as md
import datetime
import unittest
import os
import shutil
import arcpy
import gc

feaure_class =r"C:\Temp\arcpy_metadata-master\tests\test_data_temp_folder\test.gdb\root_poly"
metadata = md.MetadataEditor(feaure_class)
metadata.title.set("The metadata title!")

generated_time = "This layer was generated on {0:s}".format(datetime.datetime.now().strftime("%m/%d/%Y %I:%M %p"))

metadata.purpose.set = ("Layer represents locations of the rare Snipe.")

metadata.abstract.append("generated by ___ software")
metadata.abstract.append(generated_time)
metadata.tags.add(["foo", "bar", "baz"])

metadata.finish() # save the metadata back to the original source feature class and cleanup
gc.collect()


At:
metadata.title.set(..)
metadata.purpose.set (..)

Error encountered:
AttributeError: 'str' object has no attribute 'set'

also for:
metadata.abstract.append(..)

Error encountered:
AttributeError: 'str' object has no attribute 'append'

Also for:
metadata.tags.add([..])

Error encountered:
AttributeError: 'list' object has no attribute 'add'

I'm using:
python 2.7.5
ArcGIS 10.2.2

Please advise,
Thanks,

Is MetadataEditor changing exit codes?

I am finding that when I use MetadataEditor it changes the exit codes emitted by my scripts.

For example when this python script:

#exittest-metadata.py
import arcpy_metadata as md;

if sys.argv[1] == "true":
    print("Editing  metadata")
    table = "sde\\connection.sde\\OWNER.TABLE"
    editor = md.MetadataEditor(table)
    editor.finish()
else:
    print("Skipping metadata")

sys.exit(0)

is called by this batch file:

python exittest-metadata.py false
@echo Returns %ERRORLEVEL%

python exittest-metadata.py true
@echo Returns %ERRORLEVEL%

they produce this output:

>python exittest-metadata.py false
Skipping metadata
Returns 0

>python exittest-metadata.py true
Editing metadata
Exporting metadata to temporary file C:\Users\<user>\AppData\Local\Temp\scratch\OWNER.TABLE.xml
Saving metadata
cleaning up from metadata operation
Returns -2146234327    

As you can see on the second run a non-zero exit code is emitted despite calling sys.exit(0).

Is this a known gotcha?
Is there a workaround I should be using?

Merge v0.4?

Hey Nick,

would you feel comfortable if I merge my current pull request into your repo?
Latest changes are not backwards compatible and the way you interact with the API a little bit different, but way easier.

It will also be much easier to add new items if needed.

I updated the documentation on our current fork
https://github.com/wri/arcpy_metadata

Thomas

Confirm Python 3.4 Compatibility (ArcGIS Pro 1.1+)

A quick glance makes it look like this code base should be ready for Python 3, but with ArcGIS Pro running Python 3.4 it's probably time to verify. I have a project that will need this library running in ArcGIS Pro, so I'll give it a test and run the test suite (such as it is) to check it.

Metadata values not available

Using ArcMap version 10.3.0.4322
Windows 7 Enterprise version 6.1.7601 SP1 Build 7601

md.version

'0.2.5'

I am unable to pull the values from the metadata items through the library functions. I have tried on .shp files as well as feature classes located in .gdbs. Unsure of how to attach the data I'm using, but if you let me know how I would be happy to include it with this issue. Below is from my ArcMap Python window

import arcpy_metadata as md
data = md.MetadataEditor(r'C:\Temp\Example.shp')
Exporting metadata to temporary file c:\users\gpopulis\appdata\local\temp\arcd9b3\tmpmfsqivarcpy_metadata\pisces0metadata
data.items
[<arcpy_metadata.MetadataAbstract object at 0x349DC250>, <arcpy_metadata.MetadataPurpose object at 0x349DC270>, <arcpy_metadata.MetadataTags object at 0x349DC2F0>, <arcpy_metadata.MetadataTitle object at 0x349DC490>]
for item in data.items:
... print item.name, item.value
...
abstract
purpose
tags
title

write to text: metadata description has xml code

I have a script that uses arcpy_metadata and writes the title, tags, purpose (summary) and description (abstract) to a text file. In general, it works great, but it looks like some XML code is being written along with the text. It's not causing any errors, only it interferes with the readability of the text file content.
Here's a zip that has the script I created and the text file:
Metadata2Txt.zip

Thanks,
Jared

suppress messages to console

I would like to see an enhancement that would allow for suppression of the messages to the console for use of this module in a scripting environment. I have been able to control it by redirecting sys.stdout, but it would be a nice feature to have added to the MetadataEditor module as a flag.

Dropdowns with code values?

I noticed in the code that all of the drop down types have been commented out. And when trying these out the coded values appear within the XML tag, which is incorrect and not read properly. Are there plans to fix this?

I can help if I got some help on how the process of changing the tags works in the module.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.