| commit | author | age | ||
| 91fb15 | 1 | from . import Exceptions |
| 5288d6 | 2 | from math import floor, log10 |
| d89217 | 3 | |
| 7b5760 | 4 | STRING = 1 |
| SP | 5 | FLOAT = 2 |
| 6 | ||
| 7 | ||
| 8 | class Variable: | |
| 7e7033 | 9 | def __init__(self, value=None, formatting=None): |
| 993a25 | 10 | self.formatted_value = None |
| 7b5760 | 11 | try: |
| SP | 12 | self.value = float(value) |
| 7e7033 | 13 | self.type = FLOAT |
| 7b5760 | 14 | except (ValueError, TypeError): |
| SP | 15 | self.type = STRING |
| 08b2a2 | 16 | self.value = value |
| SP | 17 | self.formatted_value = value |
| 7b5760 | 18 | if formatting is not None: |
| 33c054 | 19 | self.format_float(formatting) |
| 7b5760 | 20 | self.formatting = formatting |
| 08b2a2 | 21 | |
| SP | 22 | def is_float(self): |
| ce4fc9 | 23 | if self.type == FLOAT: |
| 08b2a2 | 24 | return True |
| SP | 25 | else: |
| 26 | return False | |
| 7b5760 | 27 | |
| 33c054 | 28 | def format_float(self, formatting=None): |
| 993a25 | 29 | if formatting is None: |
| SP | 30 | formatting = self.formatting |
| 31 | formatter = FormatterFactory.get_formatter(formatting) | |
| 32 | self.formatted_value = formatter.getValue(self.value) | |
| 7b5760 | 33 | |
| da1010 | 34 | def format_as_tex(self, formatting=None, glyph=None, unit=None, dollar="$"): |
| 993a25 | 35 | if formatting is None: |
| SP | 36 | formatting = self.formatting |
| 04ee9d | 37 | formatter = FormatterFactory.get_formatter(formatting) |
| da1010 | 38 | if formatting.split()[0] == "prefix": |
| SP | 39 | leading_space = "" |
| 40 | else: | |
| 39922f | 41 | leading_space = "\," |
| 5bc997 | 42 | if formatting == "str" or formatting == "string": |
| 04ee9d | 43 | return formatter.toFormat(self.value) |
| 08b2a2 | 44 | elif glyph is None and unit is None: |
| da1010 | 45 | return ("{}{}{}{}").format( |
| SP | 46 | dollar, formatter.toFormat(self.value), leading_space, dollar |
| 08b2a2 | 47 | ) |
| da1010 | 48 | elif glyph is None and unit is not None: |
| SP | 49 | return ("{}{}{}\mathrm{{{}}}{}{}").format( |
| 50 | dollar, formatter.toFormat(self.value), leading_space, unit, dollar | |
| 51 | ) | |
| 52 | elif glyph is not None and unit is None: | |
| 53 | return ("{}{}={}{}{}").format( | |
| 54 | dollar, glyph, formatter.toFormat(self.value), leading_space, dollar | |
| 55 | ) | |
| 56 | else: | |
| 57 | return ("{}{}={}{}\mathrm{{{}}}{}").format( | |
| 58 | dollar, | |
| 59 | glyph, | |
| 60 | formatter.toFormat(self.value), | |
| 61 | leading_space, | |
| 62 | unit, | |
| 63 | dollar, | |
| 64 | ) | |
| 7b5760 | 65 | |
| SP | 66 | def get_formatted_value(self): |
| 993a25 | 67 | return self.formatted_value |
| 08b2a2 | 68 | # if self.type != STRING else self.value |
| 7b5760 | 69 | |
| ef19a9 | 70 | def __str__(self): |
| SP | 71 | return str(self.format_as_tex()) |
| 72 | ||
| 78d798 | 73 | def __repr__(self): |
| SP | 74 | return self.__str__() |
| 75 | ||
| 7b5760 | 76 | |
| d89217 | 77 | class FormatterFactory: |
| 404823 | 78 | @staticmethod |
| SP | 79 | def get_formatter(formatstring): |
| 80 | spl = formatstring.split() | |
| 81 | type = spl[0] | |
| 82 | arglist = spl[1:] | |
| 83 | ||
| 5bc997 | 84 | if type == "sci" or type == "scientific": |
| d89217 | 85 | return SciFloatFormatter(arglist) |
| 5bc997 | 86 | elif type == "str" or type == "string": |
| 993a25 | 87 | return StringFormatter() |
| 5bc997 | 88 | elif type == "eng" or type == "engineering": |
| 993a25 | 89 | return EngFloatFormatter(arglist) |
| 5bc997 | 90 | elif type == "prefix": |
| SP | 91 | return PrefixFloatFormatter(arglist) |
| 92 | elif type == "dec" or type == "decimal": | |
| 839d16 | 93 | return DecFloatFormatter(arglist) |
| 404823 | 94 | else: |
| SP | 95 | return None |
| 5288d6 | 96 | |
| SP | 97 | @staticmethod |
| 98 | def fexp(f): | |
| 99 | return int(floor(log10(abs(f)))) if f != 0 else 0 | |
| 100 | ||
| 101 | @staticmethod | |
| 102 | def fman(f): | |
| 7b5760 | 103 | return f / 10 ** FormatterFactory.fexp(f) |
| 993a25 | 104 | |
| SP | 105 | |
| 106 | class StringFormatter(FormatterFactory): | |
| 107 | def __init__(self): | |
| 108 | pass | |
| 109 | ||
| 110 | def toFormat(self, string): | |
| 32d3f2 | 111 | return string.replace('"', "") |
| 993a25 | 112 | |
| SP | 113 | def getValue(self, string): |
| 32d3f2 | 114 | return '"{}"'.format(str(string.replace('"', ""))) |
| SP | 115 | |
| 404823 | 116 | |
| 839d16 | 117 | class DecFloatFormatter(FormatterFactory): |
| SP | 118 | def __init__(self, formatparameters): |
| 119 | if len(formatparameters) != 1: | |
| 120 | raise Exceptions.WrongParameters("Dec format accept only one argument") | |
| 121 | self.precision = int(formatparameters[0]) | |
| 122 | ||
| 123 | def toFormat(self, num): | |
| 124 | try: | |
| 125 | num = float(num) | |
| 126 | except ValueError: | |
| 127 | raise ValueError | |
| 128 | except TypeError: | |
| 129 | raise ValueError | |
| 130 | ||
| 32d3f2 | 131 | num = float(("{:." + str(self.precision - 1) + "e}").format(num)) |
| SP | 132 | places = self.fexp(num) |
| 34c8f6 | 133 | |
| 32d3f2 | 134 | decimal_places = self.precision - places - 1 |
| SP | 135 | if decimal_places < 0: |
| 136 | decimal_places = 0 | |
| 137 | format_str = "{:" + str(places) + "." + str(decimal_places) + "f}" | |
| 839d16 | 138 | |
| 8fe4d9 | 139 | return format_str.format(num).replace(".", ",\!") |
| 34c8f6 | 140 | |
| 839d16 | 141 | def getValue(self, num): |
| 34c8f6 | 142 | |
| 32d3f2 | 143 | num = float(("{:." + str(self.precision - 1) + "e}").format(num)) |
| SP | 144 | places = self.fexp(num) |
| 34c8f6 | 145 | |
| 32d3f2 | 146 | decimal_places = self.precision - places - 1 |
| SP | 147 | if decimal_places < 0: |
| 148 | decimal_places = 0 | |
| 149 | format_str = "{:" + str(places) + "." + str(decimal_places) + "f}" | |
| 150 | val = format_str.format(num) | |
| 839d16 | 151 | return float(val) |
| SP | 152 | |
| 404823 | 153 | |
| d89217 | 154 | class SciFloatFormatter(FormatterFactory): |
| SP | 155 | def __init__(self, formatparameters): |
| 404823 | 156 | if len(formatparameters) != 1: |
| 91fb15 | 157 | raise Exceptions.WrongParameters("Sci format accept only one argument") |
| 404823 | 158 | self.precision = int(formatparameters[0]) |
| SP | 159 | |
| 160 | def toFormat(self, num): | |
| 161 | try: | |
| 162 | num = float(num) | |
| 163 | except ValueError: | |
| 164 | raise ValueError | |
| 165 | except TypeError: | |
| 166 | raise ValueError | |
| 167 | ||
| 7b5760 | 168 | exp = self.fexp(num) |
| SP | 169 | man = self.fman(num) |
| 78d798 | 170 | if exp == 0: |
| 08b2a2 | 171 | return ( |
| SP | 172 | ("{:." + str(self.precision - 1) + "f}").format(man).replace(".", ",\!") |
| 173 | ) | |
| 78d798 | 174 | else: |
| 08b2a2 | 175 | return ( |
| SP | 176 | ("{:." + str(self.precision - 1) + "f} \cdot 10^{{{}}}") |
| 177 | .format(man, int(exp)) | |
| 178 | .replace(".", ",\!") | |
| 78d798 | 179 | ) |
| d89217 | 180 | |
| 33c054 | 181 | def getValue(self, num): |
| SP | 182 | exp = self.fexp(num) |
| 183 | man = self.fman(num) | |
| 78d798 | 184 | man = ("{:." + str(self.precision - 1) + "f}e{}").format(man, int(exp)) |
| 33c054 | 185 | return float(man) |
| d89217 | 186 | |
| 78d798 | 187 | |
| ce4fc9 | 188 | class EngFloatFormatter(FormatterFactory): |
| d89217 | 189 | def __init__(self, formatparameters): |
| SP | 190 | if len(formatparameters) != 1: |
| 191 | raise Exceptions.WrongParameters("Eng format accept only one argument") | |
| 192 | self.precision = int(formatparameters[0]) | |
| 193 | ||
| ce4fc9 | 194 | def realign3(self, exp, man): |
| SP | 195 | mul = exp % 3 |
| 196 | man = man * 10 ** mul | |
| 197 | exp = exp - mul | |
| 198 | return (exp, man) | |
| 199 | ||
| d89217 | 200 | def toFormat(self, num): |
| SP | 201 | try: |
| 202 | num = float(num) | |
| ce4fc9 | 203 | except ValueError: |
| d89217 | 204 | raise ValueError |
| ce4fc9 | 205 | except TypeError: |
| SP | 206 | raise ValueError |
| 32d3f2 | 207 | # Clip precision firstly |
| SP | 208 | num = float(("{:." + str(self.precision - 1) + "e}").format(num)) |
| ce4fc9 | 209 | exp = self.fexp(num) |
| SP | 210 | man = self.fman(num) |
| 211 | (exp, man) = self.realign3(exp, man) | |
| 32d3f2 | 212 | decimal_places = self.precision - self.fexp(man) - 1 |
| SP | 213 | if decimal_places < 0: |
| 214 | decimal_places = 0 | |
| ce4fc9 | 215 | if exp == 0: |
| 32d3f2 | 216 | return ("{:." + str(decimal_places) + "f}").format(man).replace(".", ",\!") |
| ce4fc9 | 217 | else: |
| SP | 218 | return ( |
| 32d3f2 | 219 | ("{:." + str(decimal_places) + "f} \cdot 10^{{{}}}") |
| ce4fc9 | 220 | .format(man, int(exp)) |
| SP | 221 | .replace(".", ",\!") |
| 222 | ) | |
| 223 | ||
| 224 | def getValue(self, num): | |
| 225 | exp = self.fexp(num) | |
| 226 | man = self.fman(num) | |
| 227 | man = ("{:." + str(self.precision - 1) + "f}e{}").format(man, int(exp)) | |
| 228 | return float(man) | |
| 229 | ||
| 230 | ||
| 5bc997 | 231 | class PrefixFloatFormatter(EngFloatFormatter): |
| ce4fc9 | 232 | def __init__(self, formatparameters): |
| SP | 233 | if len(formatparameters) != 1: |
| 234 | raise Exceptions.WrongParameters("Dec format accept only one argument") | |
| 235 | self.precision = int(formatparameters[0]) | |
| 236 | ||
| 237 | def exp2prefix(self, exp): | |
| 238 | prefixes = { | |
| 239 | "24": "Y", | |
| 240 | "21": "Z", | |
| 241 | "18": "E", | |
| 242 | "15": "P", | |
| 243 | "12": "T", | |
| 244 | "9": "G", | |
| 245 | "6": "M", | |
| 246 | "3": "k", | |
| 247 | "-3": "m", | |
| da1010 | 248 | "-6": "\\upmu", |
| SP | 249 | "-9": "n", |
| 250 | "-12": "p", | |
| 251 | "-15": "f", | |
| 252 | "-18": "a", | |
| 253 | "-21": "z", | |
| 254 | "-24": "y", | |
| ce4fc9 | 255 | } |
| SP | 256 | try: |
| 257 | prefix = prefixes[str(exp)] | |
| 258 | except KeyError: | |
| da1010 | 259 | raise Exceptions.PrefixError( |
| SP | 260 | "Could not change exponent " + str(exp) + " into prefix form!" |
| 261 | ) | |
| ce4fc9 | 262 | return prefix |
| SP | 263 | |
| 264 | def toFormat(self, num): | |
| 265 | try: | |
| 266 | num = float(num) | |
| 267 | except ValueError: | |
| 268 | raise ValueError | |
| 269 | except TypeError: | |
| 270 | raise ValueError | |
| 32d3f2 | 271 | # Clip precision firstly |
| SP | 272 | num = float(("{:." + str(self.precision - 1) + "e}").format(num)) |
| ce4fc9 | 273 | exp = self.fexp(num) |
| SP | 274 | man = self.fman(num) |
| 275 | (exp, man) = self.realign3(exp, man) | |
| 32d3f2 | 276 | decimal_places = self.precision - self.fexp(man) - 1 |
| SP | 277 | if decimal_places < 0: |
| 278 | decimal_places = 0 | |
| ce4fc9 | 279 | if exp == 0: |
| SP | 280 | return ( |
| 32d3f2 | 281 | ("{:." + str(decimal_places) + "f}\,").format(man).replace(".", ",\!") |
| ce4fc9 | 282 | ) |
| SP | 283 | else: |
| 284 | prefix = self.exp2prefix(exp) | |
| 285 | return ( | |
| 32d3f2 | 286 | ("{:." + str(decimal_places) + "f}\,\mathrm{{{}}}") |
| ce4fc9 | 287 | .format(man, prefix) |
| SP | 288 | .replace(".", ",\!") |
| 289 | ) | |