2

I have a question and hope that you can help me. I put together a small MCVE below.

When you click the button for the first time, you can see that the 3d data (add_mesh, add_points) and 2d data (chart.scatter) show up. If you click it again only the 3d data shows up.

Does someone have an idea why this happens?

import sys
import os
os.environ["QT_API"] = "pyqt5"

from qtpy import QtWidgets
import numpy as np
from pyvista import Chart2D
import pyvista as pv
from pyvistaqt import QtInteractor, MainWindow

class MyMainWindow(MainWindow):

    def __init__(self, parent=None, show=True):
        QtWidgets.QMainWindow.__init__(self, parent)
        self.frame = QtWidgets.QFrame()
        vlayout = QtWidgets.QVBoxLayout()
        self.plotter = QtInteractor(self.frame)
        btn1 = QtWidgets.QPushButton("Button 1", self)
        vlayout.addWidget(btn1)
        btn1.clicked.connect(self.buttonClicked)
        vlayout.addWidget(self.plotter)
        self.frame.setLayout(vlayout)
        self.setCentralWidget(self.frame)
        self.show()


    def buttonClicked(self):

        self.plotter.clear()
        data = np.random.standard_normal(size=(100, 3))
        actor = self.plotter.add_points(data)
        chart = Chart2D()
        _x = np.random.standard_normal(100)
        _y = np.random.standard_normal(100)
        chart.scatter(_x, _y, color="tab:blue", style="d", label="Scores")
        self.plotter.add_chart(chart)
        self.plotter.add_mesh(pv.Sphere())

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MyMainWindow()

    sys.exit(app.exec_())
Joe
  • 6,758
  • 2
  • 26
  • 47

1 Answers1

2

I think you've found a bug, thanks for the great example! This is now fixed in PyVista version 0.35.2, updating the package should make things working. Original (pre-fix) version of the answer below.


What happens with charts is that they are stored in a private attribute called __charts, accessible via a private property called _charts on a plotter's Renderer. I.e. self.plotter.renderer._charts will give you a private pyvista.plotting.charts.Charts object. This is what actually keeps track of individual charts added via plotter.add_chart().

But calling plotter.clear() doesn't clear this list of charts. How exactly this messes with replotting is not yet clear to me (I suspect that somehow earlier charts prevent new ones from being added, but new ones have already been removed from the plotter). But it makes sense to clear the charts too on plotter.clear(), and if I do that by editing PyVista's library code, your issue goes away.

I've opened a pull request in PyVista to fix this (or to learn if I'm wrong about this being a bug). Until that happens and the fix is released, you can hack the equivalent step in your own code, in the callback:

        self.plotter.clear()
        self.plotter.renderer._charts.deep_clean()  # <- hacky workaround

Needless to say, this is a temporary measure and very bad form to have in your own code. As soon as we have a new release with this fixed, you should remove this line.

  • One thing that I found confusing is that after the first call, while showing the mesh and the chart, self.plotter.renderer.actors only lists the GLWhatever object of the sphere, no actor related to the chart. The same is shown after the second click. Is this expected? – Joe Jul 15 '22 at 05:10
  • That might be what you were mentioning in the PR, "plotter.renderer._actors has no knowledge of any chart-related stuff". – Joe Jul 15 '22 at 05:35
  • @Joe indeed. The `_actors` list on `pyvista.Renderer`s is maintained by PyVista. Charts (currently) use VTK methods like `AddActor()`/`RemoveActor()`, which gets around the PyVista logistics. I actually have a mind to fix this, but that's a less urgent matter so it should probably have to be a different PR. – Andras Deak -- Слава Україні Jul 15 '22 at 09:48
  • @Joe PyVista version 0.35.2 is now out with a fix for this. Thanks again for finding it. – Andras Deak -- Слава Україні Jul 18 '22 at 20:10