Select to view content in your preferred language

python add-in and matplotlib crash

2306
4
Jump to solution
05-06-2014 12:30 PM
KarenMaloof1
Deactivated User
I'm trying to make a python add-in toolbar that displays a graph. I can create a graph with a function in command line without any difficulty, but when I try to create the same graph from within a class for the add-in, it crashes. The crash happens whether the class is made in the command line or the add-in button.  What happens is the graph appears, then a few seconds later, arcmap unexpectedly shuts down, and asks if I want to send an error report.

The class causing the crash is:
class ButtonClass15(object):     """Implementation for WizardTest_addin.button (Button)"""     def __init__(self):         self.enabled = True         self.checked = False     def onClick(self):         allVals = ((1,1),(2,2),(3,3))         valArray = np.array (allVals)                  rasterArray  = valArray [:,0]         distanceArray = valArray [:,1]          pyplot.plot(distanceArray, rasterArray, 'r' )         pyplot.xlabel('Distance from Start')         pyplot.ylabel('Raster Val')         pyplot.show()



Does anyone have any workarounds that would let me display the graph while still creating it with an add-in button?

Thanks!
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
MattEiben
Deactivated User
It looks like matplotlib utilizes Tkinter in it's backend.  I've had problems running Tkinter windows from within ArcMap.  I was on 10.2, but in my case, ArcMap immediately crashed with no error window when I run a Tkinter window through a python add-in.

One solution that I found was to launch your Tk based window through the subprocess module, so it's doesn't interfere with ArcMap.  Here's an example of a way I made something somewhat similar work.

In my main add-in, I called on the gui file through the subprocess module:

import arcpy import pythonaddins import os from subprocess import Popen, PIPE  class CreateNewXYPoint(object):     """     Implementation for Create_New_Point_addin.createNewXYPoint (Button)     """     def __init__(self):         ...         ...         ...      def onClick(self):         self.GUI_response = open_GUI("GUI.py")         self.returnedData = self.GUI_response.split(";")  def open_GUI(file_name):     file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), file_name)     proc = Popen(file_path, shell=True, stdout=PIPE, bufsize=1)     stdoutdata, stderrdata = proc.communicate()     return stdoutdata


In a second GUI.py Python file in the same "Install" directory, you have your code for the GUI.  In my case, I wasn't passing any information in, mine was a custom Tkinter window to collect user information.  I passed back my collected data as semicolon delineated text through the stdout.

from Tkinter import * from ttk import *  class GetXYPointInfoGUI(object):     def __init__(self):         # Your custom class   gui = GetXYPointInfoGUI() print "{0};{1};{2}".format(gui.latitude,gui.longitude,gui.name)


I'm not entirely certain how to make this work in your case, since it looks like you need to pass variables into matplotlib, but maybe my solution will give you some ideas.  Hope this helps!

Matt

View solution in original post

0 Kudos
4 Replies
MattEiben
Deactivated User
It looks like matplotlib utilizes Tkinter in it's backend.  I've had problems running Tkinter windows from within ArcMap.  I was on 10.2, but in my case, ArcMap immediately crashed with no error window when I run a Tkinter window through a python add-in.

One solution that I found was to launch your Tk based window through the subprocess module, so it's doesn't interfere with ArcMap.  Here's an example of a way I made something somewhat similar work.

In my main add-in, I called on the gui file through the subprocess module:

import arcpy import pythonaddins import os from subprocess import Popen, PIPE  class CreateNewXYPoint(object):     """     Implementation for Create_New_Point_addin.createNewXYPoint (Button)     """     def __init__(self):         ...         ...         ...      def onClick(self):         self.GUI_response = open_GUI("GUI.py")         self.returnedData = self.GUI_response.split(";")  def open_GUI(file_name):     file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), file_name)     proc = Popen(file_path, shell=True, stdout=PIPE, bufsize=1)     stdoutdata, stderrdata = proc.communicate()     return stdoutdata


In a second GUI.py Python file in the same "Install" directory, you have your code for the GUI.  In my case, I wasn't passing any information in, mine was a custom Tkinter window to collect user information.  I passed back my collected data as semicolon delineated text through the stdout.

from Tkinter import * from ttk import *  class GetXYPointInfoGUI(object):     def __init__(self):         # Your custom class   gui = GetXYPointInfoGUI() print "{0};{1};{2}".format(gui.latitude,gui.longitude,gui.name)


I'm not entirely certain how to make this work in your case, since it looks like you need to pass variables into matplotlib, but maybe my solution will give you some ideas.  Hope this helps!

Matt
0 Kudos
JoshuaChisholm
Frequent Contributor
Hello Karen,

I haven't used "pyplot", so this is just a guess.

I suspect that pyplot.show() is somehow breaking ArcMap. As a possible workaround, could you save the graph to a image (in a temporary location) and pop up the image?
Try this:
import os

#other code...
pyplot.ylabel('Raster Val')
fig1=pyplot.gcf()
fig1.savefig(r'C:\Path\To\tempImage.png', dpi=100)
os.system(r'"C:\Path\To\tempImage.png"')


Let me know if it works!
0 Kudos
DaveBarrett
Deactivated User
Hi Karen,

You may struggle to get anything that relies on a GUI to work within ArcMap, this thread highlights few issues.

http://forums.arcgis.com/threads/58207-ArcPy-and-Tkinter

The main one that is the tkinter event loop used by pyplot does not play nicely with the ArcMap interface.

Dave
0 Kudos
KarenMaloof1
Deactivated User
Thanks Matt. I was able to make a workaround by passing the argument as a file. Awkward, but it seems to work.

Karen
0 Kudos