Skip to content
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

scale figsize in plot_events depending on n unique events #12844

Merged
merged 7 commits into from
Sep 20, 2024

Conversation

sappelhoff
Copy link
Member

@larsoner what do you think of this "low hanging fruit" improvement?

Using this MWE (if you checkout and install my branch here), this scales well to a number of 40 unique events. It looks a bit small in this PR preview, but on my screen it looks fine. Beyond scaling factor 2, it all gets wonky.

# %%
import numpy as np
import mne

events = np.arange(300).reshape(-1, 3)

if 1:
    for i in range(10, 100, 10):
        fig = mne.viz.plot_events(events[:i, :], show=True)
        figsize = fig.get_size_inches()
        print(f"previous was: n events: {i}, Figure size: {figsize}")

# Looks good up to 40 unique events
report = mne.Report("try")
report.add_events(events[:40, :], title="events", sfreq=100)
report.save("try.html", overwrite=True)

20 unique events (no changes compared to main ... and any fewer events will also produce same size fig)

image

30 unique events (slightly bigger figure, no events cut off)

image

40 unique events (max scaling, no events cut off)

image

60 unique events (same scaling as for 40, now some events cut off)

image

@larsoner
Copy link
Member

Looks good!

Maybe another easy improvement would be to only create the legend for the first [:40] handles and labels? That way we cut off the legend ourselves. Could even use the first [:40] handles and labels[:39] + ["..."] in cases where there are more than 40 to make it clear we've truncated?

Copy link
Member

@agramfort agramfort left a comment

Choose a reason for hiding this comment

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

useful magic :)

@sappelhoff
Copy link
Member Author

Maybe another easy improvement would be to only create the legend for the first [:40] handles and labels?

@larsoner with dac65e4 I opted instead to "magically" spread the legend over more columns.

This fixes the layout also for plots that contain really high amounts of different events, see for example the previous case of 60 unique events:

import numpy as np
import mne

events = np.arange(300).reshape(-1, 3)
n = 60
event_id = {f"very long string indeed even longer {i}": j for i, j in enumerate(events[:n, -1])}
fig = mne.viz.plot_events(events[:n, :], event_id=event_id, show=True)
image

With respect to the mne.Report, the changes here will also make it work "out of the box" for more cases than before, but will still lead to problems for some edge cases like:

  • even more unique events (so the additional figure scaling is still not enough)
  • very long event_id keys (so spreading over legend columns would lead to cutoffs in the horizontal again)

But all in all, I think this is about as much magic as we should introduce:

  • it fixes a good amount of cases
  • it does not introduce new problems (in that: people getting their plots cut off, would also have had them cut off with the previous code)
  • remaining issues should be approached with proper PRs, like dealing with html, as you suggested in #12835

Ready for merge from my side :-)

@sappelhoff
Copy link
Member Author

sappelhoff commented Sep 16, 2024

@larsoner I had one more idea on how to make the overview better when many events are supplied (and not worse when only few are supplied), see: b499f7b

When there are many events, the visual mapping between a dot on the canvas and the event_id becomes impossible. therefore a "duplicating" (strictly speaking) mapping in the legend would lead to a better correspondence, see examples:

Instead of having the count n just as some event id string (n) or N=n when event_id=None, it is now:

  • some event id string (id=1234; N=n)
  • id=1234; N=n

Note how the previous method of some event id string (n) also had a potential of being confusing, because people may not know that (n) is actually an event count. With the present N=n that should be more clear.

image

image

@larsoner
Copy link
Member

Beautiful!

How about touching some events tutorials/examples and the report tutorial just so we can see CircleCI render them, then marking for ready assuming they look good?

If you really want to venture into bonus territory you could open a PR to MNE-BIDS-Pipeline that makes CircleCI there install MNE-Python using your sappelhoff:events branch rather than upstream/main and we could inspect the reports there. But if not then we can merge this assuming MNE-Python's tutorials look good and I can bother you later if I see problems in MNE-BIDS-Pipeline 🙂

@sappelhoff
Copy link
Member Author

Thanks for the feedback, I will go to the bonus territory as soon as I find a chunk of time!

@sappelhoff
Copy link
Member Author

Examples for mne website

unfortunately, all of them are clipped now 🥲

  1. before, after
  2. before, after
  3. before, after
  4. before, after
  5. before, after
  6. before, after

Examples from mne-bids-pipeline

image

image


image

image


As mentioned above, some plots are not affected at all (apart from more info about id and N in legend).

image

image

image

image


And some previously existing problems are not touched / solved at all (here: clipping the legend due to long event_id keys).

image

image

@sappelhoff
Copy link
Member Author

@larsoner the long texts in the legend are problematic.

For most cases, this could be fixed with text wrapping: https://stackoverflow.com/a/47058132/5201771

Do you think that is something worth trying? any other ideas?

@sappelhoff
Copy link
Member Author

☝️ 0be3f9a clearly overshot with the fontsize="x-small" setting.

However, I have tested many more cases locally and found a few extra adjustments that we can try. See: 754a8a4

For me this works quite well locally (on my personal examples), and also looks good when running the examples.

Let's see how it looks online.

@larsoner
Copy link
Member

Yes I think overall the wrapping is an improvement. I don't think we can aim at perfection and what you have now is already an improvement in almost all cases so I think we can merge once you have another look through the examples. No need to link them all again since you've already linked plenty above -- I'm happy to trust your eyes for the last run(s), so you can just look and say "yes they look better" to save yourself some time 🙂

And at the end of the day if people have event ids that are super long they should probably consider renaming them with abbreviations in the event_id they pass in to plot_events or something like that. So I'm okay with those looking a little wacky. You could document this option/idea, though, if it's not in there. Or we can add it later once we check that it actually works.

@sappelhoff
Copy link
Member Author

I don't think we can aim at perfection and what you have now is already an improvement in almost all cases

Thanks! I was starting to go mad :-)

A little improvement was everything I was aiming for in the first place. Seemingly low hanging fruit 😉

I will report back when the circleci renderings for mne and mne-bids-pipeline are out and I am happy.

@sappelhoff
Copy link
Member Author

@larsoner I checked all outputs again, and (if you ask me) we have an improvement for every example I looked at now. Ready for merge from my side!

@larsoner
Copy link
Member

Failure is unrelated, thanks @sappelhoff !

@larsoner larsoner merged commit a218f96 into mne-tools:main Sep 20, 2024
26 of 28 checks passed
@sappelhoff sappelhoff deleted the events branch September 20, 2024 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants