pyxem / orix

Analysing crystal orientations and symmetry in Python
https://orix.readthedocs.io
GNU General Public License v3.0
80 stars 48 forks source link

Simplify and standardize package structure and API #113

Closed hakonanes closed 4 years ago

hakonanes commented 4 years ago

I think this is a good time to (1) formalize some guides for the import structure and (2) simplify the API.

I see there was an attempt to simplify the API via orix.objects and orix.symmetry, is this still the goal?

I think there are generally 2,5 (2 and 3 go together) options for an import structure:

  1. Import everything
    >>> import orix
    >>> orix.vector.Vector3d.xvector()
    Vector3d (1,)
    [[1 0 0]]
  2. Import modules/submodules/sub-packages
    >>> from orix import vector
    >>> vector.Vector3d.xvector()
    Vector3d (1,)
    [[1 0 0]]
  3. Import functions and classes
    >>> from orix.vector import Vector3d
    >>> Vector3d.xvector()
    Vector3d (1,)
    [[1 0 0]]

I think we shouldn't make anything available from orix (except __version__ etc.), and force users to either import modules, or functions and classes from modules.

We should also make the API as intuitive as possible. This is an example of how it is now for the orix.quaternion module, which I think is unintuitive

>>> from orix.quaternion import Quaternion
>>> from orix.quaternion.orientation import Orientation
>>> from orix.quaternion.orientation_region import OrientationRegion
>>> from orix.quaternion.symmetry import Symmetry

It should be like this

>>> from orix.quaternion import Quaternion, Orientation, OrientationRegion, Symmetry

In general I'm a fan of these guiding principles:

scikit-image does it like this: https://github.com/scikit-image/scikit-image/blob/master/skimage/__init__.py. I like their import structure a lot, and would like us to use that.

Practically speaking I think what is required is to

These changes would create this (public) API

>>> from orix.crystal_map import CrystalMap, CrystalMapProperties, Phase, PhaseList
>>> from orix.io import load, save, loadang, loadctf
>>> from orix.plot import CrystalMapPlot, AxAnglePlot, RodriguesPlot, RotationPlot
>>> from orix.quaternion import Quaternion, Rotation, Misorientation, Orientation, OrientationRegion, Symmetry
>>> from orix.sampling import get_sample_fundamental, get_sample_local, uniform_SO3_sample
>>> from orix.scalar import Scalar
>>> from orix.vector import Vector3d, AxAngle, Homochoric, NeoEuler, Rodrigues, SphericalRegion
pc494 commented 4 years ago

So I did read the whole post, but I think the clarity of the final code block is pretty compelling.

On the more minor things, I think Object3d should be private and we might also want to check if a couple of the other Classes could go private (possibly a 1.0 thing, #110).

Similarly, although not something we endorse, I think offering

>>> from orix import *

wouldn't be the worst idea.

Not to detract from the main point, which is yes this a good idea.

hakonanes commented 4 years ago

Okay, to offer from orix import * we would have to import all modules in orix/__init__.py alongside the __version__ etc. (scikit-image does not allow this). Then we offer all three options, and everyone should be happy, right?

pc494 commented 4 years ago

On further reflection, ignore me. While I anticipated some users will condense

from orix.quaternion import Quaternion, Rotation, Misorientation, Orientation, OrientationRegion, Symmetry

to

from orix.quaternion import *

I think it's too rare a use-case for us to go out of the way to accommodate it. So perhaps stick with your original plan?

hakonanes commented 4 years ago

Yeah, from orix.quaternion import * is supported without anything new in orix/__init__.py.

dnjohnstone commented 4 years ago

Yeah, this is good - I've even changed the label from discussion to enhancement because I think it's a no brainer.