Python in GMS 3.4.x - DM crashes when using matplotlib.pyplot: Could not find or load the Qt platform plugin for windows

Viewed 435

I cannot get matplotlib.pyplot to work under GMS 3.4. It keeps crashing DM with the following error message

This application failed to start because it could not find or load the Qt platform plugin "windows" in "". Reinstalling the application may fix this problem.

When I run this code (taken from the DM Help document):

import sys
sys.argv.extend(['-a', ' '])
import numpy as np
import matplotlib.pyplot as plt

t = np.arange( 0.0, 3.0, 0.01)
s1 = np.sin(2 * np.pi * t)
plt.plot(t, s1)
plt.show()

Reinstalling/repairing GMS doesn't seems to solve the issue. I'm pretty new to Python so I may have missed something obvious?

3 Answers

Even though the fix presented by miile7 does its job, I would like to propose an alternative solution:

As very nicely pointed out by miile7, setting the environment variable globally might interfere with other software and should be avoided. To make DM finding the Qt platform, one can simply

Copy the folder

ProgramData\Miniconda3\envs\GMS_VENV_PYTHON\Library\plugins\platforms

to

Program Files\Gatan

or more specifically to the location of the DigitalMicrograph.exe

A more general, GMS-unrelated thread on this can be found here:

Changing QT_PLUGIN_PATH in environment variables causes programs to fail

Update:

It is probably better to create a junction by executing the following command (with admin rights):

mklink /J "C:\Program Files\Gatan\platforms" "C:\ProgramData\Miniconda3\envs\GMS_VENV_PYTHON\Library\plugins\platforms"

The problem is still fixed this way and in case you update/modify Qt in your Miniconda, DM should still find the latest version.

I wanted to use python in GMS too and I ended up with the same error. This took me several hours to find out why and how to fix it:

TL;DR

Save the following code as start-gatan.bat and use this start-gatan.bat file to start GMS. The file can be placed anywhere. Note that the console window has to stay open while GMS is active!

@echo off

rem
rem File: start-gatan.bat
rem ---------------------

SET QT_PLUGIN_PATH=%ProgramData%\Miniconda3\envs\GMS_VENV_PYTHON\Library\plugins
SET gms_path=%PROGRAMFILES%\Gatan\DigitalMicrograph.exe

echo Starting GMS
echo Do not close this window!

"%gms_path%"

Important note: To show the matplotlib window you have to untick the "Execute on Background Thread"-Checkbox in the footer of the code panel! Also it takes comparatively long to execute.


Cause

This is neither a GMS error nor a python error but a Qt error. For rendering windows matplotlib (by default) uses PyQT which uses Qt. The error tells about the qwindows.dll and that it cannot be found (explicitly?).

Side note: The renderer can be changed by adding e.g. matplotlib.use('GTK3Agg'). This does not show up the Qt-Error anymore but shows another error so I didn't follow this idea.

Solution

The qwindows.dll is located in %ProgramData%/Miniconda3/envs/GMS_VENV_PYTHON/Library/plugins/platforms. The path for the platform plugins can be set in the qt.conf (but this didn't fix it for me which, in this thread they mention that there may be differences) or in the environment variable %QT_PLUGIN_PATH% as I found here.

So add (create) the system variable %QT_PLUGIN_PATH% with the value %ProgramData%\Miniconda3\envs\GMS_VENV_PYTHON\Library\plugins. A system variable in Windows can be added under Control Panel > System > Advanced System Settings > Environment Variables.1

Note that this environment variable should only be present for GMS, not for all other QT programs. Therefore create a start-gatan.bat and copy the code postend at the top in the TL;DR section. Now start GMS by double clicking the start-gatan.bat and your example code will work.

Important note: To show the matplotlib window you have to untick the "Execute on Background Thread"-Checkbox in the footer of the code panel, otherwise the plot window will not be visible.

1Adding a new environment variable works but if you have one other program that uses QT (which is very likely the cause) you will run into the (nearly) same error message but in the other program. If you only have GMS pyqt using QT this may be your solution.

Further notes

Several forum threads including the QT forum tell about duplicate paths for this qwindows.dll. If my answer didn't help you you might want to look into that. Note that checking environment variables has to be done in the miniconda environment. So make sure to run

activate GMS_VENV_PYTHON

before outputting variables. Also you might want to have a look into the qt config which can be found at %PROGRAMDATA%/Miniconda3/envs/GMS_VENV_PYTHON/bin. Note that there always is the file in the normal Miniconda diretory (%PROGRAMDATA%/Miniconda3/bin) and the one in the envs.

Tested method to get MatplotLib to run in GMS
(Tested with GMS 3.4.1.2938 beta)

  • Start with clean system (no GMS installed, no Python-for-GMS Miniconda installed)
  • Install GMS with the installer and the Python option enabled.
  • Start the Anaconda-prompt with administrator rights (right-click item in start-menu)
    Start the Anaconda-prompt with administrator rights
  • Activate the GMS_VENV_PYTHON environment by typing activate GMS_VENV_PYTHON
  • Install Matplotlib with the pip installer by typing pip install Matplotlib (requires internet connection)
  • Start DigitalMicrograph and run the following test-script:
# This is a PYTHON script to be run in DigitalMicrograph
if ( False == DM.IsScriptOnMainThread() ):
    print( ' MatplotLib scripts require to be run on the main thread.' )
    exit()

import sys
sys.argv.extend(['-a', ' '])
import matplotlib.pyplot as plt
import numpy as np
a = np.linspace(0, 10, 100)
b = np.exp(-a)
plt.plot(a, b)

DM.ClearResults()
print('Start plotting. Script continues when figure is closed')
plt.show()
print('Done plotting.')

Result

And as a bonus, because this is about DM-scripting: Using the capability of hybrid-scripting one can wrap the Python call in a string and execute it directly from within a DM-script:

// This is a DM-script
string pyScript
pyScript += "import sys" + "\n"
pyScript += "sys.argv.extend(['-a', ' '])" + "\n"
pyScript += "import matplotlib.pyplot as plt" + "\n"
pyScript += "import numpy as np" + "\n"
pyScript += "a = np.linspace(0, 10, 100)" + "\n"
pyScript += "b = np.exp(-a)" + "\n"
pyScript += "plt.plot(a, b)" + "\n"
pyScript += "plt.show()" + "\n"

ClearResults()
Result( "Script continues when figure is closed\n" )
ExecutePythonScriptString( pyScript, 1 ) // On Main-thread
Result( "Done plotting.\n" )
Related