子類化

NDData

このような役割を果たしています numpy.ndarray (あるいは1つのものを提示する) numpy -クラスインタフェース) data 属性です。

注釈

各属性は,1つのプリアンブル下線を持つ属性として存在する.例えば data 名前を付けて保存 _data そして mask として _mask ちょっと待って。

別の属性を追加する

>>> from astropy.nddata import NDData
>>> class NDDataWithFlags(NDData):
...     def __init__(self, *args, **kwargs):
...         # Remove flags attribute if given and pass it to the setter.
...         self.flags = kwargs.pop('flags') if 'flags' in kwargs else None
...         super().__init__(*args, **kwargs)
...
...     @property
...     def flags(self):
...         return self._flags
...
...     @flags.setter
...     def flags(self, value):
...         self._flags = value
>>> ndd = NDDataWithFlags([1,2,3])
>>> ndd.flags is None
True
>>> ndd = NDDataWithFlags([1,2,3], flags=[0, 0.2, 0.3])
>>> ndd.flags
[0, 0.2, 0.3]

注釈

サブクラス化を簡略化するために,setterごと(除く) data )が呼び出される __init__ したがって,setter内部で任意の属性を制限することができ,事例作成過程にも適用可能である.

カスタム属性の設定器

>>> import numpy as np
>>> class NDDataMaskBoolNumpy(NDData):
...
...     @NDData.mask.setter
...     def mask(self, value):
...         # Convert mask to boolean numpy array.
...         self._mask = np.array(value, dtype=np.bool_)
>>> ndd = NDDataMaskBoolNumpy([1,2,3])
>>> ndd.mask = [True, False, True]
>>> ndd.mask
array([ True, False,  True]...)

拡張属性のSetter

unit, meta, and uncertainty implement some additional logic in their setter so subclasses might define a call to the superclass and let the super property set the attribute afterwards:

>>> import numpy as np

>>> class NDDataUncertaintyShapeChecker(NDData):
...
...     @NDData.uncertainty.setter
...     def uncertainty(self, value):
...         value = np.asarray(value)
...         if value.shape != self.data.shape:
...             raise ValueError('uncertainty must have the same shape as the data.')
...         # Call the setter of the super class in case it might contain some
...         # important logic (only True for meta, unit and uncertainty)
...         super(NDDataUncertaintyShapeChecker, self.__class__).uncertainty.fset(self, value)
...         # Unlike "super(cls_name, cls_name).uncertainty.fset" or
...         # or "NDData.uncertainty.fset" this will respect Pythons method
...         # resolution order.

>>> ndd = NDDataUncertaintyShapeChecker([1,2,3], uncertainty=[2,3,4])
INFO: uncertainty should have attribute uncertainty_type. [astropy.nddata.nddata]
>>> ndd.uncertainty
UnknownUncertainty([2, 3, 4])

データに設定器を設定する

>>> class NDDataWithDataSetter(NDData):
...
...     @NDData.data.setter
...     def data(self, value):
...         self._data = np.asarray(value)
>>> ndd = NDDataWithDataSetter([1,2,3])
>>> ndd.data = [3,2,1]
>>> ndd.data
array([3, 2, 1])

NDDataRef

NDDataRef それ自体が継承されています NDData したがって,どのような可能性もNDDataRefに適用される.しかしNDDataRefはMixinからも継承されています

これは追加的な操作を可能にする。

別の算術演算を追加する

別の操作を追加することができます data そして unit それを許すのは Quantity それがそうです。

実例.

電源関数を追加するには、以下の操作を実行してください。

>>> from astropy.nddata import NDDataRef
>>> import numpy as np
>>> from astropy.utils import sharedmethod

>>> class NDDataPower(NDDataRef):
...     @sharedmethod # sharedmethod to allow it also as classmethod
...     def pow(self, operand, operand2=None, **kwargs):
...         # the uncertainty doesn't allow propagation so set it to None
...         kwargs['propagate_uncertainties'] = None
...         # Call the _prepare_then_do_arithmetic function with the
...         # numpy.power ufunc.
...         return self._prepare_then_do_arithmetic(np.power, operand,
...                                                 operand2, **kwargs)

これは、以下と同様の他の算術方法を使用するように使用することができる add() それがそうです。したがって、クラスまたはインスタンスでアップグレードされると、それが機能する:

>>> ndd = NDDataPower([1,2,3])

>>> # using it on the instance with one operand
>>> ndd.pow(3)
NDDataPower([ 1,  8, 27])

>>> # using it on the instance with two operands
>>> ndd.pow([1,2,3], [3,4,5])
NDDataPower([  1,  16, 243])

>>> # or using it as classmethod
>>> NDDataPower.pow(6, [1,2,3])
NDDataPower([  6,  36, 216])

伝播を可能にするためには uncertainty サブクラス化を参照してください NDUncertainty それがそうです。

♪the _prepare_then_do_arithmetic 1つまたは2つのオペランドが与えられた場合、必要に応じてオペランドを適切なクラスに変換するために、クラスまたはインスタンスでそれをアップレギュレートするかどうかの関連チェックが実装される。覆う _prepare_then_do_arithmetic 可能であれば,サブクラスでの使用は避けるべきである.

既存の属性上の算術演算

関数呼び出しのいくつかのパラメータを使用して、例えば、演算中に既存の属性を処理する方法をカスタマイズすることができる add() しかし,行為をハードコードすることも可能である.属性上の実際の操作(除く) unit )は1つの方法で行われています _arithmetic_* どこだ? * 属性の名前です。

実例.

カスタマイズしてどのように使うか meta 演算プロセスにおいて影響を受けることになる:

>>> from astropy.nddata import NDDataRef

>>> from copy import deepcopy
>>> class NDDataWithMetaArithmetics(NDDataRef):
...
...     def _arithmetic_meta(self, operation, operand, handle_mask, **kwds):
...         # the function must take the arguments:
...         # operation (numpy-ufunc like np.add, np.subtract, ...)
...         # operand (the other NDData-like object, already wrapped as NDData)
...         # handle_mask (see description for "add")
...
...         # The meta is dict like but we want the keywords exposure to change
...         # Anticipate that one or both might have no meta and take the first one that has
...         result_meta = deepcopy(self.meta) if self.meta else deepcopy(operand.meta)
...         # Do the operation on the keyword if the keyword exists
...         if result_meta and 'exposure' in result_meta:
...             result_meta['exposure'] = operation(result_meta['exposure'], operand.data)
...         return result_meta # return it

この方法をトリガする場合は、ご利用ください handle_meta 算術方法のパラメータは除算であってもよい None あるいは…。 "first_found" **

>>> ndd = NDDataWithMetaArithmetics([1,2,3], meta={'exposure': 10})
>>> ndd2 = ndd.add(10, handle_meta='')
>>> ndd2.meta
{'exposure': 20}

>>> ndd3 = ndd.multiply(0.5, handle_meta='')
>>> ndd3.meta
{'exposure': 5.0}

警告

これらの内部を使って _arithmetic_* メソッド呼び出し操作には属性に制限がある:

  • mask: handle_mask must not be None, "ff", or "first_found".

  • wcscompare_wcs パラメータは,マスクと同じ制約を持つ.

  • metahandle_meta パラメータは,マスクと同じ制約を持つ.

  • uncertainty: propagate_uncertainties must be None or evaluate to False. arithmetic_uncertainty must also accept different arguments: operation, operand, result, correlation, **kwargs.

算術演算のデフォルトパラメータを変更する

目標が算術方法の既存のパラメータのデフォルト値を変更することである場合(例えば、算術演算を呼び出すたびにパラメータを明示的に指定するのは大変である)、方法署名において既存のパラメータのデフォルト値を変更することによって、値を変更することができる。 _arithmetic それがそうです。

例を引く

算術方法の既存のパラメータのデフォルト値を変更するには、以下の動作を実行してください。

>>> from astropy.nddata import NDDataRef
>>> import numpy as np

>>> class NDDDiffAritDefaults(NDDataRef):
...     def _arithmetic(self, *args, **kwargs):
...         # Changing the default of handle_mask to None
...         if 'handle_mask' not in kwargs:
...             kwargs['handle_mask'] = None
...         # Call the original with the updated kwargs
...         return super()._arithmetic(*args, **kwargs)

>>> ndd1 = NDDDiffAritDefaults(1, mask=False)
>>> ndd2 = NDDDiffAritDefaults(1, mask=True)
>>> ndd1.add(ndd2).mask is None  # it will be None
True

>>> # But giving other values is still possible:
>>> ndd1.add(ndd2, handle_mask=np.logical_or).mask
True

>>> ndd1.add(ndd2, handle_mask="ff").mask
False

The parameter controlling how properties are handled are all keyword-only so using the *args, **kwargs approach allows you to only alter one default without needing to care about the positional order of arguments.

付加的な性質を持つ算術

これはまた書き直す必要がある _arithmetic 方法です。もし私たちが1つあるとしましょう flags 属性再出現:

>>> from copy import deepcopy
>>> import numpy as np

>>> class NDDataWithFlags(NDDataRef):
...     def __init__(self, *args, **kwargs):
...         # Remove flags attribute if given and pass it to the setter.
...         self.flags = kwargs.pop('flags') if 'flags' in kwargs else None
...         super().__init__(*args, **kwargs)
...
...     @property
...     def flags(self):
...         return self._flags
...
...     @flags.setter
...     def flags(self, value):
...         self._flags = value
...
...     def _arithmetic(self, operation, operand, *args, **kwargs):
...         # take all args and kwargs to allow arithmetic on the other properties
...         # to work like before.
...
...         # do the arithmetics on the flags (pop the relevant kwargs, if any!!!)
...         if self.flags is not None and operand.flags is not None:
...             result_flags = np.logical_or(self.flags, operand.flags)
...             # np.logical_or is just a suggestion you can do what you want
...         else:
...             if self.flags is not None:
...                 result_flags = deepcopy(self.flags)
...             else:
...                 result_flags = deepcopy(operand.flags)
...
...         # Let the superclass do all the other attributes note that
...         # this returns the result and a dictionary containing other attributes
...         result, kwargs = super()._arithmetic(operation, operand, *args, **kwargs)
...         # The arguments for creating a new instance are saved in kwargs
...         # so we need to add another keyword "flags" and add the processed flags
...         kwargs['flags'] = result_flags
...         return result, kwargs # these must be returned

>>> ndd1 = NDDataWithFlags([1,2,3], flags=np.array([1,0,1], dtype=bool))
>>> ndd2 = NDDataWithFlags([1,2,3], flags=np.array([0,0,1], dtype=bool))
>>> ndd3 = ndd1.add(ndd2)
>>> ndd3.flags
array([ True, False,  True]...)

既存の属性を切断する

2 Dが必要なクラスがあるとしましょう data しかしマスクは一次元にすぎない。2つの次元に分割すると、これが問題になる。

>>> from astropy.nddata import NDDataRef
>>> import numpy as np
>>> class NDDataMask1D(NDDataRef):
...     def _slice_mask(self, item):
...         # Multidimensional slices are represented by tuples:
...         if isinstance(item, tuple):
...             # only use the first dimension of the slice
...             return self.mask[item[0]]
...         # Let the superclass deal with the other cases
...         return super()._slice_mask(item)
>>> ndd = NDDataMask1D(np.ones((3,3)), mask=np.ones(3, dtype=bool))
>>> nddsliced = ndd[1:3,1:3]
>>> nddsliced.mask
array([ True,  True]...)

注釈

The methods slicing the attributes are prefixed by a _slice_* where * can be mask, uncertainty, or wcs. So overriding them is the most convenient way to customize how the attributes are sliced.

注釈

もしスライスが影響すべきなら unit あるいは…。 meta 次の例を参照されたい。

他の属性を分割する

追加された属性に基づいて構築する flags 分割可能であることを願っています

>>> class NDDataWithFlags(NDDataRef):
...     def __init__(self, *args, **kwargs):
...         # Remove flags attribute if given and pass it to the setter.
...         self.flags = kwargs.pop('flags') if 'flags' in kwargs else None
...         super().__init__(*args, **kwargs)
...
...     @property
...     def flags(self):
...         return self._flags
...
...     @flags.setter
...     def flags(self, value):
...         self._flags = value
...
...     def _slice(self, item):
...         # slice all normal attributes
...         kwargs = super()._slice(item)
...         # The arguments for creating a new instance are saved in kwargs
...         # so we need to add another keyword "flags" and add the sliced flags
...         kwargs['flags'] = self.flags[item]
...         return kwargs # these must be returned
>>> ndd = NDDataWithFlags([1,2,3], flags=[0, 0.2, 0.3])
>>> ndd2 = ndd[1:3]
>>> ndd2.flags
[0.2, 0.3]

原本だけを保存したいなら flags スライスではありませんので、ご利用いただけます kwargs['flags'] = self.flags 省略しています [item] それがそうです。

NDDataBase

The class NDDataBase is a metaclass — when subclassing it, all properties of NDDataBase must be overridden in the subclass.

子類化自 NDDataBase データストレージおよび他の属性をどのように実装するかについて完全な柔軟性を持たせます。もしあなたのデータが numpy 配列(または行動は numpy 配列)、サブクラス化の方が便利かもしれません NDData ではなく NDDataBase それがそうです。

例を引く

読み出し専用コンテナを作成することでNDDataBaseインタフェースを実現するためには、以下の操作を実行してください。

>>> from astropy.nddata import NDDataBase

>>> class NDDataReadOnlyNoRestrictions(NDDataBase):
...     def __init__(self, data, unit, mask, uncertainty, meta, wcs):
...         self._data = data
...         self._unit = unit
...         self._mask = mask
...         self._uncertainty = uncertainty
...         self._meta = meta
...         self._wcs = wcs
...
...     @property
...     def data(self):
...         return self._data
...
...     @property
...     def unit(self):
...         return self._unit
...
...     @property
...     def mask(self):
...         return self._mask
...
...     @property
...     def uncertainty(self):
...         return self._uncertainty
...
...     @property
...     def meta(self):
...         return self._meta
...
...     @property
...     def wcs(self):
...         return self._wcs

>>> # A meaningless test to show that creating this class is possible:
>>> NDDataReadOnlyNoRestrictions(1,2,3,4,5,6) is not None
True

注釈

実際に定義されているのは __init__ 必要ではなく,属性は任意の値を返すことができるが,属性は must 定義されています

子類化 NDUncertainty

警告

NDUnsureとサブクラスの内部インタフェースは実験的であり,将来のバージョンで変更される可能性がある.

派生自. NDUncertainty 以下の動作を実行する必要がある.

  • 属性 uncertainty_type 不確実性を記述する文字列、例えば、 "ivar" 逆分散を表す.

  • 伝播方法: _propagate_* どこだ? * 汎用関数(Ufunc)の名前であり、この関数は NDData 親です。

伝播せずに不確実性を作る

UnknownUncertainty 最小の作業実現であり,誤り伝播はない.ストレージ·システムの不確実性によって不確実性を作成することができます

>>> from astropy.nddata import NDUncertainty

>>> class SystematicUncertainty(NDUncertainty):
...     @property
...     def uncertainty_type(self):
...         return 'systematic'
...
...     def _data_unit_to_uncertainty_unit(self, value):
...         return None
...
...     def _propagate_add(self, other_uncert, *args, **kwargs):
...         return None
...
...     def _propagate_subtract(self, other_uncert, *args, **kwargs):
...         return None
...
...     def _propagate_multiply(self, other_uncert, *args, **kwargs):
...         return None
...
...     def _propagate_divide(self, other_uncert, *args, **kwargs):
...         return None

>>> SystematicUncertainty([10])
SystematicUncertainty([10])