Python Mlab-无法导入名称find_available_releases [英] Python Mlab - cannot import name find_available_releases

查看:142
本文介绍了Python Mlab-无法导入名称find_available_releases的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Python的新手.我正在尝试使用 mlab 包从Python内部运行MATLAB.我正在网站上的指南中进行操作,并在Python命令行中输入了此内容:

from mlab.releases import latest_release

我得到的错误是:

cannot import name find_available_releases

matlabcom.py下似乎没有find_available_releases函数.

我可以知道是否有人知道如何解决这个问题吗?谢谢!

PS:我正在使用Windows 7,MATLAB 2012a和Python 2.7

解决方案

我浏览了一下代码,但我不认为所有 mlabwrap 项目复制的.

这令人困惑,因为mlabwrap是使用 C扩展模块实现的 MATLAB进行交互引擎API .但是mlab代码似乎已用纯Python实现作为MATLAB桥接后端替换了该部分.它来自"Dana Peerer Lab ",它会根据平台使用两种不同的方法与MATLAB进行交互( >在Linux/Mac上为管道).


现在我们了解了后端的实现方式,您可以开始查看导入错误.

注意:代码的Linux/Mac部分尝试在硬编码的固定位置查找 MATLAB可执行文件,并允许在不同版本之间进行选择.

无论如何,您都在Windows上工作,并且代码实际上并没有实现在此平台的MATLAB版本之间进行选择的任何方式(因此,discover_locationfind_available_releases之类的所有方法在Windows上都是无用的).最后,COM对象是创建为:

self.client = win32com.client.Dispatch('matlab.application')

在此处解释,ProgID matlab.application不是特定于版本的,它将仅使用 $ git diff diff --git a/src/mlab/matlabcom.py b/src/mlab/matlabcom.py index 93f075c..da1c6fa 100644 --- a/src/mlab/matlabcom.py +++ b/src/mlab/matlabcom.py @@ -21,6 +21,11 @@ except: print 'win32com in missing, please install it' raise +def find_available_releases(): + # report we have all versions + return [('R%d%s' % (y,v), '') + for y in range(2006,2015) for v in ('a','b')] + def discover_location(matlab_release): pass @@ -62,7 +67,7 @@ class MatlabCom(object): """ self._check_open() try: - self.eval('quit();') + pass #self.eval('quit();') except: pass del self.client diff --git a/src/mlab/mlabraw.py b/src/mlab/mlabraw.py index 3471362..16e0e2b 100644 --- a/src/mlab/mlabraw.py +++ b/src/mlab/mlabraw.py @@ -42,6 +42,7 @@ def open(): if is_win: ret = MatlabConnection() ret.open() + return ret else: if settings.MATLAB_PATH != 'guess': matlab_path = settings.MATLAB_PATH + '/bin/matlab' diff --git a/src/mlab/releases.py b/src/mlab/releases.py index d792b12..9d6cf5d 100644 --- a/src/mlab/releases.py +++ b/src/mlab/releases.py @@ -88,7 +88,7 @@ class MatlabVersions(dict): # Make it a module sys.modules['mlab.releases.' + matlab_release] = instance sys.modules['matlab'] = instance - return MlabWrap() + return instance def pick_latest_release(self): return get_latest_release(self._available_releases)

首先,我添加了缺少的find_available_releases函数.我这样做是为了报告所有MATLAB版本都可用(就像我在上面解释的那样,因为创建COM对象的方式并没有什么关系).更好的解决方案是使用Windows注册表检测已安装/注册的MATLAB版本(检查键HKCR\Matlab.Application.X.Y并遵循HKCR\CLSID中的CLSID).这样,您就可以真正选择并选择要运行的版本.

我还修复了两个不相关的错误(一个错误是作者忘记了函数的返回值,另一个错误是不必要地两次创建了包装对象).

注意:在测试过程中,每次调用脚本时不启动/关闭MATLAB实例可能会更快.这就是为什么我在close函数中注释了self.eval('quit();')的原因.这样,您可以使用matlab.exe -automation 启动MATLAB . (仅执行一次),然后在不关闭会话的情况下重复使用该会话.完成后就杀死进程:)

这是一个测试模块的Python示例(我还显示了与NumPy/SciPy/Matplotlib的比较):

test_mlab.py

 # could be anything from: latest_release, R2014b, ..., R2006a
# makes no difference :)
from mlab.releases import R2014a as matlab

# show MATLAB version
print "MATLAB version: ", matlab.version()
print matlab.matlabroot()

# compute SVD of a NumPy array
import numpy as np
A = np.random.rand(5, 5)
U, S, V = matlab.svd(A, nout=3)
print "S = \n", matlab.diag(S)

# compare MATLAB's SVD against Scipy's SVD
U, S, V = np.linalg.svd(A)
print S

# 3d plot in MATLAB
X, Y, Z = matlab.peaks(nout=3)
matlab.figure(1)
matlab.surf(X, Y, Z)
matlab.title('Peaks')
matlab.xlabel('X')
matlab.ylabel('Y')
matlab.zlabel('Z')

# compare against matplotlib surface plot
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='jet')
ax.view_init(30.0, 232.5)
plt.title('Peaks')
plt.xlabel('X')
plt.ylabel('Y')
ax.set_zlabel('Z')
plt.show()
 

这是我得到的输出:

C:\>python test_mlab.py
MATLAB version: 8.3.0.532 (R2014a)
C:\Program Files\MATLAB\R2014a
S =
[[ 2.41632007]
 [ 0.78527851]
 [ 0.44582117]
 [ 0.29086795]
 [ 0.00552422]]
[ 2.41632007  0.78527851  0.44582117  0.29086795  0.00552422]


上述更改已接受并合并为mlab. >

I am new to Python. I am trying to run MATLAB from inside Python using the mlab package. I was following the guide on the website, and I entered this in the Python command line:

from mlab.releases import latest_release

The error I got was:

cannot import name find_available_releases

It seems that under matlabcom.py there was no find_available_releases function.

May I know if anyone knows how to resolve this? Thank you!

PS: I am using Windows 7, MATLAB 2012a and Python 2.7

解决方案

I skimmed through the code, and I don't think all of the README file and its documentation match what's actually implemented. It appears to be mostly copied from the original mlabwrap project.

This is confusing because mlabwrap is implemented using a C extension module to interact with the MATLAB Engine API. However the mlab code seems to have replaced that part with a pure Python implementation as the MATLAB-bridge backend. It comes from "Dana Pe'er Lab" and it uses two different methods to interact with MATLAB depending on the platform (COM/ActiveX on Windows and pipes on Linux/Mac).


Now that we understand how the backend is implemented, you can start looking at the import error.

Note: the Linux/Mac part of the code tries to find the MATLAB executable in some hardcoded fixed locations, and allows to choose between different versions.

However you are working on Windows, and the code doesn't really implement any way of picking between MATLAB releases for this platform (so all of the methods like discover_location and find_available_releases are useless on Windows). In the end, the COM object is created as:

self.client = win32com.client.Dispatch('matlab.application')

As explained here, the ProgID matlab.application is not version-specific, and will simply use whatever was registered as the default MATLAB COM server. We can explicitly specify what MATLAB version we want (assuming you have multiple installations), for instance matlab.application.8.3 will pick MATLAB R2014a.

So to fix the code, IMO the easiest way would be to get rid of all that logic about multiple MATLAB versions (in the Windows part of the code), and just let it create the MATLAB COM object as is. I haven't attempted it, but I don't think it's too involved... Good luck!


EDIT:

I download the module and I managed to get it to work on Windows (I'm using Python 2.7.6 and MATLAB R2014a). Here are the changes:

$ git diff
diff --git a/src/mlab/matlabcom.py b/src/mlab/matlabcom.py
index 93f075c..da1c6fa 100644
--- a/src/mlab/matlabcom.py
+++ b/src/mlab/matlabcom.py
@@ -21,6 +21,11 @@ except:
   print 'win32com in missing, please install it'
   raise

+def find_available_releases():
+    # report we have all versions
+    return [('R%d%s' % (y,v), '')
+        for y in range(2006,2015) for v in ('a','b')]
+
 def discover_location(matlab_release):
     pass

@@ -62,7 +67,7 @@ class MatlabCom(object):
     """
     self._check_open()
     try:
-      self.eval('quit();')
+      pass    #self.eval('quit();')
     except:
       pass
     del self.client
diff --git a/src/mlab/mlabraw.py b/src/mlab/mlabraw.py
index 3471362..16e0e2b 100644
--- a/src/mlab/mlabraw.py
+++ b/src/mlab/mlabraw.py
@@ -42,6 +42,7 @@ def open():
     if is_win:
         ret = MatlabConnection()
         ret.open()
+        return ret
     else:
         if settings.MATLAB_PATH != 'guess':
             matlab_path = settings.MATLAB_PATH + '/bin/matlab'
diff --git a/src/mlab/releases.py b/src/mlab/releases.py
index d792b12..9d6cf5d 100644
--- a/src/mlab/releases.py
+++ b/src/mlab/releases.py
@@ -88,7 +88,7 @@ class MatlabVersions(dict):
         # Make it a module
         sys.modules['mlab.releases.' + matlab_release] = instance
         sys.modules['matlab'] = instance
-        return MlabWrap()
+        return instance

     def pick_latest_release(self):
         return get_latest_release(self._available_releases)

First I added the missing find_available_releases function. I made it so that it reports that all MATLAB versions are available (like I explained above, it doesn't really matter because of the way the COM object is created). An even better fix would be to detect the installed/registered MATLAB versions using the Windows registry (check the keys HKCR\Matlab.Application.X.Y and follow their CLSID in HKCR\CLSID). That way you can truly choose and pick which version to run.

I also fixed two unrelated bugs (one where the author forgot the function return value, and the other unnecessarily creating the wrapper object twice).

Note: During testing, it might be faster NOT to start/shutdown a MATLAB instance each time the script is called. This is why I commented self.eval('quit();') in the close function. That way you can start MATLAB using matlab.exe -automation (do this only once), and then repeatedly re-use the session without shutting it down. Just kill the process when you're done :)

Here is a Python example to test the module (I also show a comparison against NumPy/SciPy/Matplotlib):

test_mlab.py

# could be anything from: latest_release, R2014b, ..., R2006a
# makes no difference :)
from mlab.releases import R2014a as matlab

# show MATLAB version
print "MATLAB version: ", matlab.version()
print matlab.matlabroot()

# compute SVD of a NumPy array
import numpy as np
A = np.random.rand(5, 5)
U, S, V = matlab.svd(A, nout=3)
print "S = \n", matlab.diag(S)

# compare MATLAB's SVD against Scipy's SVD
U, S, V = np.linalg.svd(A)
print S

# 3d plot in MATLAB
X, Y, Z = matlab.peaks(nout=3)
matlab.figure(1)
matlab.surf(X, Y, Z)
matlab.title('Peaks')
matlab.xlabel('X')
matlab.ylabel('Y')
matlab.zlabel('Z')

# compare against matplotlib surface plot
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='jet')
ax.view_init(30.0, 232.5)
plt.title('Peaks')
plt.xlabel('X')
plt.ylabel('Y')
ax.set_zlabel('Z')
plt.show()

Here is the output I get:

C:\>python test_mlab.py
MATLAB version: 8.3.0.532 (R2014a)
C:\Program Files\MATLAB\R2014a
S =
[[ 2.41632007]
 [ 0.78527851]
 [ 0.44582117]
 [ 0.29086795]
 [ 0.00552422]]
[ 2.41632007  0.78527851  0.44582117  0.29086795  0.00552422]


EDIT2:

The above changes have been accepted and merged into mlab.

这篇关于Python Mlab-无法导入名称find_available_releases的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆