8000 Fixed the positioning of cursor in Textbox: no approximation by Tortar · Pull Request #24065 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content
Dismiss alert

Fixed the positioning of cursor in Textbox: no approximation #24065

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

Merged
merged 1 commit into from
Oct 20, 2022

Conversation

Tortar
Copy link
Contributor
@Tortar Tortar commented Oct 1, 2022

PR Summary

I updated the position_cursor function of Textbox so that it doesn't approximate the position of the cursor incorrectly anymore. Now, instead, to calculate the cursor's position, we accumulate the width of each character contained in the text and find the index where the distance between the click position and the accumulated sum is minimal.

I found that the approximation used in the position_cursor function before this PR was really buggy sometimes, running this code block and trying to set the cursor in different positions makes it apparent :

from matplotlib import pyplot as plt
from matplotlib.widgets import TextBox

fig = plt.figure(figsize=(4, 3))
        
box_input = fig.add_axes([0.1, 0.5, 0.8, 0.2])
        
text_box = TextBox(ax=box_input, initial=f'kkkkkk iiiii kkkkkk', label='')

fig.show()

For example, to put the cursor at the start of the second block of "k"s you needed to click one letter forward, while with the change it works as one would expect.

PR Checklist

Tests and Styling

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (install flake8-docstrings and run flake8 --docstring-convention=all).

Documentation

  • [N/A] New features are documented, with examples if plot related.
  • [N/A] New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • [N/A] API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).

@Tortar Tortar changed the title Updated the position_cursor function of Textbox Fixed the positioning of cursor in Textbox: no approximation Oct 1, 2022
Copy link
Member
@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the logic as well as caching should be done (lazily) in the Text object and provided via a function self.disp_text.char_index_at(x) or similar, where x is a relative coordinate inside the text bbox.

It's the responsibility of the text object to do this. Note that a user could do text_box.disp_text.set_fontsize(100), which needs to invalidate the char_size cache, but the text_box itself does not see when this gets called.

@Tortar Tortar requested a review from timhoffm October 2, 2022 21:31
@Tortar
Copy link
Contributor Author
Tortar commented Oct 2, 2022

Hi @timhoffm , I tried to follow your suggestions, let me know what you think about it!

edit: There are still problems when I change the fontsize after creation, trying to solve them

@Tortar
Copy link
Contributor Author
Tortar commented Oct 3, 2022

Now it works in cases like this one:

from matplotlib import pyplot as plt
from matplotlib.widgets import TextBox

fig = plt.figure(figsize=(4, 3))
        
box_input = fig.add_axes([0.1, 0.5, 0.8, 0.2])
        
text_box = TextBox(ax=box_input, initial=f'kkkkkk iiiii kkkkkk', label='',
                   textalignment="center")

text_box.text_disp.char_index_at(200)
text_box.text_disp.set_fontsize(20)

fig.show()

but there is still a problem related to .get_window_extent() I don't know how to solve. When the boundingboxes are calculated it gets wrong sizes before actually showing the figure; if you try to delete from the code block above the line with text_box.text_disp.set_fontsize(20), you'll see that the cursor doesn't work anymore, the problem is that the boundingboxes of the letter and of the entire text are incorrectly calculated before showing the figure and those are cached so that it doesn't update with the correct values when you set the cursor on the actual textbox.

How can the correct sizes of the boundingboxes be found?

edit:

I notice that the renderer changes throughout the execution with print(self.figure._get_renderer()) inside the Text.char_index_at(x) method.

The solutions I see right now it's dropping the caching, but this still doesn't change the fact that the coordinates are incorrectly calculated before showing the figure or It would be even good in my opinion rolling back to the first change so that the method would belong just to the Textbox object so that no problem of this sort would appear

@Tortar Tortar marked this pull request as draft October 4, 2022 13:48
@Tortar Tortar marked this pull request as ready for review October 6, 2022 18:40
Copy link
Member
@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There can still be some edge cases like ligatures or letter spacing, where the position is not just the sum of character widths. However, I believe they are negligible in practical use cases. This approach is better than the previous guessing, and I think good enough for the use case.

@Tortar
Copy link
Contributor Author
Tortar commented Oct 7, 2022

Thanks @timhoffm for the review, I applied your suggested changes, everything should be good to go!

@Tortar Tortar force-pushed the patch-2 branch 2 times, most recently from 65a9a9b to 971d59e Compare October 8, 2022 18:39
@Tortar Tortar requested a review from timhoffm October 8, 2022 18:39
Copy link
Member
@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Can you think of a test?

Maybe:

  • set a text "i" and measure its size
  • set a text "m" and measure its size
  • set a text "iiiimmmm" and test the char indices at some positions

@Tortar Tortar requested a review from timhoffm October 11, 2022 08:41
Copy link
Member
@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

Copy link
Member
@timhoffm timhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, only docstring wording and some additional test cases to do.

In the process a new function for the Text
object called _char_index_at has been created

Co-authored-by: Tortar <68152031+Tortar@users.noreply.github.com>
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
@tacaswell tacaswell added this to the v3.7.0 milestone Oct 20, 2022
@tacaswell
Copy link
Member

I see some edge cases (a Ctrl-c at the wrong time won't reset the text) and an un-bounded cache, but I think that both of those are low enough risk to merge this as-is and address if they actually are a problem.

@tacaswell tacaswell merged commit e7f52ea into matplotlib:main Oct 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0