コード例 #1
0
    def __createFigure(self):
        ##      self.__fig=mpl.figure.Figure(figsize=(8, 5),constrained_layout=True, tight_layout=None)  #单位英寸
        ##      self.__fig=mpl.figure.Figure(figsize=(8, 5))  #单位英寸
        self.__fig = mpl.figure.Figure()
        figCanvas = FigureCanvas(self.__fig)  #创建FigureCanvas对象,必须传递一个Figure对象
        self.__fig.suptitle("suptitle:matplotlib in Qt GUI",
                            fontsize=16,
                            fontweight='bold')  # 总的图标题

        naviToolbar = NavigationToolbar(figCanvas,
                                        self)  #创建NavigationToolbar工具栏
        actList = naviToolbar.actions()  #关联的Action列表
        count = len(actList)  #Action的个数
        lastAction = actList[count - 1]  #最后一个Action

        labCurAxes = QLabel("当前子图")
        naviToolbar.insertWidget(lastAction, labCurAxes)
        self.__comboAxes = QComboBox(self)  #子图列表,用于选择子图
        self.__comboAxes.setToolTip("选择当前子图")
        self.__comboAxes.currentIndexChanged.connect(self.do_currentAxesChaned)
        naviToolbar.insertWidget(lastAction, self.__comboAxes)

        naviToolbar.insertAction(lastAction,
                                 self.ui.actQuit)  #在最后一个Action之前插入一个Action
        ##      naviToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)  #ToolButtonTextUnderIcon
        self.addToolBar(naviToolbar)  #添加作为主窗口工具栏

        splitter = QSplitter(self)
        splitter.setOrientation(Qt.Horizontal)
        splitter.addWidget(self.ui.toolBox)  #左侧控制面板
        splitter.addWidget(figCanvas)  #右侧FigureCanvas对象
        self.setCentralWidget(splitter)
コード例 #2
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.setWindowTitle("Demo14_3, 交互操作")
        self.__labMove = QLabel("Mouse Move:")
        self.__labMove.setMinimumWidth(200)
        self.ui.statusBar.addWidget(self.__labMove)

        self.__labPick = QLabel("Mouse Pick:")
        self.__labPick.setMinimumWidth(200)
        self.ui.statusBar.addWidget(self.__labPick)

        mpl.rcParams['font.sans-serif'] = ['SimHei']  #显示汉字为 楷体, 汉字不支持 粗体,斜体等设置
        mpl.rcParams['font.size'] = 11
        ##  Windows自带的一些字体
        ##  黑体:SimHei 宋体:SimSun 新宋体:NSimSun 仿宋:FangSong  楷体:KaiTi
        mpl.rcParams['axes.unicode_minus'] = False  #减号unicode编码

        self.__fig = None  #Figue对象
        self.__createFigure()  #创建Figure和FigureCanvas对象,初始化界面
        self.__drawFig1X2()

##  ==============自定义功能函数========================

    def __createFigure(self):  ##创建绘图系统
        self.__fig = mpl.figure.Figure(figsize=(8, 5))  #单位英寸
        figCanvas = FigureCanvas(self.__fig)  #创建FigureCanvas对象,必须传递一个Figure对象
        self.__naviBar = NavigationToolbar(figCanvas,
                                           self)  #创建NavigationToolbar工具栏

        actList = self.__naviBar.actions()  #关联的Action列表
        for act in actList:  #获得每个Action的标题和tooltip,可注释掉
            print("text=%s,\ttoolTip=%s" % (act.text(), act.toolTip()))
        self.__changeActionLanguage()  #改工具栏的语言为汉语
        ##工具栏改造
        actList[6].setVisible(False)  #隐藏Subplots 按钮
        actList[7].setVisible(False)  #隐藏Customize按钮
        act8 = actList[8]  #分隔条
        self.__naviBar.insertAction(act8, self.ui.actTightLayout)  #"紧凑布局"按钮
        self.__naviBar.insertAction(act8, self.ui.actSetCursor)  #"十字光标"按钮

        count = len(actList)  #Action的个数
        lastAction = actList[count - 1]  #最后一个Action
        self.__naviBar.insertAction(lastAction,
                                    self.ui.actScatterAgain)  #"重绘散点"按钮

        lastAction.setVisible(False)  #隐藏其原有的坐标提示
        self.__naviBar.addSeparator()
        self.__naviBar.addAction(self.ui.actQuit)  #"退出"按钮
        self.__naviBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)  #显示方式

        self.addToolBar(self.__naviBar)  #添加作为主窗口工具栏
        self.setCentralWidget(figCanvas)

        figCanvas.setCursor(Qt.CrossCursor)
        ## 必须保留变量cid,否则可能被垃圾回收
        self._cid1 = figCanvas.mpl_connect("motion_notify_event",
                                           self.do_canvas_mouseMove)
        self._cid2 = figCanvas.mpl_connect("axes_enter_event",
                                           self.do_axes_mouseEnter)
        self._cid3 = figCanvas.mpl_connect("axes_leave_event",
                                           self.do_axes_mouseLeave)
        self._cid4 = figCanvas.mpl_connect("pick_event", self.do_series_pick)
        self._cid5 = figCanvas.mpl_connect("scroll_event", self.do_scrollZoom)

    def __changeActionLanguage(self):
        actList = self.__naviBar.actions()  #关联的Action列表
        actList[0].setText("复位")  #Home
        actList[0].setToolTip("复位到原始视图")  #Reset original view

        actList[1].setText("回退")  #Back
        actList[1].setToolTip("回到前一视图")  #Back to previous view

        actList[2].setText("前进")  #Forward
        actList[2].setToolTip("前进到下一视图")  #Forward to next view

        actList[4].setText("平动")  #Pan
        actList[4].setToolTip(
            "左键平移坐标轴,右键缩放坐标轴")  #Pan axes with left mouse, zoom with right

        actList[5].setText("缩放")  #Zoom
        actList[5].setToolTip("框选矩形框缩放")  #Zoom to rectangle

        actList[6].setText("子图")  #Subplots
        actList[6].setToolTip("设置子图")  #Configure subplots

        actList[7].setText("定制")  #Customize
        actList[7].setToolTip("定制图表参数")  #Edit axis, curve and image parameters

        actList[9].setText("保存")  #Save
        actList[9].setToolTip("保存图表")  #Save the figure

    def __drawScatters(self, N=15):
        x = range(N)  #序列0,1,....N-1
        ##      x=np.random.rand(N)
        y = np.random.rand(N)
        colors = np.random.rand(N)  #0~1之间随机数
        self.__markerSize = (
            40 * (0.2 + np.random.rand(N)))**2  #0 to 15 point radius
        self.__axScatter.scatter(x,
                                 y,
                                 s=self.__markerSize,
                                 c=colors,
                                 marker='*',
                                 alpha=0.5,
                                 label="scatter series",
                                 picker=True)  #允许被拾取pick
        #s=The marker size in points**2
        #c=color, sequence, or sequence of color, optional, default: 'b'
        ## marker : `~matplotlib.markers.MarkerStyle`, optional, default: 'o'
        self.__axScatter.set_title("散点图")
        self.__axScatter.set_xlabel('序号')  # X轴标题

    def __drawFig1X2(self):  #初始化绘图
        gs = self.__fig.add_gridspec(1, 2)  #1行,2列
        ##      ax1=self.__fig.add_subplot(1,1,1) #添加一个Axes对象,并返回此对象,不支持constrained_layout
        ax1 = self.__fig.add_subplot(gs[0, 0], label="Line2D plot")

        t = np.linspace(0, 10, 40)
        y1 = np.sin(t)
        y2 = np.cos(2 * t)
        ax1.plot(t,
                 y1,
                 'r-o',
                 label="sin series",
                 linewidth=1,
                 markersize=5,
                 picker=True)  #绘制一条曲线
        ax1.plot(t, y2, 'b:', label="cos series", linewidth=2)  #绘制一条曲线
        ax1.set_xlabel('X 轴')
        ax1.set_ylabel('Y 轴')
        ax1.set_xlim([0, 10])
        ax1.set_ylim([-1.5, 1.5])
        ax1.set_title("曲线")
        ax1.legend()  #自动创建Axes的图例

        self.__axScatter = self.__fig.add_subplot(gs[0, 1],
                                                  label="scatter plot")  #创建子图
        self.__drawScatters(N=15)  #绘制散点图

##  ==============event处理函数==========================

##  ==========由connectSlotsByName()自动连接的槽函数============

    @pyqtSlot()  ## 紧凑布局
    def on_actTightLayout_triggered(self):
        self.__fig.tight_layout()  # 对所有子图 进行一次tight_layout
        self.__fig.canvas.draw()

    @pyqtSlot()  ## 设置鼠标光标
    def on_actSetCursor_triggered(self):
        self.__fig.canvas.setCursor(Qt.CrossCursor)

    @pyqtSlot()  ## 重新绘制散点图
    def on_actScatterAgain_triggered(self):
        self.__axScatter.clear()  #清除子图
        self.__drawScatters(N=15)
        self.__fig.canvas.draw()  #刷新

##  =================自定义槽函数==========
#event类型 matplotlib.backend_bases.MouseEvent

    def do_canvas_mouseMove(self, event):
        if event.inaxes == None:
            return
        info = "%s: xdata=%.2f,ydata=%.2f  " % (event.inaxes.get_label(),
                                                event.xdata, event.ydata)
        self.__labMove.setText(info)

## event类型:matplotlib.backend_bases.LocationEvent

    def do_axes_mouseEnter(self, event):
        event.inaxes.patch.set_facecolor('g')  #设置背景颜色
        event.inaxes.patch.set_alpha(0.2)  #透明度
        event.canvas.draw()

    def do_axes_mouseLeave(self, event):
        event.inaxes.patch.set_facecolor('w')  #设置背景颜色
        event.canvas.draw()

##event 类型: matplotlib.backend_bases.PickEvent

    def do_series_pick(self, event):
        series = event.artist  # 产生事件的对象
        index = event.ind[0]  #索引号,是array([int32])类型,可能有多个对象被pick,只取第1个
        #是否有ind属性与具体的对象有关

        if isinstance(series, mpl.collections.PathCollection):  #scatter()生成的序列
            markerSize = self.__markerSize[index]
            info = "%s: index=%d, marker size=%d " % (
                event.mouseevent.inaxes.get_label(), index, markerSize)
        elif isinstance(series, mpl.lines.Line2D):  #plot()生成的序列
            ##         xdata=series.get_xdata() #两种方法都可以
            ##         x=xdata[index]
            ##         ydata=series.get_ydata()
            ##         y=ydata[index]
            x = event.mouseevent.xdata  #标量数据点
            y = event.mouseevent.ydata  #标量数据点
            info = "%s: index=%d, data_xy=(%.2f, %.2f) " % (series.get_label(),
                                                            index, x, y)

        self.__labPick.setText(info)

#event类型 matplotlib.backend_bases.MouseEvent

    def do_scrollZoom(self, event):  #通过鼠标滚轮缩放
        ax = event.inaxes  # 产生事件的axes对象
        if ax == None:
            return

        self.__naviBar.push_current(
        )  #Push the current view limits and position onto the stack,这样才可以还原
        xmin, xmax = ax.get_xbound()  #获取范围
        xlen = xmax - xmin

        ymin, ymax = ax.get_ybound()  #获取范围
        ylen = ymax - ymin

        xchg = event.step * xlen / 20  #step [scalar],positive = ’up’, negative ='down'
        xmin = xmin + xchg
        xmax = xmax - xchg

        ychg = event.step * ylen / 20
        ymin = ymin + ychg
        ymax = ymax - ychg

        ax.set_xbound(xmin, xmax)
        ax.set_ybound(ymin, ymax)

        event.canvas.draw()
コード例 #3
0
class PlotWidget(QWidget):
    """A wrapper over CanvasWidget to handle additional MOOSE-specific
    stuff.

    modelRoot - path to the entire model our plugin is handling

    dataRoot - path to the container of data tables.

    pathToLine - map from moose path to Line2D objects in plot. Can
    one moose table be plotted multiple times? Maybe yes (e.g., when
    you want multiple other tables to be compared with the same data).

    lineToDataSource - map from Line2D objects to moose paths

    """

    widgetClosedSignal = pyqtSignal(object)
    addGraph = pyqtSignal(object)

    def __init__(self, model, graph, index, parentWidget, *args, **kwargs):
        super(PlotWidget, self).__init__()
        self.model = model
        self.graph = graph
        self.index = index

        self.menu = self.getContextMenu()
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.contextMenuRequested)
        #  self.connect( self
        #  , SIGNAL("customContextMenuRequested(QPoint)")
        #  , self
        #  , SLOT("contextMenuRequested(QPoint)")
        #  )

        self.canvas = CanvasWidget(self.model, self.graph, self.index)
        self.canvas.setParent(self)
        self.navToolbar = NavigationToolbar(self.canvas, self)
        self.hackNavigationToolbar()
        self.canvas.mpl_connect('pick_event', self.togglePlot)
        layout = QGridLayout()
        layout.addWidget(self.navToolbar, 0, 0)
        layout.addWidget(self.canvas, 1, 0)
        self.setLayout(layout)
        self.pathToLine = defaultdict(set)
        self.lineToDataSource = {}
        self.axesRef = self.canvas.addSubplot(1, 1)
        self.legend = None
        desktop = QApplication.desktop()
        self.setMinimumSize(desktop.screenGeometry().width() // 4,
                            desktop.screenGeometry().height() // 3)
        self.canvas.updateSignal.connect(self.plotAllData)
        self.plotAllData()

    def hackNavigationToolbar(self):
        # ADD Graph Action
        pixmap = QtGui.QPixmap(
            os.path.join(config.MOOSE_ICON_DIR, 'add_graph.png'))
        icon = QtGui.QIcon(pixmap)
        action = QAction(icon, "Add a graph", self.navToolbar)
        # self.navToolbar.addAction(action)
        action.triggered.connect(self.addGraph.emit)
        self.navToolbar.insertAction(self.navToolbar.actions()[0], action)

        # Delete Graph Action
        pixmap = QtGui.QPixmap(
            os.path.join(config.MOOSE_ICON_DIR, "delete_graph.png"))
        icon = QtGui.QIcon(pixmap)
        action = QAction(icon, "Delete this graph", self.navToolbar)
        action.triggered.connect(self.delete)
        self.navToolbar.insertAction(self.navToolbar.actions()[1], action)

        #Toggle Grid Action
        pixmap = QtGui.QPixmap(os.path.join(config.MOOSE_ICON_DIR, "grid.png"))
        icon = QtGui.QIcon(pixmap)
        action = QAction(icon, "Toggle Grid", self.navToolbar)
        action.triggered.connect(self.canvas.toggleGrid)
        self.navToolbar.insertAction(self.navToolbar.actions()[2], action)
        self.navToolbar.insertSeparator(self.navToolbar.actions()[3])

    @property
    def plotAll(self):
        return len(self.pathToLine) == 0

    def toggleLegend(self):
        if self.legend is not None:
            self.legend.set_visible(not self.legend.get_visible())
        self.canvas.draw()

    def getContextMenu(self):
        menu = QMenu()
        # closeAction      = menu.addAction("Delete")
        exportCsvAction = menu.addAction("Export to CSV")
        exportCsvAction.triggered.connect(self.saveAllCsv)
        toggleLegendAction = menu.addAction("Toggle legend")
        toggleLegendAction.triggered.connect(self.toggleLegend)
        self.removeSubmenu = menu.addMenu("Remove")
        # configureAction.triggered.connect(self.configure)
        # self.connect(,SIGNAL("triggered()"),
        #                 self,SLOT("slotShow500x500()"))
        # self.connect(action1,SIGNAL("triggered()"),
        #                 self,SLOT("slotShow100x100()"))

        return menu

    def deleteGraph(self):
        """ If there is only one graph in the view, please don't delete it """
        print("Deleting %s " % self.graph.path)
        moose.delete(self.graph.path)

    def delete(self, event):
        """FIXME: The last element should not be deleted """
        _logger.info("Deleting PlotWidget ")
        self.deleteGraph()
        self.close()
        self.widgetClosedSignal.emit(self)

    def configure(self, event):
        print("Displaying configure view!")
        self.plotView.getCentralWidget().show()

    @pyqtSlot(QtCore.QPoint)
    def contextMenuRequested(self, point):
        self.menu.exec_(self.mapToGlobal(point))

    def setModelRoot(self, path):
        self.modelRoot = path

    def setDataRoot(self, path):
        self.dataRoot = path
        #plotAllData()

    def genColorMap(self, tableObject):
        species = tableObject + '/info'
        colormap_file = open(
            os.path.join(config.settings[config.KEY_COLORMAP_DIR],
                         'rainbow2.pkl'), 'rb')
        self.colorMap = pickle.load(colormap_file)
        colormap_file.close()
        hexchars = "0123456789ABCDEF"
        color = 'white'
        #Genesis model exist the path and color will be set but not xml file so bypassing
        #print "here genColorMap ",moose.exists(species)
        if moose.exists(species):
            color = moose.element(species).getField('color')
            if ((not isinstance(color, (list, tuple)))):
                if color.isdigit():
                    tc = int(color)
                    tc = (tc * 2)
                    r, g, b = self.colorMap[tc]
                    color = "#" + hexchars[r / 16] + hexchars[
                        r % 16] + hexchars[g / 16] + hexchars[
                            g % 16] + hexchars[b / 16] + hexchars[b % 16]
            else:
                color = 'white'
        return color

    def removePlot(self, table):
        print(("removePlot =>", table))
        moose.delete(table)
        self.plotAllData()

    def makeRemovePlotAction(self, label, table):
        action = self.removeSubmenu.addAction(label)
        action.triggered.connect(lambda: self.removePlot(table))
        return action

    def plotAllData(self):
        """Plot data from existing tables"""
        self.axesRef.lines = []
        self.pathToLine.clear()
        self.removeSubmenu.clear()
        if self.legend is not None:
            self.legend.set_visible(False)
        path = self.model.path
        modelroot = self.model.path
        time = moose.Clock('/clock').currentTime
        tabList = []
        #for tabId in moose.wildcardFind('%s/##[TYPE=Table]' % (path)):
        #harsha: policy graphs will be under /model/modelName need to change in kkit
        #for tabId in moose.wildcardFind('%s/##[TYPE=Table]' % (modelroot)):

        plotTables = list(
            moose.wildcardFind(self.graph.path + '/##[TYPE=Table]'))
        plotTables.extend(
            moose.wildcardFind(self.graph.path + '/##[TYPE=Table2]'))
        if len(plotTables) > 0:
            for tabId in plotTables:
                tab = moose.Table(tabId)
                #print("Table =>", tab)
                line_list = []
                tableObject = tab.neighbors['requestOut']
                # Not a good way
                #tableObject.msgOut[0]
                if len(tableObject) > 0:

                    # This is the default case: we do not plot the same
                    # table twice. But in special cases we want to have
                    # multiple variations of the same table on different
                    # axes.
                    #
                    #Harsha: Adding color to graph for signalling model, check if given path has cubemesh or cylmesh

                    color = '#FFFFFF'
                    if moose.exists(tableObject[0].path + '/info'):
                        color = getColor(tableObject[0].path + '/info')
                        color = str(color[1].name()).upper()

                    lines = self.pathToLine[tab.path]
                    if len(lines) == 0:
                        #Harsha: pass color for plot if exist and not white else random color
                        #print "tab in plotAllData ",tab, tab.path,tab.name
                        field = tab.path.rpartition(".")[-1]
                        if field.endswith("[0]") or field.endswith("_0_"):
                            field = field[:-3]
                        # label = ( tableObject[0].path.partition(self.model.path + "/model[0]/")[-1]
                        #         + "."
                        #         + field
                        #         )
                        label = (tableObject[0].path.rpartition("/")[-1] +
                                 "." + field)
                        self.makeRemovePlotAction(label, tab)
                        if (color != '#FFFFFF'):
                            newLines = self.addTimeSeries(tab,
                                                          label=label,
                                                          color=color)
                        else:
                            newLines = self.addTimeSeries(tab, label=label)
                        self.pathToLine[tab.path].update(newLines)
                        for line in newLines:
                            self.lineToDataSource[line] = PlotDataSource(
                                x='/clock', y=tab.path, z='')
                    else:
                        for line in lines:
                            dataSrc = self.lineToDataSource[line]
                            xSrc = moose.element(dataSrc.x)
                            ySrc = moose.element(dataSrc.y)
                            if isinstance(xSrc, moose.Clock):
                                ts = np.linspace(0, time, len(tab.vector))
                            elif isinstance(xSrc, moose.Table):
                                ts = xSrc.vector.copy()
                            line.set_data(ts, tab.vector.copy())
                    tabList.append(tab)

            # if len(tabList) > 0:
        self.legend = self.canvas.callAxesFn(
            'legend',
            loc='upper right',
            prop={'size': 10}
            # , bbox_to_anchor=(1.0, 0.5)
            ,
            fancybox=True,
            shadow=False,
            ncol=1)
        if self.legend is not None:
            self.legend.draggable()
            self.legend.get_frame().set_alpha(0.5)
            self.legend.set_visible(True)

        self.canvas.draw()

        #     # leg = self.canvas.callAxesFn( 'legend'
        #     #                             , loc               ='upper right'
        #     #                             , prop              = {'size' : 10 }
        #     #                             # , bbox_to_anchor    = (0.5, -0.03)
        #     #                              , fancybox          = False
        #     #                             # , shadow            = True
        #     #                             , ncol              = 1
        #     #                             )
        #     # leg.draggable(False)
        #     # print(leg.get_window_extent())
        #             #leg = self.canvas.callAxesFn('legend')
        #             #leg = self.canvas.callAxesFn('legend',loc='upper left', fancybox=True, shadow=True)
        #             #global legend
        #             #legend =leg
        #     for legobj in leg.legendHandles:
        #         legobj.set_linewidth(5.0)
        #         legobj.set_picker(True)
        # else:
        #     print "returning as len tabId is zero ",tabId, " tableObject ",tableObject, " len ",len(tableObject)

    def togglePlot(self, event):
        #print "onclick",event1.artist.get_label()
        #harsha:To workout with double-event-registered on onclick event
        #http://stackoverflow.com/questions/16278358/double-event-registered-on-mouse-click-if-legend-is-outside-axes
        legline = event.artist
        for line in self.axesRef.lines:
            if line.get_label() == event.artist.get_label():
                vis = not line.get_visible()
                line.set_visible(vis)
                if vis:
                    legline.set_alpha(1.0)
                else:
                    legline.set_alpha(0.2)
                break
        self.canvas.draw()

    def addTimeSeries(self, table, *args, **kwargs):
        ts = np.linspace(0,
                         moose.Clock('/clock').currentTime, len(table.vector))
        return self.canvas.plot(ts, table.vector, *args, **kwargs)

    def addRasterPlot(self, eventtable, yoffset=0, *args, **kwargs):
        """Add raster plot of events in eventtable.

        yoffset - offset along Y-axis.
        """
        y = np.ones(len(eventtable.vector)) * yoffset
        return self.canvas.plot(eventtable.vector, y, '|')

    def updatePlots(self):
        for path, lines in list(self.pathToLine.items()):
            element = moose.element(path)
            if isinstance(element, moose.Table2):
                tab = moose.Table2(path)
            else:
                tab = moose.Table(path)
            data = tab.vector
            ts = np.linspace(0, moose.Clock('/clock').currentTime, len(data))
            for line in lines:
                line.set_data(ts, data)
        self.canvas.draw()

    def extendXAxes(self, xlim):
        for axes in list(self.canvas.axes.values()):
            # axes.autoscale(False, axis='x', tight=True)
            axes.set_xlim(right=xlim)
            axes.autoscale_view(tight=True, scalex=True, scaley=True)
        self.canvas.draw()

    def rescalePlots(self):
        """This is to rescale plots at the end of simulation.

        ideally we should set xlim from simtime.
        """
        for axes in list(self.canvas.axes.values()):
            axes.autoscale(True, tight=True)
            axes.relim()
            axes.autoscale_view(tight=True, scalex=True, scaley=True)
        self.canvas.draw()

    def saveCsv(self, line, directory):
        """Save selected plot data in CSV file"""
        src = self.lineToDataSource[line]
        xSrc = moose.element(src.x)
        ySrc = moose.element(src.y)
        y = ySrc.vector.copy()
        if isinstance(xSrc, moose.Clock):
            x = np.linspace(0, xSrc.currentTime, len(y))
        elif isinstance(xSrc, moose.Table):
            x = xSrc.vector.copy()
        nameVec = ySrc.neighbors['requestOut']
        name = moose.element(nameVec[0]).name
        filename = str(directory) + '/' + '%s.csv' % (name)
        np.savetxt(filename, np.vstack((x, y)).transpose())
        print('Saved data from %s and %s in %s' %
              (xSrc.path, ySrc.path, filename))

    def saveAllCsv(self):
        """Save data for all currently plotted lines"""
        #Harsha: Plots were saved in GUI folder instead provided QFileDialog box to save to
        #user choose
        fileDialog2 = QFileDialog(self)
        fileDialog2.setFileMode(QFileDialog.Directory)
        fileDialog2.setWindowTitle('Select Directory to save plots')
        fileDialog2.setOptions(QFileDialog.ShowDirsOnly)
        fileDialog2.setLabelText(QFileDialog.Accept, self.tr("Save"))
        targetPanel = QFrame(fileDialog2)
        targetPanel.setLayout(QVBoxLayout())
        layout = fileDialog2.layout()
        layout.addWidget(targetPanel)
        if fileDialog2.exec_():
            directory = fileDialog2.directory().path()
            for line in list(self.lineToDataSource.keys()):
                self.saveCsv(line, directory)

    def getMenus(self):
        if not hasattr(self, '_menus'):
            self._menus = []
            self.plotAllAction = QAction('Plot all data', self)
            self.plotAllAction.triggered.connect(self.plotAllData)
            self.plotMenu = QMenu('Plot')
            self.plotMenu.addAction(self.plotAllAction)
            self.saveAllCsvAction = QAction('Save all data in CSV files', self)
            self.saveAllCsvAction.triggered.connect(self.saveAllCsv)
            self.plotMenu.addAction(self.saveAllCsvAction)
            self._menus.append(self.plotMenu)
        return self._menus