hgrecco / pint

Operate and manipulate physical quantities in Python
http://pint.readthedocs.org/
Other
2.37k stars 466 forks source link

Get all compatible units #610

Closed terranjp closed 1 year ago

terranjp commented 6 years ago

Is there a way to get all of the available compatible units?

The documentation shows this method:

In [4]: x = 1 * ureg['foot']
In [5]: ureg.get_compatible_units(x)
Out[5]:
frozenset({<Unit('angstrom')>,
           <Unit('thou')>,
           <Unit('inch')>,
           <Unit('link')>,
           <Unit('foot')>,
           <Unit('survey_foot')>,
           <Unit('yard')>,
           <Unit('rod')>,
           <Unit('mile')>,
           <Unit('survey_mile')>,
           <Unit('league')>,
           <Unit('light_year')>})

But there are a units missing such as "meter", "nautical_mile", "chain", "fathom", etc.

Is there where to query the registry by dimension?

I am working on a simple GUI for Pint and integration with Spyder's variable explorer and it would very helpful to get a list all compatible units.

EDIT: Of course after I submit this I start getting ideas. I came up with this method but it kind of feels dirty for some reason but it appears to get what I am after.

compatible_units = set()

for unit_str in dir(ureg):
    unit = getattr(ureg, unit_str)

    if hasattr(unit, 'dimensionality'):
        if unit.dimensionality == x.dimensionality:
            compatible_units.add(unit)

Resulting in a more 'complete' set of compatible units:

{<Unit('angstrom')>,
 <Unit('thou')>,
 <Unit('point')>,
 <Unit('millimeter')>,
 <Unit('pica')>,
 <Unit('centimeter')>,
 <Unit('inch')>,
 <Unit('link')>,
 <Unit('foot')>,
 <Unit('survey_foot')>,
 <Unit('yard')>,
 <Unit('meter')>,
 <Unit('fathom')>,
 <Unit('rod')>,
 <Unit('chain')>,
 <Unit('furlong')>,
 <Unit('kilometer')>,
 <Unit('mile')>,
 <Unit('us_statute_mile')>,
 <Unit('survey_mile')>,
 <Unit('nautical_mile')>,
 <Unit('league')>,
 <Unit('astronomical_unit')>,
 <Unit('light_year')>,
 <Unit('parsec')>}

Is there a cleaner built in method that attains similar results?

poutant1 commented 6 years ago

Hi, I too would like this functionality! Would be great when implementing something that allows user to select data type using this package. Thanks!

poutant1 commented 6 years ago

Also having something like a human-readable name in Unit entries for prettier presentation in web development would do

hgrecco commented 1 year ago

This was fixed long ago. get_compatible_units return all compatible units (removing prefixes). Feel free to reopen.

jakeogh commented 1 year ago

Sorry if I'm missing a newer issue, but why does ureg.foot.compatible_units() not include <Unit('inch')>?

In [1]: >>>: from pint import UnitRegistry; ureg = UnitRegistry()

In [2]: >>>: ureg.foot
Out[2]: <Unit('foot')>

In [3]: >>>: ureg.foot.compatible_units()
Out[3]: 
frozenset({<Unit('planck_length')>,
           <Unit('fermi')>,
           <Unit('classical_electron_radius')>,
           <Unit('x_unit_Cu')>,
           <Unit('x_unit_Mo')>,
           <Unit('bohr')>,
           <Unit('angstrom')>,
           <Unit('angstrom_star')>,
           <Unit('lattice_spacing_of_Si')>,
           <Unit('micron')>,
           <Unit('meter')>,
           <Unit('nautical_mile')>,
           <Unit('astronomical_unit')>,
           <Unit('light_year')>,
           <Unit('parsec')>})

In [4]: >>>: ureg.inch
Out[4]: <Unit('inch')>

(on pint git-latest)

Workaround from @terranjp:

$ cat comp_units_test.py ; ./comp_units_test.py
#!/usr/bin/env python3

from pint import Unit
from pint import UnitRegistry
from pint.errors import UndefinedUnitError

def get_compatiable_units(ureg, x):
    compatible_units = set()

    for unit_str in dir(ureg):
        try:
            unit = getattr(ureg, unit_str)
        except UndefinedUnitError:
            continue
        if not isinstance(unit, Unit):
            continue
        if hasattr(unit, "dimensionality"):
            if unit.dimensionality == x.dimensionality:
                compatible_units.add(unit)

    return compatible_units

ureg = UnitRegistry()
unit_def_string = 'royal_cubit = 52.3 * cm = _ = '
ureg.define(unit_def_string)

_compat = get_compatiable_units(ureg, ureg.foot)
for _ in _compat:
    print(_)

decimeter
parsec
kilometer
bohr
cicero
micrometer
astronomical_unit
light_year
lattice_spacing_of_Si
centimeter
chain
fathom
point
thou
planck_length
cables_length
yard
foot
league
micron
x_unit_Cu
femtometer
didot
link
rod
tex_didot
meter
mile
classical_electron_radius
css_pixel
tex_cicero
nautical_mile
hand
tex_pica
millimeter
scaled_point
royal_cubit
survey_mile
furlong
angstrom
survey_foot
angstrom_star
tex_point
statfarad
fermi
x_unit_Mo
inch
pica