Title: [ENH?] EngFormatter: add the possibility to remove the space before the SI prefix · Issue #6533 · matplotlib/matplotlib · GitHub
Open Graph Title: [ENH?] EngFormatter: add the possibility to remove the space before the SI prefix · Issue #6533 · matplotlib/matplotlib
X Title: [ENH?] EngFormatter: add the possibility to remove the space before the SI prefix · Issue #6533 · matplotlib/matplotlib
Description: Discussing with some of my colleagues who are using other plotting softwares than Matplotlib, I noticed that their formatting of the engineering notation is a bit different from the one implemented in ticker.EngFormatter. Some softwares ...
Open Graph Description: Discussing with some of my colleagues who are using other plotting softwares than Matplotlib, I noticed that their formatting of the engineering notation is a bit different from the one implemented...
X Description: Discussing with some of my colleagues who are using other plotting softwares than Matplotlib, I noticed that their formatting of the engineering notation is a bit different from the one implemented...
Opengraph URL: https://github.com/matplotlib/matplotlib/issues/6533
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[ENH?] EngFormatter: add the possibility to remove the space before the SI prefix ","articleBody":"Discussing with some of my colleagues who are using other plotting softwares than Matplotlib, I noticed that their formatting of the engineering notation is a bit different from the one implemented in `ticker.EngFormatter`. Some softwares append directly the prefix/unit to the tick value (e.g. \"1.23µs\", vs \"1.23 µs\" with Matplotlib). I am not sure it is really OK from the (English) typography point of view but I guess they are doing this due to the rather limited ticklablel space. \n\nI wonder how interesting it may be to add such a possibility to the `EngFormatter` in Matplotlib. As some users may prefer \"1.23µs\" over \"1.23 µs\", I would say it's worth adding it to `EngFormatter`. \n\nIf it is added to `EngFormatter`, I guess the major pitfall would be the default values… IMO, the current behavior of Matplotlib is the best one when `EngFormatter` is instantiated with a unit. However, when it is instantatied without unit (`unit=\"\"`), I wouldn't be categorical about the fact that \"1.23 µ\" is better than \"1.23µ\". So I don't really know if one should use by default a space separator between the value and the prefix/unit, or not…\n\nI wrote a small demonstration of what could be easily done with the `EngFormatter`class (keeping the current Matplotlib behavior as the default one). It is \u003e 100 lines because I directly copy-pasted the source code of `ticker.EngFormatter`. I've put the changes between `\u003cENH\u003e` and `\u003c\\ENH\u003e` tags. NB: the code includes a bug fix similar to PR #6014 . \n\n``` python\nfrom __future__ import division, print_function, unicode_literals\nimport decimal\nimport math\nimport numpy as np\nfrom matplotlib.ticker import Formatter\n\n\n# Proposed \"enhancement\" of the EngFormatter\nclass EnhancedEngFormatter(Formatter):\n \"\"\"\n Formats axis values using engineering prefixes to represent powers of 1000,\n plus a specified unit, e.g., 10 MHz instead of 1e7.\n \"\"\"\n\n # the unicode for -6 is the greek letter mu\n # commeted here due to bug in pep8\n # (https://github.com/jcrocholl/pep8/issues/271)\n\n # The SI engineering prefixes\n ENG_PREFIXES = {\n -24: \"y\",\n -21: \"z\",\n -18: \"a\",\n -15: \"f\",\n -12: \"p\",\n -9: \"n\",\n -6: \"\\u03bc\",\n -3: \"m\",\n 0: \"\",\n 3: \"k\",\n 6: \"M\",\n 9: \"G\",\n 12: \"T\",\n 15: \"P\",\n 18: \"E\",\n 21: \"Z\",\n 24: \"Y\"\n }\n\n def __init__(self, unit=\"\", places=None, space_sep=True):\n \"\"\" Parameters\n ----------\n unit: str (default: \"\")\n Unit symbol to use.\n\n places: int (default: None)\n Number of digits after the decimal point.\n If it is None, falls back to the floating point format '%g'.\n\n space_sep: boolean (default: True)\n If True, a (single) space is used between the value and the\n prefix/unit, else the prefix/unit is directly appended to the\n value.\n \"\"\"\n self.unit = unit\n self.places = places\n # \u003cENH\u003e\n if space_sep is True:\n self.sep = \" \" # 1 space\n else:\n self.sep = \"\" # no space\n # \u003c\\ENH\u003e\n\n def __call__(self, x, pos=None):\n s = \"%s%s\" % (self.format_eng(x), self.unit)\n return self.fix_minus(s)\n\n def format_eng(self, num):\n \"\"\" Formats a number in engineering notation, appending a letter\n representing the power of 1000 of the original number. Some examples:\n\n \u003e\u003e\u003e format_eng(0) # for self.places = 0\n '0'\n\n \u003e\u003e\u003e format_eng(1000000) # for self.places = 1\n '1.0 M'\n\n \u003e\u003e\u003e format_eng(\"-1e-6\") # for self.places = 2\n u'-1.00 \\u03bc'\n\n @param num: the value to represent\n @type num: either a numeric value or a string that can be converted to\n a numeric value (as per decimal.Decimal constructor)\n\n @return: engineering formatted string\n \"\"\"\n\n dnum = decimal.Decimal(str(num))\n\n sign = 1\n\n if dnum \u003c 0:\n sign = -1\n dnum = -dnum\n\n if dnum != 0:\n pow10 = decimal.Decimal(int(math.floor(dnum.log10() / 3) * 3))\n else:\n pow10 = decimal.Decimal(0)\n\n pow10 = pow10.min(max(self.ENG_PREFIXES.keys()))\n pow10 = pow10.max(min(self.ENG_PREFIXES.keys()))\n\n prefix = self.ENG_PREFIXES[int(pow10)]\n\n mant = sign * dnum / (10 ** pow10)\n\n # \u003cENH\u003e\n if self.places is None:\n format_str = \"%g{sep:s}%s\".format(sep=self.sep)\n elif self.places == 0:\n format_str = \"%i{sep:s}%s\".format(sep=self.sep)\n elif self.places \u003e 0:\n format_str = \"%.{p:i}f{sep:s}%s\".format(p=self.places,\n sep=self.sep)\n # \u003c\\ENH\u003e\n\n formatted = format_str % (mant, prefix)\n\n formatted = formatted.strip()\n if (self.unit != \"\") and (prefix == self.ENG_PREFIXES[0]):\n # \u003cENH\u003e\n formatted = formatted + self.sep\n # \u003c\\ENH\u003e\n\n return formatted\n\n\n# DEMO\ndef demo_formatter(**kwargs):\n \"\"\" Print the strings produced by the EnhancedEngFormatter for a list of\n arbitrary test values.\n \"\"\"\n TEST_VALUES = [1.23456789e-6, 0.1, 1, 999.9, 1001]\n unit = kwargs.get('unit', \"\")\n space_sep = kwargs.get('space_sep', True)\n formatter = EnhancedEngFormatter(**kwargs)\n\n print(\"\\n[Case: unit='{u:s}' \u0026 space_sep={s}]\".format(u=unit, s=space_sep))\n print(*[\"{tst};\".format(tst=formatter(value)) for value in TEST_VALUES])\n\nif __name__ == '__main__':\n \"\"\" Matplotlib current behavior (w/ space separator) \"\"\"\n demo_formatter(unit=\"s\", space_sep=True)\n # \u003e\u003e 1.23457 μs; 100 ms; 1 s; 999.9 s; 1.001 ks;\n demo_formatter(unit=\"\", space_sep=True)\n # \u003e\u003e 1.23457 μ; 100 m; 1; 999.9; 1.001 k;\n\n \"\"\" New possibility (w/o space separator) \"\"\"\n demo_formatter(unit=\"s\", space_sep=False)\n # \u003e\u003e 1.23457μs; 100ms; 1s; 999.9s; 1.001ks;\n demo_formatter(unit=\"\", space_sep=False)\n # \u003e\u003e 1.23457μ; 100m; 1; 999.9; 1.001k;\n```\n","author":{"url":"https://github.com/afvincent","@type":"Person","name":"afvincent"},"datePublished":"2016-06-04T22:27:19.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":10},"url":"https://github.com/6533/matplotlib/issues/6533"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:b03b034c-7f5e-e1bc-0abb-eaf3df814d35 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | DAFE:2CEF6D:F41033:163EE23:6A560A39 |
| html-safe-nonce | b9b26d4560be8b734bc3af1adaabbecd4e294a8d858cf9ce1732ad26c83ee643 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJEQUZFOjJDRUY2RDpGNDEwMzM6MTYzRUUyMzo2QTU2MEEzOSIsInZpc2l0b3JfaWQiOiIzNzMwMzM2MjI5NzM4NTQ3NzY5IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | b87cb3f8c267bdac147a04c1c223e97f618cb363eb8c96cecdaf45aecd42eb48 |
| hovercard-subject-tag | issue:158527140 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/matplotlib/matplotlib/6533/issue_layout |
| twitter:image | https://opengraph.githubassets.com/99523311652a7c6ca393dacdea7ddaf478cba79dedd1451269f7ffb88f930c26/matplotlib/matplotlib/issues/6533 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/99523311652a7c6ca393dacdea7ddaf478cba79dedd1451269f7ffb88f930c26/matplotlib/matplotlib/issues/6533 |
| og:image:alt | Discussing with some of my colleagues who are using other plotting softwares than Matplotlib, I noticed that their formatting of the engineering notation is a bit different from the one implemented... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | afvincent |
| hostname | github.com |
| expected-hostname | github.com |
| None | f4368738fc918fecd9b3958f6b49218bbe60d4185f38e72e3954e11f1ad0213a |
| turbo-cache-control | no-preview |
| go-import | github.com/matplotlib/matplotlib git https://github.com/matplotlib/matplotlib.git |
| octolytics-dimension-user_id | 215947 |
| octolytics-dimension-user_login | matplotlib |
| octolytics-dimension-repository_id | 1385122 |
| octolytics-dimension-repository_nwo | matplotlib/matplotlib |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1385122 |
| octolytics-dimension-repository_network_root_nwo | matplotlib/matplotlib |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 85a7179838b41e8b23f939d3b67b53f752ecfc54 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width