Coder Social home page Coder Social logo

glotzerlab / coxeter Goto Github PK

View Code? Open in Web Editor NEW
21.0 8.0 5.0 26.04 MB

Collection of tools to help initialize and manipulate shapes.

Home Page: https://coxeter.readthedocs.io/

License: BSD 3-Clause "New" or "Revised" License

Python 12.14% Jupyter Notebook 47.64% GLSL 39.86% TeX 0.35%
geometry shapes physics computational-geometry polyhedra polygons

coxeter's Introduction

coxeter

JOSS ReadTheDocs PyPI conda-forge

Welcome to the documentation for coxeter! The coxeter Python library provides tools for working with common geometric objects in two and three dimensions. Named for the 20th century geometer best known for his work on polytopes, coxeter is especially focused on polygons and polyhedra, but it also support various standard curved shapes such as spheres and ellipsoids.

The package emphasizes working with shapes as mutable objects whose geometric attributes may be accessed using property-based APIs. Since coxeter originally arose to support representations of anisotropic nanoparticles, many shapes support calculations of physical properties (such as form factors and inertia tensors) in addition to purely geometric ones. However, the package is designed with more general audiences in mind as well, and it aims to support precise calculations of a wide range of geometric quantities that are useful in a number of fields.

Some core features of coxeter include:

  • Libraries of common shapes to support easy construction.
  • Mutable shape objects that can be rescaled in a variety of ways to suit a number of needs.
  • Immediate access to geometric properties of shapes via Python properties of shape objects.
  • Plotting functionality to make it easy to visualize shapes in both two and three dimensions.

More detailed information on coxeter's features and examples of how to use them may be found in the documentation.

Setup

The recommended methods for installing coxeter are using pip or conda.

Installation via pip

To install the package from PyPI, execute:

pip install coxeter --user

Installation via conda

To install the package from conda, first add the conda-forge channel:

conda config --add channels conda-forge

After the conda-forge channel has been added, you can install coxeter by executing

conda install coxeter

Installation from source

Start by executing the following:

git clone https://github.com/glotzerlab/coxeter.git
cd coxeter

To install coxeter and other optional dependencies, choose one of the following:

pip install . # Install with no additional dependencies
pip install .[tests] # RECOMMENDED: Install with dependencies required to run pytests
pip install .[tests,doc] # Install all dependencies required to develop for coxeter

Requirements

  • Python >= 3.8
  • NumPy >= 1.19.0
  • SciPy >= 1.0.0
  • rowan >= 1.2.0

Testing

The package is currently tested for Python >= 3.8 on Unix-like systems. Continuous integrated testing is performed using Github actions on these Python versions.

First, install the packages required to test coxeter (if not already done):

pip install -r tests/requirements.txt

To run the packaged unit tests, execute the following line from the root of the repository:

pytest

To run the packaged unit tests with the coverage module:

pytest --cov=coxeter

Building Documentation

Documentation for coxeter is written in reStructuredText and compiled using Sphinx. To build the documentation, first install Sphinx and the other required packages:

pip install -r doc/requirements.txt
conda install -c conda-forge fresnel

Warning

The fresnel package on conda-forge must be used. The PyPI package fresnel is different and will not function properly.

You can then use Sphinx to create the actual documentation in either PDF or HTML form by running the following commands:

cd doc
make html # For html output
make latexpdf # For a LaTeX compiled PDF file
open build/html/index.html

Support and Contribution

This package is hosted on GitHub. Please report any bugs or problems that you find on the issue tracker. All contributions to coxeter are welcomed via pull requests!

coxeter's People

Contributors

b-butler avatar bdice avatar bvansade avatar cbkerr avatar dependabot[bot] avatar domfijan avatar eirrgang avatar harperic avatar j-proc avatar janbridley avatar joaander avatar kjcoulter avatar mariano-semelman-olx avatar pre-commit-ci[bot] avatar tcmoore3 avatar tfteague avatar tobias-dwyer avatar tommy-waltmann avatar vyasr avatar willzygmunt avatar

Stargazers

 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

coxeter's Issues

Shape2D Abstract Properties (perimeter, planar moments of inertia)

Feature description

I noticed that there are some abstract properties of Shape3D that are not mirrored for Shape2D.

Shape3D defines abstract volume, surface area, and inertia tensor properties.

Shape2D defines only area.

Proposed solution

I suggest adding perimeter and planar moments of inertia to the Shape2D abstract properties.

I believe the perimeter property is not yet implemented for polygon or its convex/sphero variants.

MathematicaToPython.py needs refactoring

The MathematicaToPython.py utility script is out of date and needs to be refactored. It refers to changed/removed APIs in coxeter.

Moreover, its intended usage isn't very clear to me, despite the long comment at the top. Is it possible to include a corresponding Mathematica script in this repository so the data is reproducible?

Should this file be kept someplace outside the coxeter package directory, in a scripts folder or something like that?

Sum and difference bodies

Description

Taking the sum or difference body of two shapes in 2D or 3D would not be difficult to implement and would be a nice feature. This could use duck typing to work with 2D or 3D vectors as well. I would recommend overwriting the __add__ and __sub__ methods of Poly classes for this.

Tasks

  • Create functions to calculate the sum and difference body and wrap results in the correct object
  • Use these functions to allow shape1 + shape2 and shape1 - shape2
  • Document these function
  • write unit tests for these functions

Points on the surface of shapes

Feature description

I would like the ability to get a set of points (ideally somewhat equally distributed) on the surface of the shapes.

Proposed solution

I could access the points through a property called points_on_surface, or something similar to that

Additional context

I am going to use this for the crystal structure prediction code that is in the beginning stages of development. If this feature is added, I may add a coxeter dependency to that package.

The feature would be used to get a set of grafting sites on the surface of the cores for grafting ligands onto.

All shapes should have a center

Feature description

It should be possible to define shapes with respect to some coordinate system. For this to work, shapes must all have a concept of a center that is settable.

Proposed solution

Polyhedra and polygons already have a center property. Spheres and ellipsoids should be generalized to support this as well.

Additional context

Solving this issue is a prerequisite for #59.

Add documentation for properties/methods inherited from the base shape classes

Searching for the term "isoperimetric quotient" does not show up with results for any of the classes where the property is inherited from the base class Shape3D. Only shapes with custom overrides show up (e.g. spheres always return exactly 1 and have a different docstring to indicate that). We need to add Sphinx documentation for properties/methods inherited from the base shape classes.

https://coxeter.readthedocs.io/en/latest/search.html?q=isoperimetric+quotient

Proposal: Shape getter

The package should provide a simple interface for creating shapes from an internally stored library of available shapes. The creation of the common shapes module from FreudShape is a good starting point, but we need a well-defined API. Here are some reasonable features we might expect from this feature with potential accessors (not a proposed API, just examples of what we'd hope to achieve):

  1. Access shapes by DOI (ex: euclid.shapes.get('10.1126/science.1220869') for Pablo's shapes)
  2. Access shapes by name (ex: euclid.shapes.get('cube'))
  3. Ability to request shape with specific volume (ex: euclid.shapes.get('cube', volume=2.0))
  4. Request parameterized shape (ex: euclid.shapes.get('323family', a=1, b=2, c=3))

We don't need to necessarily implement all of these, but we should define an API (or collection of APIs) that are sufficiently general that the features could be implemented if needed.

@csadorf I know we had some discussion of this, any thoughts on what else would be useful/necessary? @b-butler @willzygmunt feel free to tack on any additional features to this list that you think make sense.

Consistent conventions for inertia centering

An ongoing project is to allow every shape in coxeter to have a center (and possibly an orientation). Currently this is intrinsically possible for polytopes, which are specified by a set of vertices that can be placed arbitrarily. The center property gives the centroid of the polytope, and as part of #66 all other shapes such as ellipsoids will also be given a center (although in those cases the centers will be independent of the parameterization). However, this raises a question of the axes about which moments of inertia should be computed. For 3D shapes there's little reason not to use the origin of the absolute coordinate system and the coordinate axes to define the axes of rotation, but it may not be what users usually want in practice. On the other hand, for 2D shapes this is tricky, particularly the Polygon class since it's a 2D shape embedded in 3D. While this feature is generally useful because it encapsulates core logic useful for polyhedra, a polygon out of the plane does not have an intuitive choice of rotation axis (and of course an inertia tensor is meaningless, only one moment is finite).

Possible solutions:

  1. All inertia measurements should be done relative to the centroid of a shape. Users are required to apply the parallel axis theorem manually to compute rotation about an arbitrary axis.
  2. All inertia measurements are done relative to the origin. Users desiring the inertia tensor about the COM must set self.center = 0 prior to requesting the inertia tensor.
  3. Provide both measurements as separate properties (e.g. inertia_tensor and centered_inertia_tensor). This is actually pretty easy to do (the implementation of inertia_tensor in terms of centered_inertia_tensor should only be like 3 or 4 lines), so as long as this API is not confusing I would advocate for this option.

In either (2) or (3), a decision needs to be made on how to handle 3D polygons. IMO option (3) probably makes the most sense because there's a clear way to handle this; the centered_inertia_tensor always exists, but the inertia_tensor will raise an exception if the z component of the center is nonzero. The only question then is whether or not it makes sense for this to be a property or a method; it's generally frowned upon to throw exceptions in properties, but it isn't a hard and fast rule and I think in this sense it conceptually makes sense because it's basically a mathematical statement of "this property is not well defined in the case you're trying".

Should we leave originalpoints in Polyhedron class

Description

The Polyhedron class current stores the original points and this prevents some of the getters and setters to not use python properties. Storing the original points to me doesn't seem necessary. The user could keep a static copy if they wished. I propose removing this and allowing for more of the 'ers' to be properties.

Update docstrings

We need to convert the docstrings into Sphinx and make sure that all core functions have proper documentation. Something that might help is breathe, but that depends on whether or not the existing docstrings are actually proper doxygen. Given that we don't have too much code, it may be easier to just convert by hand.

Add shape __repr__ methods

Feature description

I would like to define __repr__ methods for shape classes. I find this to be very useful when developing interactively.

The current behavior without these methods is:

>>> coxeter.shapes.Sphere(3.0)
<coxeter.shapes.sphere.Sphere object at 0x7f5c869d6820>

Proposed solution

I like to write __repr__ methods to adhere to the invariant: repr(eval(repr(obj))) == repr(obj). However, this would result in very long representations for shapes with many vertices.

I recommend that for shapes with "fixed" numbers of inputs (e.g. spheres just have r, ellipsoids just have a, b, c), the representation result should match the constructor signature, like:

>>> ellipsoid = coxeter.shapes.Ellipsoid(1.0, 3.0, 2.0)
>>> ellipsoid
coxeter.shapes.Ellipsoid(a=1.0, b=3.0, c=2.0, center=(0, 0, 0))

For shapes with variable inputs (e.g. polygons), it would be fine to have something shorter like:

>>> triangle = coxeter.shapes.Polygon([[-1, 0], [0, 1], [1, 0]])
>>> triangle
coxeter.shapes.Polygon(vertices=<3 vertices>)

Insphere calculation

Feature description

The calculation of inspheres in the old shape classes is only correct in a very limited set of cases. In fact, inspheres are not even necessarily well-defined for many shapes, and the term is very ambiguous. In particular, for most irregular shapes the center of the largest bounded sphere may not even correspond to the centroid of the shape itself. We should implement one or more functions that calculate well-defined metrics that capture the quantities of interest people need when calculating they typically calculate inspheres.

Proposed solution

This paper describes a general (but very slow) algorithm for calculating the insphere of any convex polyhedron. Although in principle it is very slow (it's a combinatorial algorithm, so it's definitely not even a polynomial runtime algorithm), in practical use-cases this is probably not an important limitation. Implementing this algorithm is probably a sufficiently good insphere calculation to use.

Ellipsoid class

Feature description

We should implement an ellipsoid class (and a simple sphere subclass).

Make scipy.spatial a dependency

Description

We allow euclid to be used without scipy.spatial; however, if ConvexHull is not there it is set to None and will cause other functions to fail. scipy.spatial should just be required (most people have it installed anyways as the module is quite old now).

Tasks

  • Remove logic to allow for scipy.spatial to not be importable

Add high level documentation

Including a statement of need and maybe some other context. For example, this package does seem focused (but not limited) on the micro-scale and related sciences, but this is not mentioned anywhere.

There are guides for contributing and an API documentation, but not on other levels. You could take inspiration from the four levels of documentation and an implementation of that idea, such as the Django documentation.

Import magic in `euclid/__init__.py` should be moved to `euclid/common_shapes/__init__.py`

Description

The logic using in euclid/__init__.py should go into euclid/common_shapes/__init__.py . This keeps the logic self contained and allows common_shapes to be changed without having to look at the larger context. Then we could import everything from common shapes, or define an __all__ for common_shapes programmatically.

Tasks

  • Move logic to the other __init__.py
  • Import common_shapes.py into euclid module

Notes

This should be merged into the next branch.

Scalar multiplication for shapes

Feature description

I would like to be able to multiply a polyhedron or polygon by a scaling factor, which would apply as a scalar multiplication to its vertex vectors. Similarly, radii of spheres or spheropolytopes would scale linearly.

Proposed solution

Implement __mul__, etc: https://docs.python.org/3/library/operator.html#operator.__mul__

The operations should return a new shape instance.

Candidates:

  • __mul__ for shape * 1.5
  • __matmul__ for shape @ three_by_three_transformation_matrix
  • __truediv__ for shape / 1.5

Other things like negation (multiply all vertex vectors by -1), vector addition to all vertices, etc. are possible if desired.

Improved plotting for Spheropolyhedra

Feature description

It should be possible to plot the actual spheropolygon instead of the underlying polygon.

Proposed solution

matplotlib has a PathPatch module that allows you to draw arcs. The only thing to do here would be to figure out where the line segments intersect the circles on the vertices and draw the arcs based on those.

Additional context

It's probably not worth spending much time on this until there's a specific use case. I just wanted to make a note of it here.

Implement `is_inside` for spheropolyhedra

Feature description

It should be possible to check whether a set of points is contained in a spheropolyhedron. A similar feature exists for convex polyhedra.

Proposed solution

The API should match that of ConvexPolyhedron, which takes an array of points and returns an array of booleans indicating whether points are inside shape.

Should 2D shapes be orientable out of the plane?

Currently the Polygon class supports polygons embedded in 3D. If circles and ellipses were given an orientation in the form of a quaternion, they would also implicitly support this. However, we could also give them a single angle orientation that's a rotation about the z-axis.

This raises the question of whether polygons in 3D are useful, and more broadly whether 2D shapes in 3D are useful. Some of the features of the Polygon class are necessary to support polyhedra, because the easiest way to compute certain properties is by treating each facet of a polyhedron as a polygon. However, we could move the logic for rotating a 3D polygon into the plane from polygon.py to polyhedron.py, and then we would be able to simplify the existing polygon logic by removing any process of alignment or consideration of the normal direction. We essentially need some way of handling polygons in 3D, but we could move that to internal logic contained in the polyhedron file and just leave polygons as 2D.

The 3D polygon already works, so we should only make this change if we think it is clearer to users or prevents implementation difficulties down the road. I'm raising this issue because I'm seeing one obvious difficulty, which is how to handle moments of inertia in a way that isn't confusing to users.

Determine minimum required versions of dependencies

Currently numpy and scipy are listed as requirements without any particular version required. We should determine specific minimum version requirements and add them to both setup.py and requirements.txt.

Add tests for form factor

Feature description

It would be good to validate the form factor calculation much more thoroughly than the current implementation (either in the legacy ft.py module or in the new code in #92.

Proposed solution

There are many known form factors described here. We should use some of these as test cases.

Testing symmetry.py

We need to verify that the groups in symmetry.py have the correct set of operations. The best idea I have for how to do this is to take a set of points (e.g. a polyhedron) with the appropriate symmetry and make sure all the operations map that set onto itself.

Change all [in|circum][sphere|circle]* calculations to return Sphere objects

Feature description

Currently methods that generate some sort of bounding or bounded sphere return a center and a radius. Now that euclid has a Sphere object, it would be cleaner to simply return one of those.

Proposed solution

The Sphere class (as well as the Ellipse, Ellipsoid, and Circle) need to have a center property added to them. Once that is added, we can easily modify these functions to return Spheres instead of the current tuple.

Implement IQ in Polygon class

Feature description

To implement IQ in shape_classes.Polygon, which is currently raising notImplemented error.

Proposed solution

area function is already included. Will add perimeter function and iq.

Additional context

Ellipse class

Feature description

We should implement an ellipse class (and a simple circle subclass).

"center" should mean Centroid (Center of Mass for shapes with uniform density)

Currently the polyhedron.center property appears to be defined as an average of the vertices. However, this does not always coincide with the shape's center of mass: https://bell0bytes.eu/centroid-convex/

@property
def center(self):
""":math:`(3, )` :class:`numpy.ndarray` of float: Get or set the centroid of the shape.""" # noqa: E501
return np.mean(self.vertices, axis=0)

I recommend the following:

  • Clarify and define relevant properties (center = center of mass = centroid = barycenter) [1]
  • The current behavior of center could be retained under another name, but the proper name for this is unclear to me

[1] I note that Wikipedia says the center of mass, centroid, and barycenter are synonymous for shapes of uniform density:

While in geometry the word barycenter is a synonym for centroid, in astrophysics and astronomy, the barycenter is the center of mass of two or more bodies that orbit each other. In physics, the center of mass is the arithmetic mean of all points weighted by the local density or specific weight. If a physical object has uniform density, its center of mass is the same as the centroid of its shape.

Make setter names consistent

The setters for Python properties should consistently either use the name of the property or just value as the argument. This will improve code consistency and readability.

Additional property setters

Overview

The package currently has setters for many shape attributes, allowing users to "normalize" or otherwise rescale various shapes. For example, Sphere.volume can be set to a value, and the radius will be changed accordingly.

New setters

Some shapes are missing setters, like Ellipse.perimeter or Ellipsoid.surface_area. A thorough search should be done to add setters for all getters. The style should match that of #124.

Rescaling

I recommend the addition of a _rescale function (with an abstract method at the Shape level) that is defined for each shape class. Then, for instance, area setters can be implemented in Shape2D (with an abstract getter) simply by computing a ratio of current area to new area, taking the square root, and calling the shape's _rescale function. This is also a straightforward path to enable scalar multiplication #41.

Notes on accuracy and stability

For some shapes, e.g. circles and spheres, the radius for a given area/volume can be computed analytically. For other shapes, e.g. ellipses, the perimeter (or ellipsoid surface area) relies on elliptical integrals, which might not be accurate to full double precision (I don't know but I recall having slight issues with the precision in testing).

For the analytical cases, it may be preferable to use the analytical formula instead of rescaling the radius based on a ratio of current/new area, etc. For the cases that rely on elliptical integrals, we can probably count on it being "good enough precision."

Dedup core functionality

A lot of important functions exist in multiple places, for example utils.py has a lot of random functions that either are or should be elsewhere. We need to work on removing some of that code as we take inventory on what functions are important.

Improved caching

Feature description

Right now all properties are computed every time they are called. We should implement a caching mechanism by which the computed values are stored the first time they are computed.

Proposed solution

We should implement a decorator, e.g. cached_property, that stores computed properties into a global dict cache if they are not found in the cache. We should also implement a second decorator invalidates_cached_properties(property_names) that removes data from the cache whenever a function is run that invalidates some property (e.g. rescaling the area of a polygon invalidates the moment of inertia calculation).

Improve generation of testing points

In order to test a wide array of inputs for convex polytopes, many tests rely on generating convex hulls of random sets of points. However, there are many ways in which this choice can lead to hulls that are nearly degenerate, and parts of coxeter are currently not well equipped to handle that. Building extremely stable algorithms into the code base is out of scope, at least at present, since there is little need for representing such shapes, but the testing infrastructure would benefit from rewriting these tests to use a generation procedure that doesn't require rejecting so many inputs.

Rename subpackages

I propose the following API changes to subpackage names:

  • coxeter.shape_classes ➡️ coxeter.shapes
  • coxeter.shape_families ➡️ coxeter.families

Family523 S Documentation Corrections

Seems that there are some discrepancies with the documentation of the inverse/ golden ratio. The text is taken for S while the value and attribute name are s. And only one of the attributes is shown.

It might also be good to mention in the general class doc string that these Ss are based on the golden ratio. The current doc string is correct, but does rely on recognition of that form of the well known irrational.

Docs not building properly on `next`

Description

I'm trying to build the docs on the next branch; the build runs fine and reports no errors or warnings, but the shape_classes subpackage is not being automoduled correctly. The euclid page shows up on the homepage, but is empty.

To reproduce

$ cd /path/to/euclid
$ cd doc
$ make html
Running Sphinx v2.2.1
making output directory... done
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 3 source files that are out of date
updating environment: [new config] 3 added, 0 changed, 0 removed
reading sources... [100%] package-euclid                                                                                
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] package-euclid                                                                                 
generating indices...  genindex py-modindexdone
done
copying static files... ... done
copying extra files... done
dumping search index in English (code: en)... done
dumping object inventory... done
build succeeded.

The HTML pages are in build/html.

Error output

image

System configuration

$ python -c 'import platform; print(platform.platform()); import sys; print(sys.version); import euclid; print(euclid.__version__)'
Darwin-17.7.0-x86_64-i386-64bit
3.7.4 (default, Aug 13 2019, 15:17:50) 
[Clang 4.0.1 (tags/RELEASE_401/final)]
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AttributeError: module 'euclid' has no attribute '__version__'

Permanent versions of reference materials

Do we have a way to permanently save references to algorithms that are used, but aren't published in a journal? I'm thinking of references like this one, which is hosted on a personal web page which could disappear at any time without warning.

I know there's ways to archive webpages, but I don't know how that works out with licensing and stuff; I'm mostly just looking for input.

Supported DOIs should be documented

Feature description

The DOIs supported as arguments to coxeter.shape_families.doi_data_repositories.family_from_doi are not listed.

Proposed solution

It seems like a dictionary with built-in shape info should be in the public API (since there are only 3 valid values at present), and the supported DOIs should be in the documentation.

Additional context

coxeter.shape_families.doi_data_repositories.family_from_doi('10.1126/science.1220869')[0].data
is very long compared to the old code
euclid.damasceno.SHAPES
and it would be nice to expose this at a higher level in the package rather than 3 modules deep.

Example docstrings aren't rendered properly

Description

The syntax for embedded examples isn't quite right. It needs a few changes to match standards for Google style docstrings:

  1. Need a newline above the word "Example:" (one colon, not two).
  2. Need to wrap input lines as if typing into an interpreter with line continuation ...:
>>> print('This is a long expression and it is split across',
... 'two lines. Note the periods at the beginning of this line.')
  1. Some examples are a little lengthy and could be trimmed (do we need to get an incircle of a polygon and compute its area?)
  2. Write example code in a way that would pass through a formatter (e.g. black). For example, put spaces after commas in all lists of items:
vertices = [[1, 1], [1, -1], [-1, -1], [-1, 1]]
# instead of
vertices=[[1,1],[1,-1],[-1,-1],[-1,1]]

Here's what it looks like:

Incorrect syntax:

class ConvexPolygon(Polygon):
    """A convex polygon.

    The polygon is embedded in 3-dimensions, so the normal
    vector determines which way is "up".

    Args:
        ...
    Example::
        >>> square = coxeter.shape_classes.ConvexPolygon([[1,1],[-1,-1],
                                                          [1,-1],[-1,1]])
        >>> square.area
        4.0
        >>> # ...continued
    """

Fixed syntax:

class ConvexPolygon(Polygon):
    """A convex polygon.

    The polygon is embedded in 3-dimensions, so the normal
    vector determines which way is "up".

    Args:
        ...

    Example:
        >>> square = coxeter.shape_classes.ConvexPolygon(
        ...   [[1, 1], [-1, -1], [1, -1], [-1, 1]])
        >>> square.area
        4.0
        >>> # ...continued
    """

Incorrect output:
image

Fixed output:
image

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.