Skip to content

Conversation

@kunmonster
Copy link

As described in #362, when the user only wants to save the plot, the terminal is still set to qt and the graphic view is invoked.
This behavior should not occur when the plot is only exported without interactive display.

Root cause

Fix

  • Open the gnuplot pipe lazily only when show() or save() is called.
  • Render the plot only when necessary (either show or save), avoiding redundant rendering.

void gnuplot::lazy_init_pipe() {
int perr;
if constexpr (windows_should_persist_by_default) {
perr = pipe_.open("gnuplot --persist");
Copy link
Owner

Choose a reason for hiding this comment

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

So it's not only opening it later but also calling it every time we show the figure?

Copy link
Author

@kunmonster kunmonster Oct 14, 2025

Choose a reason for hiding this comment

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

Sorry, maybe I should check whether the pipe is already open before opening it again, to avoid reopening it when calling show() or save() multiple times.

Copy link
Owner

Choose a reason for hiding this comment

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

Yes. True. If the point of the PR is only to make it lazy, that makes more sense.

But I was checking because I'm not so familiar with the changes.

Copy link
Author

Choose a reason for hiding this comment

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

There's one point, this change will revise the render haviour. For example, you can run the examples/data_distribution/hisrogram14, the original code will draw step by step. But the changed code will render once during the whole time.

Copy link
Owner

Choose a reason for hiding this comment

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

So this means it'll only render the first time and never update it?

Copy link
Owner

Choose a reason for hiding this comment

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

Sorry. That's what I understood so far, please correct me if I'm wrong:

  • Before this PR, draw() updates/renders the plot (especially important in "quiet" mode) and show() would do the same and also block
  • After this PR, draw() wouldn't do anything until you call show() and show() would have the same expected behavior

Is my understanding correct?

I'm sorry to be insisting. I don't want to block a PR because I don't understand it. But also can't merge a PR I don't understand clearly.

did you take into account the need to display one subplot at a time?

Yes. That should be possible. To only one subplot at a time, but one thing at a time. That's why the distinction between 'draw' and 'show' exists. That's not even my design. It comes from all other analogous libraries.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, your understanding is correct.
But if this use case (displaying one subplot at a time) was indeed taken into account, then this PR might need to be reconsidered.
This issue seems quite tricky to fix and may require further discussion to find a proper solution.

Copy link
Author

@kunmonster kunmonster Oct 15, 2025

Choose a reason for hiding this comment

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

if I understant the plot logic correctly, I would like to recommend to remove the render code when adding child, and it should occus just in show or draw.

Copy link
Owner

@alandefreitas alandefreitas Oct 15, 2025

Choose a reason for hiding this comment

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

then this PR might need to be reconsidered

Exactly. I think so. draw() should update the plot pretty much like in matplotlib.

Copy link
Author

Choose a reason for hiding this comment

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

OK, I will close the PR, hope you can fix this in the future.

void figure_type::show() { backend_->show(this); }
void figure_type::show() {
// open the gnu pipe when show method is called
backend_->lazy_init_pipe();
Copy link
Owner

Choose a reason for hiding this comment

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

If this is going to be called every time we call "show", it's it easier to conceptually make it part of the gnuplot backend only and call it at the beginning of the show function?

Copy link
Author

@kunmonster kunmonster Oct 14, 2025

Choose a reason for hiding this comment

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

Yep, but there isn’t an API implementation for showing in gnuplot.cpp. We just use flushcommand() to flush the buffer and display the plot. However, you’re right -- it might be more reasonable to initialize the pipe in backend_interface instead of figure_type.

Copy link
Owner

Choose a reason for hiding this comment

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

Sorry. I'm a little confused. The very next line does backend_->show(this);. Isn't this calling "an API implementation for showing in gnuplot.cpp"? Do you mean the gnuplot backend doesn't override show()?

Copy link
Author

Choose a reason for hiding this comment

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

That's the truth what I want to say. But, it seems that the backend_interface::show doesn't need to be overrided. It's unnecessary.

Copy link
Owner

Choose a reason for hiding this comment

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

OK. So if I understand you correctly, matplot::backend::gnuplot doesn't define matplot::backend::gnuplot::show(), so that means matplot::backend::gnuplot::show() is equivalent to matplot::backend::backend_interface::show().

If that's correct, we could override and define matplot::backend::gnuplot::show() so that 1) it calls lazy_init_pipe() and only then 2) calls matplot::backend::backend_interface::show(). The advantage of this would be that the gnuplot fix would be limited to the scope of the gnuplot backend, and figure_type would make reference to a property that doesn't belong to all backends.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, that's a nice strategy.

@kunmonster
Copy link
Author

kunmonster commented Oct 14, 2025

Actually, I think the best way to fix the problem is that we shouldn't run the command while adding the child, instead just run the commands once in the show or save.

@kunmonster kunmonster closed this Oct 14, 2025
@kunmonster kunmonster reopened this Oct 14, 2025
@alandefreitas
Copy link
Owner

Actually, I think the best way to fix the problem is that we shouldn't run the command while adding the child, instead just run the commands once in the show or save.

I agree. This is what called "quiet mode" or something in this implementation. In retrospect, this should be the only mode possible. But it's too late to change that unless there's a matplot++ v2.

@kunmonster kunmonster closed this Oct 15, 2025
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.

2 participants