coordinates


Namecoordinates JSON
Version 0.4.0 PyPI version JSON
download
home_pagehttps://github.com/clbarnes/coordinates
SummaryConvenience class for doing maths with explicit coordinates
upload_time2020-01-06 14:07:16
maintainer
docs_urlNone
authorChris L Barnes
requires_python>=3.6
licenseMIT
keywords coordinate spatial mathdict
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI
coveralls test coverage No coveralls.
            # coordinates

[![Build Status](https://travis-ci.org/clbarnes/coordinates.svg?branch=master)](https://travis-ci.org/clbarnes/coordinates)
[![Python Versions](https://img.shields.io/pypi/pyversions/coordinates)](https://pypi.org/project/coordinates/)

Convenience class for dealing with coordinates which need both maths and explicit ordering.

## Motivation

Numpy arrays are great for doing maths with coordinates stored as arrays.

Dicts are great for dealing with coordinate systems where the order keeps changing
(e.g. between C and Fortran order).

But what if you want both?

(Note: if you're doing *lots* of maths... stick with `numpy`)

## Installation

```bash
pip install coordinates
```

## Usage

`Coordinate`s are `Mapping`s (i.e. `dict`-like). They don't expose an interface for mutation, but
we're all consenting adults so if you really want to modify the internal `_dict`, I won't
stop you.

### Instantiation

They can be instantiated in any of the ways a `dict` can (from another `Mapping`, a sequence of pairs,
some keyword arguments, or a mixture of the above).

```python
from coordinates import Coordinate

Coordinate({'x': 1, 'y': 2})
Coordinate({'x': 1}, y=2)
Coordinate([('x', 1), ('y', 2)])
Coordinate(x=1, y=2)
```

If an order is defined (more on this later), you can also instantiate a `Coordinate` from a single
argument which is a sequence, or from a number of `*args`.

```python
Coordinate([1, 2], order='xy')
Coordinate(1, 2, order='xy')

Coordinate.default_order = 'xy'
Coordinate([1, 2])
Coordinate(1, 2)
```

Because `Mapping`s can be instantiated from other `Mapping`s, you can "extend" existing coordinates
into new dimensions.

```python
coord_2d = Coordinate(x=1, y=2)
coord_3d = Coordinate(coord_2d, z=3)
```

Finally, many `Coordinate`s can be instantiated lazily using `from_sequence`:

```python
Coordinate.from_sequence([(1, 2, 3), (3, 4, 5)], order='xyz')
Coordinate.from_sequence([{'x': 1, 'y': 2}, {'x': 3, 'y': 4}], z=10)
```

To note:

- `order`-dependent instantiation is incompatible with `**kwargs`
- Instantiation from a sequence of tuples will fail in 2D because it will be interpreted as
key-value pairs. Use a comprehension here instead: `Coordinate.from_sequence(zip('xy', row) for row in sequence)`

### Maths

Coordinates do maths like you might expect them to, where the other operand is anything dict-like
with the same keys, or a number.

```python
coord = Coordinate(x=1, y=2, z=3)

coord * 2 == Coordinate(x=2, y=4, z=6)
>>> True

coord ** 2 == Coordinate(x=1, y=4, z=9)
>>> True

coord + coord == Coordinate(x=2, y=4, z=3)
>>> True

coord += 1  # coord is a reference to a new object; no mutation
coord == Coordinate(x=2, y=3, z=4)
>>> True

abs(Coordinate(x=-10, y=10)) == Coordinate(x=10, y=10)
>>> True

import math
math.ceil(Coordinate(x=0.5)) == Coordinate(x=1)
>>> True

math.floor(Coordinate(x=0.5)) == Coordinate(x=0)
>>> True
```

They also have some convenience methods for getting the sum, product or norm of their keys.

```python
coord.sum() == 9
>>> True

coord.prod() == 24
>>> True

Coordinate(x=3, y=4).norm(order=2) == 5
>>> True
```

### Ordering

You can get the keys, values or items of the `Coordinate` in a specific order:

```python
coord.to_list('yxz') == [2, 1, 3]
>>> True

list(coord.items('yxz')) == [('y', 2), ('x', 1), ('z', 3)]
>>> True
```

The default order for a single instance can be given on instantiation, or mutated (this does not affect equality).

The default order for all `Coordinate`s can be set on the class. This affects existing instances, but does not
override their order if it was set explicitly.

If neither an instance `order` or a class `default_order` is set, it falls back to reverse lexicographic.

```python
coord3 = Coordinate(x=1, y=2, z=3, order='zxy')
coord3.order = 'yzx'

Coordinate.default_order = 'xyz'
```

### Subclassing

If you're working in one space, the `spaced_coordinate` factory can create custom subclasses with a fixed set of
keys and optionally a default order.

```python
from coordinates import spaced_coordinate
CoordinateXYZC = spaced_coordinate('CoordinateXYZC', 'xyzc')

# this will raise a ValueError
CoordinateXYZC(x=1, y=2, z=3)
```

Or you can subclass `Coordinate` directly.

### Value access

Coordinate values can be accessed with dict-like syntax (`coord['x']`, `coord.get('y', 2)`) or, for convenience,
attribute-like (`coord.z`) if the keys are strings.

## Note

If you don't want the order-related functionality for another application, the base class `MathDict` is
implemented here too.



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/clbarnes/coordinates",
    "name": "coordinates",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "coordinate spatial mathdict",
    "author": "Chris L Barnes",
    "author_email": "barnesc@janelia.hhmi.org",
    "download_url": "https://files.pythonhosted.org/packages/b1/ed/06617f24371b48875b3b24f5e558c5606daad2be7a00d0099a14b70636ad/coordinates-0.4.0.tar.gz",
    "platform": "",
    "description": "# coordinates\n\n[![Build Status](https://travis-ci.org/clbarnes/coordinates.svg?branch=master)](https://travis-ci.org/clbarnes/coordinates)\n[![Python Versions](https://img.shields.io/pypi/pyversions/coordinates)](https://pypi.org/project/coordinates/)\n\nConvenience class for dealing with coordinates which need both maths and explicit ordering.\n\n## Motivation\n\nNumpy arrays are great for doing maths with coordinates stored as arrays.\n\nDicts are great for dealing with coordinate systems where the order keeps changing\n(e.g. between C and Fortran order).\n\nBut what if you want both?\n\n(Note: if you're doing *lots* of maths... stick with `numpy`)\n\n## Installation\n\n```bash\npip install coordinates\n```\n\n## Usage\n\n`Coordinate`s are `Mapping`s (i.e. `dict`-like). They don't expose an interface for mutation, but\nwe're all consenting adults so if you really want to modify the internal `_dict`, I won't\nstop you.\n\n### Instantiation\n\nThey can be instantiated in any of the ways a `dict` can (from another `Mapping`, a sequence of pairs,\nsome keyword arguments, or a mixture of the above).\n\n```python\nfrom coordinates import Coordinate\n\nCoordinate({'x': 1, 'y': 2})\nCoordinate({'x': 1}, y=2)\nCoordinate([('x', 1), ('y', 2)])\nCoordinate(x=1, y=2)\n```\n\nIf an order is defined (more on this later), you can also instantiate a `Coordinate` from a single\nargument which is a sequence, or from a number of `*args`.\n\n```python\nCoordinate([1, 2], order='xy')\nCoordinate(1, 2, order='xy')\n\nCoordinate.default_order = 'xy'\nCoordinate([1, 2])\nCoordinate(1, 2)\n```\n\nBecause `Mapping`s can be instantiated from other `Mapping`s, you can \"extend\" existing coordinates\ninto new dimensions.\n\n```python\ncoord_2d = Coordinate(x=1, y=2)\ncoord_3d = Coordinate(coord_2d, z=3)\n```\n\nFinally, many `Coordinate`s can be instantiated lazily using `from_sequence`:\n\n```python\nCoordinate.from_sequence([(1, 2, 3), (3, 4, 5)], order='xyz')\nCoordinate.from_sequence([{'x': 1, 'y': 2}, {'x': 3, 'y': 4}], z=10)\n```\n\nTo note:\n\n- `order`-dependent instantiation is incompatible with `**kwargs`\n- Instantiation from a sequence of tuples will fail in 2D because it will be interpreted as\nkey-value pairs. Use a comprehension here instead: `Coordinate.from_sequence(zip('xy', row) for row in sequence)`\n\n### Maths\n\nCoordinates do maths like you might expect them to, where the other operand is anything dict-like\nwith the same keys, or a number.\n\n```python\ncoord = Coordinate(x=1, y=2, z=3)\n\ncoord * 2 == Coordinate(x=2, y=4, z=6)\n>>> True\n\ncoord ** 2 == Coordinate(x=1, y=4, z=9)\n>>> True\n\ncoord + coord == Coordinate(x=2, y=4, z=3)\n>>> True\n\ncoord += 1  # coord is a reference to a new object; no mutation\ncoord == Coordinate(x=2, y=3, z=4)\n>>> True\n\nabs(Coordinate(x=-10, y=10)) == Coordinate(x=10, y=10)\n>>> True\n\nimport math\nmath.ceil(Coordinate(x=0.5)) == Coordinate(x=1)\n>>> True\n\nmath.floor(Coordinate(x=0.5)) == Coordinate(x=0)\n>>> True\n```\n\nThey also have some convenience methods for getting the sum, product or norm of their keys.\n\n```python\ncoord.sum() == 9\n>>> True\n\ncoord.prod() == 24\n>>> True\n\nCoordinate(x=3, y=4).norm(order=2) == 5\n>>> True\n```\n\n### Ordering\n\nYou can get the keys, values or items of the `Coordinate` in a specific order:\n\n```python\ncoord.to_list('yxz') == [2, 1, 3]\n>>> True\n\nlist(coord.items('yxz')) == [('y', 2), ('x', 1), ('z', 3)]\n>>> True\n```\n\nThe default order for a single instance can be given on instantiation, or mutated (this does not affect equality).\n\nThe default order for all `Coordinate`s can be set on the class. This affects existing instances, but does not\noverride their order if it was set explicitly.\n\nIf neither an instance `order` or a class `default_order` is set, it falls back to reverse lexicographic.\n\n```python\ncoord3 = Coordinate(x=1, y=2, z=3, order='zxy')\ncoord3.order = 'yzx'\n\nCoordinate.default_order = 'xyz'\n```\n\n### Subclassing\n\nIf you're working in one space, the `spaced_coordinate` factory can create custom subclasses with a fixed set of\nkeys and optionally a default order.\n\n```python\nfrom coordinates import spaced_coordinate\nCoordinateXYZC = spaced_coordinate('CoordinateXYZC', 'xyzc')\n\n# this will raise a ValueError\nCoordinateXYZC(x=1, y=2, z=3)\n```\n\nOr you can subclass `Coordinate` directly.\n\n### Value access\n\nCoordinate values can be accessed with dict-like syntax (`coord['x']`, `coord.get('y', 2)`) or, for convenience,\nattribute-like (`coord.z`) if the keys are strings.\n\n## Note\n\nIf you don't want the order-related functionality for another application, the base class `MathDict` is\nimplemented here too.\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Convenience class for doing maths with explicit coordinates",
    "version": "0.4.0",
    "project_urls": {
        "Homepage": "https://github.com/clbarnes/coordinates"
    },
    "split_keywords": [
        "coordinate",
        "spatial",
        "mathdict"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7bd32882a9189ef47015661cf3eb38253dbe18e446da4d6f61f20080ad3ae930",
                "md5": "0ecfcbf72c7651764c4c136302861630",
                "sha256": "5dcab7b939f774e2a7ca1ac79af9f38233767d5a33bca5e0c7a7c9200450e636"
            },
            "downloads": -1,
            "filename": "coordinates-0.4.0-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0ecfcbf72c7651764c4c136302861630",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.6",
            "size": 7026,
            "upload_time": "2020-01-06T14:07:15",
            "upload_time_iso_8601": "2020-01-06T14:07:15.533165Z",
            "url": "https://files.pythonhosted.org/packages/7b/d3/2882a9189ef47015661cf3eb38253dbe18e446da4d6f61f20080ad3ae930/coordinates-0.4.0-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b1ed06617f24371b48875b3b24f5e558c5606daad2be7a00d0099a14b70636ad",
                "md5": "b87331035efb1c9fab7f26b068f4d891",
                "sha256": "4014374183909b7bab3c4bfd691b6fcf17bc6063ab7b7307d0f0ababaacfdafa"
            },
            "downloads": -1,
            "filename": "coordinates-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "b87331035efb1c9fab7f26b068f4d891",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 6739,
            "upload_time": "2020-01-06T14:07:16",
            "upload_time_iso_8601": "2020-01-06T14:07:16.699868Z",
            "url": "https://files.pythonhosted.org/packages/b1/ed/06617f24371b48875b3b24f5e558c5606daad2be7a00d0099a14b70636ad/coordinates-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2020-01-06 14:07:16",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "clbarnes",
    "github_project": "coordinates",
    "travis_ci": true,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "tox": true,
    "lcname": "coordinates"
}
        
Elapsed time: 0.11903s