Coder Social home page Coder Social logo

brettkromkamp / contextualise Goto Github PK

View Code? Open in Web Editor NEW
1.0K 25.0 45.0 13.37 MB

Contextualise is an effective tool particularly suited for organising information-heavy projects and activities consisting of unstructured and widely diverse data and information resources

Home Page: https://contextualise.dev/

License: MIT License

Python 84.80% CSS 5.26% JavaScript 9.95%
knowledge-graph flask-application python3 vuejs metamodel sqlite-database python semantic-web cms-backend content-management-system

contextualise's Introduction

Brett Kromkamp - brettkromkamp.com

Brett Kromkamp's GitHub Profile

You've reached Brett Kromkamp's GitHub profile. Find me on Mastodon.

I am working on the next version of Contextualise, a personal knowledge management application. Knowledge management is a crowded space. My contribution to the plethora of approaches and applications in this space is based on a combination of topic maps, (embeddings-based) semantic search and language model workflows.

I ask everyone to support the people of Ukraine who are being invaded by Russia. Donate now.

My latest blog post is Three.js Development in 2023.

I contribute to and maintain Contextualise, TopicDB and a couple of other open source projects. I also have several published Python packages on PyPI. Expect many of my projects to be related to knowledge graph-based applications combined with procedural generation together with 2D and 3D visualization systems.

Technologies I enjoy working with, include:

  • Topic maps describing knowledge structures and associating them with information resources
  • Python programming language
  • FastAPI web framework for building APIs
  • Angular web framework
  • Flask web framework
  • Blender 3D creation suite
  • Three.js JavaScript 3D library

Contextualise Experiments

Reveal.js-Based Knowledge Paths

Extending Contextualise to include a reveal.js-based presentation mode to supplement the existing knowledge path feature.

Mixing Art and Code to Build Engaging Web Experiences

Development of web content models, concepts, creation processes and tools: mix art and code to build interactive, engaging web experiences

Story Technologies

Storytelling With Interactive Visualisation of Semantic Events

Developing a combined Angular and Pixi.js-based web application —for storytelling purposes— that allows a user to navigate between a collection of narrative events. Each event has an accompanying 2.5D, isometric environment with participants and items that can be interacted with. Interactions include (but, are not limited to) displaying more information about the selected object and high-lighting a set of objects by tag. Narratives are Contextualise topic maps.

I will see you again, in the place where no shadows fall. — Ambassador Delenn, Babylon 5

contextualise's People

Contributors

brettkromkamp avatar epilys avatar machawk1 avatar nekroze avatar stratosgear 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  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  avatar  avatar  avatar  avatar

contextualise's Issues

Windows

Would love to see this on windows as a standalone app, but it looks like you might be going another direction.

Network graph must take context/scope filtering into account

Currently, the network graph is always filtered by scope (which could be the default "Universal" scope); nonetheless, it should be possible to display the network graph without any scope filtering since this feature has been added to Contextualise: #24

graph-view

Contextualise feedback

@machawk1 Hi Mat, not sure if you have actually taken a look at Contextualise yet. But, if you have, I would love to hear what you think of it. What works? What really doesn't? Thanks in advance.

OSX installation

I have attempted to install on my mac from scratch with the following steps:

brew install python
brew install postgresql
git clone https://github.com/brettkromkamp/topic-db.git
cd topic-db
pip install -e .
cd ../
git clone https://github.com/brettkromkamp/contextualise
cd contextualise
pip install -e .
cd ../

All good!

Then created a directory for the 'project' ie somewhere to place a settings.ini (and a topicmap-definition.sql):

mkdir first
cd first

Then edited settings.ini to:

[DATABASE]
Username = testuser
Password = password
Database = testname
Host = localhost
Port = 5432

Then create a test database.

psql postgres
CREATE USER testuser WITH PASSWORD 'password';
CREATE DATABASE testname OWNER testuser;
\q
psql -h localhost -U testuser -d testname -a -f topicmap-definition.sql

All looked good!

Then run flask:

export FLASK_APP=contextualise
export FLASK_ENV=development
flask run

And it looked like the readme example.

But then, when I open http://127.0.0.1:5000/ I get a KeyError, specifically for database_username = config["DATABASE"]["Username"].

I have never used postgres before, but am guessing I may need to log on as that user?

Any help appreciated, I feel close to a successful install!

Refactor scope filtering to also include no filtering at all

Currently, scope filtering is always "active", that is, the topic view is always rendered with occurrences and associations filtered by scope (by default, occurrences and associations have "Universal" (*) scope). It makes sense to be able to disable scope filtering (which is obviously something distinct than filtering by the default Universal scope) to see all the topic's occurrences and associations regardless of their scope.

Implement functionality to report and remove inappropriate content

A user can decide to make their topic maps public (accessible without having to log in to the application). The presence of public maps also implies that, at some point, somebody might publish content that is not appropriate. There needs to be a mechanism in place to report and subsequently remove inappropriate content (by the application administrator).

Handle non-existent topic

Currently, if a user navigates to a non-existent topic a 404 (Not found) page is displayed. Ideally, the user should be presented with the topic creation form with the relevant topic identifier already filled-out.

Add UI support for tagging

Adding, removing and visualizing (i.e., tag cloud) tags using the appropriate (topic maps) association types and roles.

Python error in install

Hi, This looks really interesting. I keep getting the following error while attempting to install the development version.

ERROR: Command errored out with exit status 1: command: /usr/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-sjgw80/topic-db/setup.py'"'"'; __file__='"'"'/tmp/pip-install-sjgw80/topic-db/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base pip-egg-info cwd: /tmp/pip-install-sjgw80/topic-db/ Complete output (5 lines): Traceback (most recent call last): File "<string>", line 1, in <module> File "/tmp/pip-install-sjgw80/topic-db/setup.py", line 13, in <module> with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: TypeError: 'encoding' is an invalid keyword argument for this function ---------------------------------------- ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
I'm on Ubuntu 19.94 . Any ideas? Thanks in advance!

First installation feedback: unexpected keyword argument 'scope'

Hi Brett,

first and foremost, thanks for opensourcing Contextualise!

I am giving it a try, and I incurred in an error when trying to open my first map. Here's how to reproduce it:

  • logged in as admin@ as per readme
  • created new map with title, description and image (form won't save without an image)
  • went to http://127.0.0.1:5000/topics/view/1/home and I got the following:
Traceback (most recent call last):
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/app.py", line 2463, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/app.py", line 2449, in wsgi_app
    response = self.handle_exception(e)
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/app.py", line 1866, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/fradeve/.pyenv/versions/3.7.3/envs/contextualise/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/fradeve/contextualise/contextualise/topic.py", line 68, in view
    resolve_attributes=RetrievalMode.RESOLVE_ATTRIBUTES,
TypeError: get_topic() got an unexpected keyword argument 'scope'

Any idea of what might have gone wrong?

Thank you very much again!

Tabs/menus user interface refactor

Currently, to switch between the different “parts” of the application (for example, the topic view, the associations view) you have to click twice (first click to open the drop-down menu, second click to select the ‘view’ item in the menu). This, in practice, is a bit cumbersome and a different approach is needed.

Internal Server Error

I have created a new topic map. When adding a new topic, the following error appears:
————————————————————————————————
Internal Server Error
Something has gone wrong. Get in touch with Support if the problem persists. Find your way back home.

Remove Google KnowledgeGraph feature

At some point, Google KnowledgeGraph support was added to Contextualise. Nonetheless, the Google KnowledgeGraph API provides for a poor experience. Removing the Google KnowledgeGraph support would be the first step in replacing it with perhaps something like the Wikidata API.

Add Google Maps support

Add Google Maps support allowing the user to set a geographic coordinate for subsequent visualization in Google Maps for a topic.

How to set the coordinates using Google Maps is explained in the Google Maps documentation.

Failed to open the home page due to an error in running Flask

flask.cli.NoAppException
flask.cli.NoAppException: While importing "contextualise", an ImportError was raised:

Traceback (most recent call last):
File "d:\python\lib\site-packages\flask\cli.py", line 240, in locate_app
import(module_name)
File "D:\contextualise\contextualise_init_.py", line 13, in
from flask_mail import Mail
ModuleNotFoundError: No module named 'flask_mail'

Traceback (most recent call last)
File "D:\contextualise\contextualise_init_.py", line 13, in
from flask_mail import Mail
During handling of the above exception, another exception occurred:
File "D:\python\Lib\site-packages\flask\cli.py", line 343, in call
rv = self._load_unlocked()
File "D:\python\Lib\site-packages\flask\cli.py", line 330, in _load_unlocked
self._app = rv = self.loader()
File "D:\python\Lib\site-packages\flask\cli.py", line 388, in load_app
app = locate_app(self, import_name, name)
File "D:\python\Lib\site-packages\flask\cli.py", line 245, in locate_app
raise NoAppException(
flask.cli.NoAppException: While importing "contextualise", an ImportError was raised:

Traceback (most recent call last):
File "d:\python\lib\site-packages\flask\cli.py", line 240, in locate_app
import(module_name)
File "D:\contextualise\contextualise_init_.py", line 13, in
from flask_mail import Mail
ModuleNotFoundError: No module named 'flask_mail'
The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.
To switch between the interactive traceback and the plaintext one, you can click on the "Traceback" headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.

You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:

dump() shows all variables in the frame
dump(obj) dumps all that's known about the object

Issues installing because of missing pg_config

I am trying to install contextualise on macOS 10.14.6 and Python 3.7.

/tmp
❯ virtualenv c-ize
Using base prefix '/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7'
New python executable in /private/tmp/c-ize/bin/python3.7
Also creating executable in /private/tmp/c-ize/bin/python
Installing setuptools, pip, wheel...
done.

/tmp
❯ source c-ize/bin/activate

/tmp
c-ize ❯ pip3 freeze

/tmp
c-ize ❯ git clone https://github.com/brettkromkamp/contextualise
Cloning into 'contextualise'...
remote: Enumerating objects: 155, done.
remote: Counting objects: 100% (155/155), done.
remote: Compressing objects: 100% (108/108), done.
remote: Total 1133 (delta 101), reused 87 (delta 45), pack-reused 978
Receiving objects: 100% (1133/1133), 769.37 KiB | 9.05 MiB/s, done.
Resolving deltas: 100% (833/833), done.

/tmp
c-ize ❯ cd contextualise

/tmp/contextualise master
c-ize ❯ pip3 install -e .
Obtaining file:///private/tmp/contextualise
Collecting flask (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/9b/93/628509b8d5dc749656a9641f4caf13540e2cdec85276964ff8f43bbb1d3b/Flask-1.1.1-py2.py3-none-any.whl
Collecting flask-security (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/88/47/4908a5040120768ff4fb2465c7eeafeb9239c27d2919bd67c4ccc1b43e14/Flask_Security-3.0.0-py2.py3-none-any.whl
Collecting flask-sqlalchemy (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/1e/65/226d95466c75e34e291a76890ed0e27af2e46ab913002847856f11d4d59d/Flask_SQLAlchemy-2.4.1-py2.py3-none-any.whl
Collecting sqlalchemy (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/fc/49/82d64d705ced344ba458197dadab30cfa745f9650ee22260ac2b275d288c/SQLAlchemy-1.3.8.tar.gz
Collecting bcrypt (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/62/20/4c94f3f8dfc6b8720c8bc903ce2951ec6397ad864e3a64b4abdced014514/bcrypt-3.1.7-cp34-abi3-macosx_10_6_intel.whl
Collecting topic-db (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/91/e9/1a3068a8326f5dbe0bc0669b7ae5989e1e80c5bee2951aad32788bafdf8c/topic_db-1.0.0-py3-none-any.whl
Collecting maya (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/1d/56/789ebf410acc1491bf4078ef57a7a277b42c0b18f43e17007bfb6c1caaf3/maya-0.6.1-py2.py3-none-any.whl
Collecting mistune (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/09/ec/4b43dae793655b7d8a25f76119624350b4d65eb663459eb9603d7f1f0345/mistune-0.8.4-py2.py3-none-any.whl
Collecting python-slugify (from contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/f5/ef/c868a9ac657405f051a8a501ac5633e769c54228716b8db7f8d717977e57/python-slugify-3.0.4.tar.gz
Collecting click>=5.1 (from flask->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl
Collecting itsdangerous>=0.24 (from flask->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
Collecting Jinja2>=2.10.1 (from flask->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/1d/e7/fd8b501e7a6dfe492a433deb7b9d833d39ca74916fa8bc63dd1a4947a671/Jinja2-2.10.1-py2.py3-none-any.whl
Collecting Werkzeug>=0.15 (from flask->contextualise==0.3.0)
  Downloading https://files.pythonhosted.org/packages/ce/42/3aeda98f96e85fd26180534d36570e4d18108d62ae36f87694b476b83d6f/Werkzeug-0.16.0-py2.py3-none-any.whl (327kB)
     |████████████████████████████████| 327kB 3.2MB/s
Collecting Flask-WTF>=0.13.1 (from flask-security->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/60/3a/58c629472d10539ae5167dc7c1fecfa95dd7d0b7864623931e3776438a24/Flask_WTF-0.14.2-py2.py3-none-any.whl
Collecting passlib>=1.7 (from flask-security->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/ee/a7/d6d238d927df355d4e4e000670342ca4705a72f0bf694027cf67d9bcf5af/passlib-1.7.1-py2.py3-none-any.whl
Collecting Flask-BabelEx>=0.9.3 (from flask-security->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/80/ad/cc2b0becd98050eed775ca85d6e5fa784547acff69f968183098df8a52b3/Flask-BabelEx-0.9.3.tar.gz
Collecting Flask-Principal>=0.3.3 (from flask-security->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/14/c7/2531aca6ab7baa3774fde2dfc9c9dd6d5a42576a1013a93701bfdc402fdd/Flask-Principal-0.4.0.tar.gz
Collecting Flask-Mail>=0.7.3 (from flask-security->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/05/2f/6a545452040c2556559779db87148d2a85e78a26f90326647b51dc5e81e9/Flask-Mail-0.9.1.tar.gz
Collecting Flask-Login>=0.3.0 (from flask-security->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/c1/ff/bd9a4d2d81bf0c07d9e53e8cd3d675c56553719bbefd372df69bf1b3c1e4/Flask-Login-0.4.1.tar.gz
Collecting cffi>=1.1 (from bcrypt->contextualise==0.3.0)
  Downloading https://files.pythonhosted.org/packages/f0/48/5aa4ea664eba26dd5142558d04762f5065c02220b4665b3f7eecb9bb614e/cffi-1.12.3-cp37-cp37m-macosx_10_9_x86_64.whl (169kB)
     |████████████████████████████████| 174kB 7.6MB/s
Collecting six>=1.4.1 (from bcrypt->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/73/fb/00a976f728d0d1fecfe898238ce23f502a721c0ac0ecfedb80e0d88c64e9/six-1.12.0-py2.py3-none-any.whl
Collecting typed-tree (from topic-db->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/12/15/5b406f42408bccd063c31465d111513f2ef25a992f58fdfcfb079ded12d7/typed_tree-1.0.3-py3-none-any.whl
Collecting psycopg2 (from topic-db->contextualise==0.3.0)
  Using cached https://files.pythonhosted.org/packages/5c/1c/6997288da181277a0c29bc39a5f9143ff20b8c99f2a7d059cfb55163e165/psycopg2-2.8.3.tar.gz
    ERROR: Command errored out with exit status 1:
     command: /private/tmp/c-ize/bin/python3.7 -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/k_/0fg5752j3vl3b814h2qyml_00000gn/T/pip-install-k4m2p3te/psycopg2/setup.py'"'"'; __file__='"'"'/private/var/folders/k_/0fg5752j3vl3b814h2qyml_00000gn/T/pip-install-k4m2p3te/psycopg2/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base pip-egg-info
         cwd: /private/var/folders/k_/0fg5752j3vl3b814h2qyml_00000gn/T/pip-install-k4m2p3te/psycopg2/
    Complete output (23 lines):
    running egg_info
    creating pip-egg-info/psycopg2.egg-info
    writing pip-egg-info/psycopg2.egg-info/PKG-INFO
    writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt
    writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt
    writing manifest file 'pip-egg-info/psycopg2.egg-info/SOURCES.txt'

    Error: pg_config executable not found.

    pg_config is required to build psycopg2 from source.  Please add the directory
    containing pg_config to the $PATH or specify the full executable path with the
    option:

        python setup.py build_ext --pg-config /path/to/pg_config build ...

    or with the pg_config option in 'setup.cfg'.

    If you prefer to avoid building psycopg2 from source, please install the PyPI
    'psycopg2-binary' package instead.

    For further information please check the 'doc/src/install.rst' file (also at
    <http://initd.org/psycopg/docs/install.html>).

    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

/tmp/contextualise master 8s
c-ize ❯

/tmp/contextualise master
c-ize ❯ git log
commit 1f97b45ad58de358772dafd313ce04367b2fbdd7 (HEAD -> master, origin/master, origin/develop, origin/HEAD)
Author: Brett Kromkamp <[email protected]>
Date:   Mon Sep 23 18:44:09 2019 +0200

    Updated README.rst file.

Running pip3 install psycopg2-binary and trying the above command again does not seem to resolve the issue.

Micro service-based Docker setup

Contextualise’s Docker support is still under development. What’s more, its current monolithic Docker setup should be refactored into a micro service-based setup for components such as PostgreSQL (database), Nginx (web-server), and so forth.

I really need help with this :)

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.