我是Python的新手。 我正在尝试使用mlab包从Python内部运行MATLAB。 我按照网站上的指南,我在Python命令行中input:
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
我浏览了代码,我不认为所有的README文件及其文档都与实际实现的相匹配。 它似乎主要是从原来的mlabwrap
项目复制。
这是令人困惑的,因为mlabwrap
是使用C扩展模块与MATLAB Engine API交互实现的。 然而, mlab
代码似乎已经用一个纯粹的Python实现替代了这个部分作为mlab
桥后端。 它来自“Dana Peer实验室” ,它使用两种不同的方法与MATLAB交互,具体取决于平台(Windows上的COM / ActiveX和Linux / Mac上的管道 )。
现在,我们了解后端的实现方式,您可以开始查看导入错误。
注意:代码中的Linux / Mac部分尝试在某些硬编码的固定位置查找 MATLAB可执行文件,并允许在不同版本之间进行选择。
然而,你正在使用Windows,代码并没有真正实现在这个平台的MATLAB版本之间进行选择的方式(所以像discover_location
和find_available_releases
这样的所有方法在Windows上都是没用的)。 最后,COM对象被创建为 :
self.client = win32com.client.Dispatch('matlab.application')
正如这里所解释的 ,ProgID matlab.application
不是版本特定的,只是简单地使用任何被注册为默认的MATLAB COM服务器。 我们可以明确指定我们想要的MATLAB版本(假设您有多个安装),例如matlab.application.8.3
将选择MATLAB R2014a。
所以要修复代码,IMO最简单的方法就是摆脱所有关于多个MATLAB版本(在代码的Windows部分 )的逻辑,并且让它直接创建MATLAB COM对象。 我没有尝试过,但我不认为这太涉及了…祝你好运!
我下载了模块,并设法让它在Windows上工作(我正在使用Python 2.7.6和MATLAB R2014a)。 这里是变化:
$ 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.XY
键,并在HKCR\CLSID
按照它们的HKCR\CLSID
)。 这样,你可以真正选择和选择运行的版本。
我还修复了两个不相关的错误(一个是作者忘记了函数返回值,另一个是不必要地创建了两次包装器对象)。
注意:在测试过程中,每次调用脚本时,不要启动/关闭一个MATLAB实例。 这就是为什么我在close
函数中评论self.eval('quit();')
的原因。 这样,你可以使用matlab.exe -automation
启动MATLAB (只做一次),然后反复重复使用会话而不关闭它。 只要你完成了就杀了这个过程:)
这里是一个测试模块的Python例子(我也展示了一个与NumPy / SciPy / Matplotlib的比较):
# 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
。
你说的没有写find_available_releases()是正确的。 2种方法来解决这个问题
在matlabp.py中添加以下函数
def find_available_releases(): global _RELEASES if not _RELEASES: _RELEASES = list(_list_releases()) return _RELEASES
如果你看到mlabraw.py文件,下面的代码会给你一个清晰的概念,为什么我这么说!
import sys is_win = 'win' in sys.platform if is_win: from matlabcom import MatlabCom as MatlabConnection from matlabcom import MatlabError as error from matlabcom import discover_location, find_available_releases from matlabcom import WindowsMatlabReleaseNotFound as MatlabReleaseNotFound else: from matlabpipe import MatlabPipe as MatlabConnection from matlabpipe import MatlabError as error from matlabpipe import discover_location, find_available_releases from matlabpipe import UnixMatlabReleaseNotFound as MatlabReleaseNotFound