"""===========Basic Units==========="""import mathimport numpy as npimport matplotlib.units as unitsimport matplotlib.ticker as tickerclass ProxyDelegate:def __init__(self, fn_name, proxy_type):self.proxy_type = proxy_typeself.fn_name = fn_namedef __get__(self, obj, objtype=None):return self.proxy_type(self.fn_name, obj)class TaggedValueMeta(type):def __init__(self, name, bases, dict):for fn_name in self._proxies:if not hasattr(self, fn_name):setattr(self, fn_name,ProxyDelegate(fn_name, self._proxies[fn_name]))class PassThroughProxy:def __init__(self, fn_name, obj):self.fn_name = fn_nameself.target = obj.proxy_targetdef __call__(self, *args):fn = getattr(self.target, self.fn_name)ret = fn(*args)return retclass ConvertArgsProxy(PassThroughProxy):def __init__(self, fn_name, obj):PassThroughProxy.__init__(self, fn_name, obj)self.unit = obj.unitdef __call__(self, *args):converted_args = []for a in args:try:converted_args.append(a.convert_to(self.unit))except AttributeError:converted_args.append(TaggedValue(a, self.unit))converted_args = tuple([c.get_value() for c in converted_args])return PassThroughProxy.__call__(self, *converted_args)class ConvertReturnProxy(PassThroughProxy):def __init__(self, fn_name, obj):PassThroughProxy.__init__(self, fn_name, obj)self.unit = obj.unitdef __call__(self, *args):ret = PassThroughProxy.__call__(self, *args)return (NotImplemented if ret is NotImplementedelse TaggedValue(ret, self.unit))class ConvertAllProxy(PassThroughProxy):def __init__(self, fn_name, obj):PassThroughProxy.__init__(self, fn_name, obj)self.unit = obj.unitdef __call__(self, *args):converted_args = []arg_units = [self.unit]for a in args:if hasattr(a, 'get_unit') and not hasattr(a, 'convert_to'):# if this arg has a unit type but no conversion ability,# this operation is prohibitedreturn NotImplementedif hasattr(a, 'convert_to'):try:a = a.convert_to(self.unit)except Exception:passarg_units.append(a.get_unit())converted_args.append(a.get_value())else:converted_args.append(a)if hasattr(a, 'get_unit'):arg_units.append(a.get_unit())else:arg_units.append(None)converted_args = tuple(converted_args)ret = PassThroughProxy.__call__(self, *converted_args)if ret is NotImplemented:return NotImplementedret_unit = unit_resolver(self.fn_name, arg_units)if ret_unit is NotImplemented:return NotImplementedreturn TaggedValue(ret, ret_unit)class TaggedValue(metaclass=TaggedValueMeta):_proxies = {'__add__': ConvertAllProxy,'__sub__': ConvertAllProxy,'__mul__': ConvertAllProxy,'__rmul__': ConvertAllProxy,'__cmp__': ConvertAllProxy,'__lt__': ConvertAllProxy,'__gt__': ConvertAllProxy,'__len__': PassThroughProxy}def __new__(cls, value, unit):# generate a new subclass for valuevalue_class = type(value)try:subcls = type(f'TaggedValue_of_{value_class.__name__}',(cls, value_class), {})if subcls not in units.registry:units.registry[subcls] = basicConverterreturn object.__new__(subcls)except TypeError:if cls not in units.registry:units.registry[cls] = basicConverterreturn object.__new__(cls)def __init__(self, value, unit):self.value = valueself.unit = unitself.proxy_target = self.valuedef __getattribute__(self, name):if name.startswith('__'):return object.__getattribute__(self, name)variable = object.__getattribute__(self, 'value')if hasattr(variable, name) and name not in self.__class__.__dict__:return getattr(variable, name)return object.__getattribute__(self, name)def __array__(self, dtype=object):return np.asarray(self.value).astype(dtype)def __array_wrap__(self, array, context):return TaggedValue(array, self.unit)def __repr__(self):return 'TaggedValue({!r}, {!r})'.format(self.value, self.unit)def __str__(self):return str(self.value) + ' in ' + str(self.unit)def __len__(self):return len(self.value)def __iter__(self):# Return a generator expression rather than use `yield`, so that# TypeError is raised by iter(self) if appropriate when checking for# iterability.return (TaggedValue(inner, self.unit) for inner in self.value)def get_compressed_copy(self, mask):new_value = np.ma.masked_array(self.value, mask=mask).compressed()return TaggedValue(new_value, self.unit)def convert_to(self, unit):if unit == self.unit or not unit:return selftry:new_value = self.unit.convert_value_to(self.value, unit)except AttributeError:new_value = selfreturn TaggedValue(new_value, unit)def get_value(self):return self.valuedef get_unit(self):return self.unitclass BasicUnit:def __init__(self, name, fullname=None):self.name = nameif fullname is None:fullname = nameself.fullname = fullnameself.conversions = dict()def __repr__(self):return f'BasicUnit({self.name})'def __str__(self):return self.fullnamedef __call__(self, value):return TaggedValue(value, self)def __mul__(self, rhs):value = rhsunit = selfif hasattr(rhs, 'get_unit'):value = rhs.get_value()unit = rhs.get_unit()unit = unit_resolver('__mul__', (self, unit))if unit is NotImplemented:return NotImplementedreturn TaggedValue(value, unit)def __rmul__(self, lhs):return self*lhsdef __array_wrap__(self, array, context):return TaggedValue(array, self)def __array__(self, t=None, context=None):ret = np.array([1])if t is not None:return ret.astype(t)else:return retdef add_conversion_factor(self, unit, factor):def convert(x):return x*factorself.conversions[unit] = convertdef add_conversion_fn(self, unit, fn):self.conversions[unit] = fndef get_conversion_fn(self, unit):return self.conversions[unit]def convert_value_to(self, value, unit):conversion_fn = self.conversions[unit]ret = conversion_fn(value)return retdef get_unit(self):return selfclass UnitResolver:def addition_rule(self, units):for unit_1, unit_2 in zip(units[:-1], units[1:]):if unit_1 != unit_2:return NotImplementedreturn units[0]def multiplication_rule(self, units):non_null = [u for u in units if u]if len(non_null) > 1:return NotImplementedreturn non_null[0]op_dict = {'__mul__': multiplication_rule,'__rmul__': multiplication_rule,'__add__': addition_rule,'__radd__': addition_rule,'__sub__': addition_rule,'__rsub__': addition_rule}def __call__(self, operation, units):if operation not in self.op_dict:return NotImplementedreturn self.op_dict[operation](self, units)unit_resolver = UnitResolver()cm = BasicUnit('cm', 'centimeters')inch = BasicUnit('inch', 'inches')inch.add_conversion_factor(cm, 2.54)cm.add_conversion_factor(inch, 1/2.54)radians = BasicUnit('rad', 'radians')degrees = BasicUnit('deg', 'degrees')radians.add_conversion_factor(degrees, 180.0/np.pi)degrees.add_conversion_factor(radians, np.pi/180.0)secs = BasicUnit('s', 'seconds')hertz = BasicUnit('Hz', 'Hertz')minutes = BasicUnit('min', 'minutes')secs.add_conversion_fn(hertz, lambda x: 1./x)secs.add_conversion_factor(minutes, 1/60.0)# radians formattingdef rad_fn(x, pos=None):if x >= 0:n = int((x / np.pi) * 2.0 + 0.25)else:n = int((x / np.pi) * 2.0 - 0.25)if n == 0:return '0'elif n == 1:return r'$\pi/2$'elif n == 2:return r'$\pi$'elif n == -1:return r'$-\pi/2$'elif n == -2:return r'$-\pi$'elif n % 2 == 0:return fr'${n//2}\pi$'else:return fr'${n}\pi/2$'class BasicUnitConverter(units.ConversionInterface):@staticmethoddef axisinfo(unit, axis):"""Return AxisInfo instance for x and unit."""if unit == radians:return units.AxisInfo(majloc=ticker.MultipleLocator(base=np.pi/2),majfmt=ticker.FuncFormatter(rad_fn),label=unit.fullname,)elif unit == degrees:return units.AxisInfo(majloc=ticker.AutoLocator(),majfmt=ticker.FormatStrFormatter(r'$%i^\circ$'),label=unit.fullname,)elif unit is not None:if hasattr(unit, 'fullname'):return units.AxisInfo(label=unit.fullname)elif hasattr(unit, 'unit'):return units.AxisInfo(label=unit.unit.fullname)return None@staticmethoddef convert(val, unit, axis):if units.ConversionInterface.is_numlike(val):return valif np.iterable(val):if isinstance(val, np.ma.MaskedArray):val = val.astype(float).filled(np.nan)out = np.empty(len(val))for i, thisval in enumerate(val):if np.ma.is_masked(thisval):out[i] = np.nanelse:try:out[i] = thisval.convert_to(unit).get_value()except AttributeError:out[i] = thisvalreturn outif np.ma.is_masked(val):return np.nanelse:return val.convert_to(unit).get_value()@staticmethoddef default_units(x, axis):"""Return the default unit for x or None."""if np.iterable(x):for thisx in x:return thisx.unitreturn x.unitdef cos(x):if np.iterable(x):return [math.cos(val.convert_to(radians).get_value()) for val in x]else:return math.cos(x.convert_to(radians).get_value())basicConverter = BasicUnitConverter()units.registry[BasicUnit] = basicConverterunits.registry[TaggedValue] = basicConverter
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。