Title: [ENH]: Support for custom/special ticks without complex workarounds · Issue #22262 · matplotlib/matplotlib · GitHub
Open Graph Title: [ENH]: Support for custom/special ticks without complex workarounds · Issue #22262 · matplotlib/matplotlib
X Title: [ENH]: Support for custom/special ticks without complex workarounds · Issue #22262 · matplotlib/matplotlib
Description: Problem There is no direct, user-friendly method to add custom/special ticks. Existing methods can lead to surprising results and I have found little official guidance in the documentation that would account for this. From what I have se...
Open Graph Description: Problem There is no direct, user-friendly method to add custom/special ticks. Existing methods can lead to surprising results and I have found little official guidance in the documentation that wou...
X Description: Problem There is no direct, user-friendly method to add custom/special ticks. Existing methods can lead to surprising results and I have found little official guidance in the documentation that wou...
Opengraph URL: https://github.com/matplotlib/matplotlib/issues/22262
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[ENH]: Support for custom/special ticks without complex workarounds","articleBody":"### Problem\r\n\r\nThere is no direct, user-friendly method to add custom/special ticks. Existing methods can lead to surprising results and I have found little official guidance in the documentation that would account for this.\r\n\r\nFrom what I have seen in the examples gallery and on the Internet, most solutions rely on `Axes.set_xticks` or `Axes.set_yticks`. These methods can fail silently (and very frustratingly) when attempting to work with e.g. a semilog plot.\r\n\r\nExample of what would be expected behaviour with user set ticks (using ordinary `plot`):\r\n```python\r\nimport numpy as np\r\nimport matplotlib as mpl\r\nimport matplotlib.pyplot as plt\r\n\r\n\r\n# Constants\r\nL = 6\r\nD = 1\r\ngamma = 1\r\nm_0 = 1\r\nDelta_m = 0.05\r\nq = gamma / D\r\nr = np.sqrt(q)\r\nSamples = 601\r\n\r\n# Functions that should work with numbers and ndarrays just as well\r\ndef dervLin(xs):\r\n return xs * 0 -m_0 / L # Trick to make this ndarray-compatible (`xs * 0 +` forces array broadcasting, but doesn't change the value)\r\n\r\ndef dervExp(xs):\r\n return -m_0 * r * np.exp(-r * xs)\r\n\r\ndef dervPow(xs):\r\n return -12 * D / gamma / (xs + np.sqrt((6 * D / gamma) / m_0))**3\r\n\r\n\r\nxs = np.linspace(0, L, Samples)\r\nys1 = Delta_m / np.abs(dervLin(xs))\r\nys2 = Delta_m / np.abs(dervExp(xs))\r\nys3 = Delta_m / np.abs(dervPow(xs))\r\n\r\n\r\nfig, ax = plt.subplots(1, 1)\r\nax.set_xlim(0, L)\r\nax.plot(xs, ys1, xs, ys2, xs, ys3)\r\nax.hlines([ys1[-1], ys2[-1], ys3[-1]], 0, L, linewidth=0.5, linestyle=\"dashed\", color=\"grey\")\r\nax.set_yticks([ys1[-1], ys2[-1], ys3[-1]])\r\n```\r\n\r\noutputs\r\n\r\n\r\nNow, trying the same with `Axes.semilogy` instead of `Axes.plot`:\r\n```python\r\nimport numpy as np\r\nimport matplotlib as mpl\r\nimport matplotlib.pyplot as plt\r\n\r\n\r\n# Constants\r\nL = 6\r\nD = 1\r\ngamma = 1\r\nm_0 = 1\r\nDelta_m = 0.05\r\nq = gamma / D\r\nr = np.sqrt(q)\r\nSamples = 601\r\n\r\n# Functions that should work with numbers and ndarrays just as well\r\ndef dervLin(xs):\r\n return xs * 0 -m_0 / L # Trick to make this ndarray-compatible (`xs * 0 +` forces array broadcasting, but doesn't change the value)\r\n\r\ndef dervExp(xs):\r\n return -m_0 * r * np.exp(-r * xs)\r\n\r\ndef dervPow(xs):\r\n return -12 * D / gamma / (xs + np.sqrt((6 * D / gamma) / m_0))**3\r\n\r\n\r\nxs = np.linspace(0, L, Samples)\r\nys1 = Delta_m / np.abs(dervLin(xs))\r\nys2 = Delta_m / np.abs(dervExp(xs))\r\nys3 = Delta_m / np.abs(dervPow(xs))\r\n\r\n\r\nfig, ax = plt.subplots(1, 1)\r\nax.set_xlim(0, L)\r\nax.semilogy(xs, ys1, xs, ys2, xs, ys3)\r\nax.hlines([ys1[-1], ys2[-1], ys3[-1]], 0, L, linewidth=0.5, linestyle=\"dashed\", color=\"grey\")\r\nax.set_yticks([ys1[-1], ys2[-1], ys3[-1]])\r\n```\r\n\r\nsilently fails to produce labelled ticks:\r\n\r\n\r\nI have deduced that the problem lies with `LogFormatterSciNotation`, which doesn't produce a tick label when presented with user-provided values.\r\n```python\r\nfmt = ax.yaxis.get_major_formatter()\r\n\u003e\u003e\u003e fmt\r\n\u003cmatplotlib.ticker.LogFormatterSciNotation at 0x1d7a95a1940\u003e\r\n\u003e\u003e\u003e fmt(0.3)\r\n''\r\n\u003e\u003e\u003e fmt(10)\r\n'$\\\\mathdefault{10^{1}}$'\r\n```\r\n\r\nMy workaround includes subclassing and substituting the formatter:\r\n```python\r\nclass SpecialLogFmt(mpl.ticker.LogFormatterSciNotation):\r\n def __call__(self, x, pos):\r\n s = super().__call__(x, pos)\r\n \r\n if len(s) == 0:\r\n s = \"%.2f\" % x\r\n return s\r\n\r\nsfmt = SpecialLogFmt()\r\nax.yaxis.set_major_formatter(sfmt)\r\n```\r\n\r\nGiven these complications that necessitate a not completely trivial workaround, I believe it would be helpful to introduce explicit support for user-provided special ticks (in parallel to automatically-generated ticks). Other software e.g. OriginLab/OriginPro offers such a feature out of the box.\r\n\r\n### Proposed solution\r\n\r\nAt the very least, amend documentation of `Axes.set_xticks`/`Axes.set_yticks` to state that the results also depend on the `Formatter` of the axis, which may ignore the ticks which were added manually. [Current documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_yticks.html) claiming that `If not set, the labels show the data value.` is misleading when this isn't mentioned.\r\n\r\nAdd a gallery example that shows how to use special ticks, with more emphasis on such edge cases as can occur with e.g. log plots.\r\n\r\nIf possible, create new API methods that would explicitly support manually-added special ticks, so that the user does not have to worry about making the axis formatter work with the custom ticks. This API could be connected with the `hlines`/`vlines` method to give horizontal/vertical lines ending in a special tick, which may be very helpful in some contexts.","author":{"url":"https://github.com/yaaun","@type":"Person","name":"yaaun"},"datePublished":"2022-01-18T20:55:40.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":10},"url":"https://github.com/22262/matplotlib/issues/22262"}
| 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:413dc0e7-c3f6-485f-866a-98e995bc6b90 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 9BA6:1F8C21:A95089:E3E79C:6A52968E |
| html-safe-nonce | 934cd7e92934085832bf50b24e79722d396332cf39baa3ae9417c4ae873274f9 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5QkE2OjFGOEMyMTpBOTUwODk6RTNFNzlDOjZBNTI5NjhFIiwidmlzaXRvcl9pZCI6IjgzODQyMjMzNjQxNjA1OTE1MDIiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | a69b10766f695a7f87215c6692ca1b36bb1bc058af9812e44d6dc4368cb557b6 |
| hovercard-subject-tag | issue:1107353812 |
| 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/22262/issue_layout |
| twitter:image | https://opengraph.githubassets.com/bf3810a82cf9daad651cbf8d0513082608112ac62136c9ed4193437b2a0f622c/matplotlib/matplotlib/issues/22262 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/bf3810a82cf9daad651cbf8d0513082608112ac62136c9ed4193437b2a0f622c/matplotlib/matplotlib/issues/22262 |
| og:image:alt | Problem There is no direct, user-friendly method to add custom/special ticks. Existing methods can lead to surprising results and I have found little official guidance in the documentation that wou... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | yaaun |
| hostname | github.com |
| expected-hostname | github.com |
| None | b9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb |
| 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 | 07a982c1d40157c619b364352b704c3ce66bb332 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width