title: Can't get matplotlib event handler working with Boost.Python
body: <p>I am developing a C++11 program with an interpreter (written in C++) that calls various class methods to do work.  I want to add the ability to create plots of data using Python 3.5 with matplotlib (backend is TkAgg).  I also want users to be able to start a Python interpreter or run python scripts from within the program in order to make detailed adjustments/enhancements to the plots in real time.</p>
  
  <p>So far I’ve been successful at creating and saving the plots using Boost.Python 1.65.1 as my interface layer, and at launching a Python interpreter using Python’s code module.  However, the event loops of the matplotlib plots do not run at my C++ interpreter prompt (i.e. if I place another window over my plot, the figure turns blank and doesn’t redraw).  It is only when the user starts the Python interpreter that the event loops work and figures are redrawn.  I’d like the program to behave as if the user created the plots in a native Python interpreter after issuing the matplotlib.pyplot.ion() command.  I’ve added a plt.ion() call to the Python code used to create the plots but this doesn’t seem to have an impact on the resulting behavior.</p>
  
  <p>I’ve attempted to fix this by performing  Python plotting and C++ interpreting on different threads, however it doesn’t seem to help anything.  I’d like to know if I should be handling the Python GIL differently from the way I am currently, or if there is something else I can do to get the matplotlib event loops running in the background thread.  I’ve posted a simple example that recreates the core issue I am having.  Any help is appreciated.</p>
  
  <p>One other thing I've tried is to manually call matplotlib's canvas.start_event_loop().  This seems to work, but it blocks me from creating new plots until it returns/timesout which isn't ideal.</p>
  
  <p><strong>Here is the Python code to create the plots</strong></p>
  
  <pre><code># Import matplotlib and pyplot and turn on interactive mode
  import matplotlib
  import matplotlib.pyplot as plt
  plt.ion()
  
  def PlotData(num):
      """ Create a simple plot and return the figure.
      """
      data_list = [[1,2,3,4],[3,2,4,1],[4,3,2,1]]
      data = data_list[num]
  
      f = plt.figure()
      ax = f.gca()
  
      ax.set_xlabel('x label')
      ax.set_ylabel('y label')
  
      ax.plot([1,2,3,4],data,'bo-')
  
      title = 'Data Set ' + str(num+1)
      f.suptitle(title)
      print(title)
      f.show()
      return f
  </code></pre>
  
  <p><strong>Here is the C++ Code</strong></p>
  
  <pre><code>#include &lt;boost/python.hpp&gt;
  #include &lt;boost/thread.hpp&gt;
  #include &lt;boost/bind.hpp&gt;
  #include &lt;boost/asio/io_service.hpp&gt;
  #include &lt;boost/chrono.hpp&gt;
  
  #include &lt;iostream&gt;
  #include &lt;string&gt;
  
  PyThreadState* mainThreadState = nullptr;
  PyThreadState* pts = nullptr; /*!&lt; Pointer for the current thread state */
  
  /*! Initialize Python */
  void init()
  {
      Py_Initialize();
      PyEval_InitThreads();
      mainThreadState = PyEval_SaveThread();
  }
  
  void init_thread()
  {
      pts = PyThreadState_New(mainThreadState-&gt;interp);
  }
  
  /*! Calls Python to create a simple plot interactively */
  void PlotData(const int&amp; inp)
  {
      using namespace boost::python;
  
      // Acquire the GIL
      std::cout &lt;&lt; "Python Thread GIL State (before): " &lt;&lt; PyGILState_Check() &lt;&lt; std::endl;
      PyEval_RestoreThread(pts);
  
      object background = import("sto");
      object fig = background.attr("PlotData")(inp);
  
      // The code below will show the plot, but the plot won't update in real time at the C++ command line
      object plt = import("matplotlib.pyplot");
      fig.attr("show")();
      plt.attr("pause")(.1);
  
      std::cout &lt;&lt; "Python Thread GIL State (during): " &lt;&lt; PyGILState_Check() &lt;&lt; std::endl;
  
      // Release the GIL
      pts = PyEval_SaveThread();
      std::cout &lt;&lt; "Python Thread GIL State (after): " &lt;&lt; PyGILState_Check() &lt;&lt; std::endl;
  }
  
  int main(int argc, char* argv[])
  {
      // Create a thread pool with 1 thread for all Python code
      boost::asio::io_service ioService;
      boost::thread_group threadpool;
  
      // Start the service
      auto work = std::make_shared&lt;boost::asio::io_service::work&gt;(ioService);
  
      // Add a single thread to the thread pool for Python operations
      threadpool.create_thread(boost::bind(&amp;boost::asio::io_service::run, &amp;ioService));
  
      // Initialize Python
      init();
      std::cout &lt;&lt; "Submitting init_thread" &lt;&lt; std::endl;
      ioService.post(boost::bind(init_thread));
  
      // Create some plots on the background thread
      std::cout &lt;&lt; "Submitting PlotData calls" &lt;&lt; std::endl;
      ioService.post(boost::bind(PlotData,0));
      ioService.post(boost::bind(PlotData,1));
  
      // Pause to allow plots to update in realtime
      boost::this_thread::sleep_for(boost::chrono::seconds(4));
  
      // Receive inputs from command line (the plots should update during this time but they don't)
      std::string inp{"1"};
      std::cout &lt;&lt; "Enter to quit\n";
      while (!inp.empty())
      {
          std::cout &lt;&lt; "&gt;&gt; ";
          std::getline(std::cin,inp);
          std::cout &lt;&lt; "GIL State: " &lt;&lt; PyGILState_Check() &lt;&lt; std::endl;
      }
  
      // Finalize Python
      std::cout &lt;&lt; "Submitting Py_Finalize" &lt;&lt; std::endl;
      ioService.post(boost::bind(PyEval_RestoreThread,pts));
      ioService.post(boost::bind(Py_Finalize));
  
      // Allow jobs to complete and shut down the thread pool
      work.reset();
      threadpool.join_all();
      ioService.stop();
  
      return 0;
  }
  </code></pre>