Skip to content

Add non-breaking spaces between units #11208

Closed

Description

@wmvanvliet

Proposed documentation enhancement

There should be a non-breaking space between the number and its unit. I don't know if this is supported here, I would use either   or   (preferably the latter). This should be consistent throughout our documents.

e.g. 250 ms

Activity

  1. self-assigned this
    on Sep 27, 2022
  2. sawradip commented on Feb 6, 2023

    @sawradip
    Contributor

    Is this issue still open? I would like to fix this if still open.

  3. wmvanvliet commented on Feb 7, 2023

    @wmvanvliet
    ContributorAuthor

    Yes, this is still open. Have fun with it! :)

  4. sawradip commented on Feb 7, 2023

    @sawradip
    Contributor

    Can you give me a little direction? (or some resources)

    • Should I change across all files? or specific type files? (python/html/rst)?
    • How do I check which space is used? (is there some tool or some way)

    I am actually new in this project, and a little uninformed about variation of spaces.

    Probably I am asking for very beginner stuff. But I an eager to contribute to this project.

  5. wmvanvliet commented on Feb 7, 2023

    @wmvanvliet
    ContributorAuthor

    Throughout our documentation, so that is the various .rst files in the doc/ folder and the RST markup code in the .py files in the examples and tutorials folders, we have text explaining things. This text occasionally contains numbers with a unit. For example 100 ms, or 23 µV. At the moment, there is usually a normal, breaking, space between the number and the unit. Sometimes this causes awkward linebreaks. It would be better if we were to use a non-breaking space between them.

    You can tell what type of space it is because anything other than a regular space probably needs to be written as a unicode directive in order for the documentation system to output a nonbreaking space. Question is how to exactly do this. This StackOverflow tread has some hints: https://stackoverflow.com/questions/11830242/how-can-i-make-a-non-breaking-space-in-restructuredtext

    If it is true that we need some sort of custom RST substitution command to generate nonbreaking spaces, we might want to make a sphinx extension that defines a custom command for "units", so we could do something like

    :unit:`ms`
    
  6. drammock commented on Feb 7, 2023

    @drammock
    Member

    FYI one way it's done (using html escape &nbsp) is seen in this tutorial:

    # they found that applying a 1 Hz high-pass decreased the probability of

    Other approach (using a \uXXXX style escape, in this case for optional hyphens) is seen here:

    mne-python/doc/conf.py

    Lines 880 to 884 in 11bc099

    # \u00AD is an optional hyphen (not rendered unless needed)
    # If these are changed, the Makefile should be updated, too
    'carousel': [
    dict(title='Source Estimation',
    text='Distributed, sparse, mixed-norm, beam\u00ADformers, dipole fitting, and more.', # noqa E501

    Yet another approach is the rST substitution syntax:

    .. |ensp| unicode:: U+2002 .. EN SPACE

    git grep "|ensp|" will show you that one in-use.

    All of those seem to me to make the rST source rather difficult to read. Making a custom rST interpreted text role (this is the :unit:`ms` style mentioned above) might be the nicest approach, especially if it were designed to take both the number and the unit, like this: :unit:`5 ms` and automatically replace the ordinary space with a non-breaking (possibly thin) space.

  7. wmvanvliet commented on Feb 7, 2023

    @wmvanvliet
    ContributorAuthor

    there's already some custom commands defined in doc/sphinxext you could use as example for how to create a new command.

  8. cbrnr commented on Feb 7, 2023

    @cbrnr
    Contributor

    👍 for thin space!

  9. sawradip commented on Feb 9, 2023

    @sawradip
    Contributor

    Thank you for these resources.

  10. sawradip commented on Feb 10, 2023

    @sawradip
    Contributor

    After taking some time for studying about rst and sphinx,I came up with this custom role.

    from docutils import nodes
    
    
    def unit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
        try:
            value = float(text.split(' ')[0])
            if len(text.split(' ')) != 2:
                raise ValueError
        except ValueError:
            msg = inliner.reporter.error(
                'The structure should be a value(int/float) and a unit(str) separated by a normal space.Ex:`5 ms`', line=lineno)
            prb = inliner.problematic(rawtext, rawtext, msg)
            return [prb], [msg]
        node = nodes.Text("\u202F".join(text.split(' ')))
        return [node], []
    
    
    def setup(app):
        app.add_role('unit', unit_role)
    

    This results in :unit:`5 ms`. Does this seem okay?

  11. drammock commented on Feb 10, 2023

    @drammock
    Member

    this is a great start! Here's a proposed cleanup:

    from docutils import nodes
    from mne.utils import _validate_type
    
    
    def unit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
        parts = text.split()
    
        def pass_error_to_sphinx(rawtext, text, lineno, inliner):
            msg = inliner.reporter.error(
                'The :unit: role requires a space-separated number and unit; '
                f'got {text}', line=lineno)
            prb = inliner.problematic(rawtext, rawtext, msg)
            return [prb], [msg]
    
        # ensure only two parts
        if len(parts) != 2:
            return pass_error_to_sphinx(rawtext, text, lineno, inliner)
        # ensure first part is a number
        try:
            _validate_type(parts[0], 'numeric', 'Numeric part of :unit: role')
        except TypeError:
            return pass_error_to_sphinx(rawtext, text, lineno, inliner)
        # input is well-formatted: proceed
        node = nodes.Text('\u202F'.join(parts))
        return [node], []
    
    
    def setup(app):
        app.add_role('unit', unit_role)

    Can you open a PR that adds this role, and uses it instead of the &nbsp here:

    # they found that applying a 1 Hz high-pass decreased the probability of

    I don't think we test any of our sphinx extensions, but it ought to be fairly easy to test this. @larsoner where would you suggest adding a test for our sphinx extensions?

  12. larsoner commented on Feb 11, 2023

    @larsoner
    Member

    @larsoner where would you suggest adding a test for our sphinx extensions?

    We don't currently test them. But we could add a mne/utils/_sphinxext.py and mne/utils/tests/test_sphinxext.py or so. I'm not sure how easy it will be to set up the infrastructure for it, the hoops we had to jump through in sphinx-gallery were not trivial. But we could figure it out

  13. sawradip commented on Feb 11, 2023

    @sawradip
    Contributor

    @drammock The cleanup has a little bug. When we split the text into parts = text.split(), parts[0] is also a string. Thus, whether it is 1 or one, it raises an error. I am not sure, if _validate_type has a correct form of application here.

    from docutils import nodes
    
    
    def unit_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
        parts = text.split()
    
        def pass_error_to_sphinx(rawtext, text, lineno, inliner):
            msg = inliner.reporter.error(
                'The :unit: role requires a space-separated number and unit; '
                f'got {text}', line=lineno)
            prb = inliner.problematic(rawtext, rawtext, msg)
            return [prb], [msg]
    
        # ensure only two parts
        if len(parts) != 2:
            return pass_error_to_sphinx(rawtext, text, lineno, inliner)
        # ensure first part is a number
        try:
              value = float(parts[0])
        except ValueError:
            return pass_error_to_sphinx(rawtext, text, lineno, inliner)
        # input is well-formatted: proceed
        node = nodes.Text('\u202F'.join(parts))
        return [node], []
    
    
    def setup(app):
        app.add_role('unit', unit_role)
    

    I am seeing one form of solution to be this, with ValueError. Any suggestions?

  14. drammock commented on Feb 11, 2023

    @drammock
    Member

    Ah good point. Let's forget about using validate_type then

  15. sawradip commented on Feb 11, 2023

    @sawradip
    Contributor

    I added a PR. If you could give me feedback.

  16. sawradip commented on Feb 16, 2023

    @sawradip
    Contributor

    Hello...everyone. As the non-breaking space role is added, Now I will like to go through the documentations (As I plan to do to strengthen my understanding of the project, and future effective contributions), and fix all the places, that should contain non-breaking space, but doesn't.
    I will probably list those somewhere(could be in this issue comment, as this is related to this topic, as well as you guys can check if all are appropriate) so that I can fix the all in one commit later.
    Will this be alright?

  17. sawradip commented on Feb 16, 2023

    @sawradip
    Contributor

    Preprocessing:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions