-
Notifications
You must be signed in to change notification settings - Fork 218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support non-ASCII characters in PyGMT arguments and text in Figure.text #2204
Comments
TODO list after PR #2584:
|
Was trying to get the character ā (Latin small letter a with macron) to plot using either ISO-8859-4/ISO-8859-10/ISO-8859-13 in #2641 (comment), but doesn't work when setting
Workaround was to use the composite character |
After PRs #2584, #2638, #3192, and #3199, PyGMT already provides basic support for non-ASCII characters. In short, we're maintaining a big dictionary mapping non-ASCII characters to their octal codes. So users can pass a character like
Since these characters are so similar, users may use the "incorrect" one and then get surprising results. Actually, we're using some incorrect characters in our mapping dictionary. To solve the problem, we need character tables that users can copy. The official GMT documentation provides the tables (https://docs.generic-mapping-tools.org/dev/reference/octal-codes.html) in PNG/PDF format but they're not easy to copy. Better tables are available at
However, these tables are "incomplete" (some characters are missing) compared to the GMT ones. For example, in the Symbol table, This repository https://github.com/seisman/GMT-octal-codes maintains the mapping files that can map Unicode characters to GMT octal codes. Check the README files in that repository for how the mapping files are created. With the well-maintained mapping files, we can refactor the mapping dictionary in the PyGMT project and add character tables for the supported encodings, as done in #3206. |
@GenericMappingTools/pygmt-maintainers After a series of PRs, I think we already provide good support for non-ASCII characters. Things to note are:
Supporting "Standard"/"Standard+" or allowing any default encoding can be tricky because we need to inquire about the current character encoding using We have some options:
I prefer option 2 and will work on it if there are no objections or comments in one week. |
Acutally, there is option 4, i.e., adding |
Problems
Due to the limitation of the PostScript language, GMT can only work with ASCII characters and a small set of non-ASCII characters. See https://docs.generic-mapping-tools.org/latest/cookbook/octal-codes.html for the full list of characters that PostScript/GMT/PyGMT can accept.
These non-ASCII characters must be specified using their octal codes or character escape sequence. A few non-ASCII characters (e.g., ü, Î) are allowed and GMT can substitute these non-ASCII characters with the correct PostScript octal codes.
Users who don't know the limitations may pass non-ASCII characters directly in the arguments. For example:
The above script produces this "surprising" figure:
So, if users want to add a non-ASCII character to a plot, they must know the limitations and have to go to this page https://docs.generic-mapping-tools.org/latest/cookbook/octal-codes.html, look for the character in the four tables, and figure out the corresponding octal code (
\260
for the symbol°
), which is tedious and not easy.After finding the octal code, users may think changing
°
to\260
should work:but it still produces the same "surprising" figure, because the Python interpreter recognizes
\260
first, and converts it to°
before passing it to the GMT API. So, users have to use double backslashes or raw strings:or
Solutions
Since Python works well with non-ASCII characters (acutally it works with any unicode characters), it's possible to pass
°
in Python, and PyGMT should substitute the non-ASCII characters with the corresponding octal codes.Here are some tests in Python:
So, if we can do the substitutions/conversions internally, we can support non-ASCII characters better. The simplest solution is to define a big dictionary that maps non-ASCII characters (e.g.,
°
) to octal codes (e.g.,\260
). Better and more clever solutions are also possible.Notes about the possible limitations of the solutions
Non-ASCII characters can be used in many cases:
frame="WSen+tTime (s) vs Distance (°)"
fig.text(x=0, y=0, text="Distance (°)")
0 0 Distance (°)
The above solution should work well for case 1, may work or not work (depending on the implentation)
for case 2, and likely don't work for case 3.
Are you willing to help implement and maintain this feature?
Yes, but more discussions are needed.
The text was updated successfully, but these errors were encountered: