Source code for steps.API_1.visual.Plotting

####################################################################################
#
#    STEPS - STochastic Engine for Pathway Simulation
#    Copyright (C) 2007-2023 Okinawa Institute of Science and Technology, Japan.
#    Copyright (C) 2003-2006 University of Antwerp, Belgium.
#    
#    See the file AUTHORS for details.
#    This file is part of STEPS.
#    
#    STEPS is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License version 3,
#    as published by the Free Software Foundation.
#    
#    STEPS is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#    GNU General Public License for more details.
#    
#    You should have received a copy of the GNU General Public License
#    along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#################################################################################   
###

import pyqtgraph as pg
from pyqtgraph.widgets.GraphicsLayoutWidget import GraphicsLayoutWidget
import numpy as np
import steps.API_1.geom as sgeom

[docs]class PlotDisplay(GraphicsLayoutWidget): """ Visualization plot display. Parameters: * title Title of the display * size Size of the display """ def __init__(self, title=None, size=(800, 600)): """ Constructor. """ GraphicsLayoutWidget.__init__(self, title=title, size=size) self.updater = {} self.show()
[docs] def addCompSpecPlot(self, title, sim, comp_id, spec_id, data_size = 1000, x_range = None, y_range = None, measure = "count", **kwargs): """ Add plot to display the amount changes of species in a compartment. Parameters: * title Title of the plot * sim STEPS solver * comp_id ID of the compartment * spec_id ID of the species * data_size Size of the data history * x_range Range of X axis * y_range Range of y axis * measure Measure type * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = CompSpecUpdater(plot, sim, comp_id, spec_id, data_size, x_range, y_range, measure, **kwargs) self.updater[title] = updater return plot
[docs] def addTetsSpecPlot(self, title, sim, tets, spec_id, data_size = 1000, x_range = None, y_range = None, measure = "count", **kwargs): """ Add plot to display the amount changes of species in a list of tetrahedrons. Parameters: * title Title of the plot * sim STEPS solver * tets List of tetrahedron indices * spec_id ID of the species * data_size Size of the data history * x_range Range of X axis * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = TetsSpecUpdater(plot, sim, tets, spec_id, data_size, x_range, y_range, measure, **kwargs) self.updater[title] = updater return plot
[docs] def addPatchSpecPlot(self, title, sim, patch_id, spec_id, data_size = 1000, x_range = None, y_range = None, **kwargs): """ Add plot to display the amount changes of species in a patch. Parameters: * title Title of the plot * sim STEPS solver * patch_id ID of the patch * spec_id ID of the species * data_size Size of the data history * x_range Range of X axis * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = PatchSpecUpdater(plot, sim, patch_id, spec_id, data_size, x_range, y_range, **kwargs) self.updater[title] = updater return plot
[docs] def addTrisSpecPlot(self, title, sim, tris, spec_id, data_size = 1000, x_range = None, y_range = None, **kwargs): """ Add plot to display the amount changes of species in a list of triangles. Parameters: * title Title of the plot * sim STEPS solver * tris List of triangle indices * spec_id ID of the species * data_size Size of the data history * x_range Range of X axis * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = TrisSpecUpdater(plot, sim, tris, spec_id, data_size, x_range, y_range, **kwargs) self.updater[title] = updater return plot
[docs] def addCompSumSpecsPlot(self, title, sim, comp_id, spec_ids, data_size = 1000, x_range = None, y_range = None, **kwargs): """ Add plot to display the sum-up amount changes of species in a compartment. Parameters: * title Title of the plot * sim STEPS solver * comp_id ID of the compartment * spec_id ID of the species * data_size Size of the data history * x_range Range of X axis * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = CompSumSpecsUpdater(plot, sim, comp_id, spec_ids, data_size, x_range, y_range, **kwargs) self.updater[title] = updater return plot
[docs] def addPatchSumSpecsPlot(self, title, sim, patch_id, spec_ids, data_size = 1000, x_range = None, y_range = None, **kwargs): """ Add plot to display the sum-up amount changes of species in a patch. Parameters: * title Title of the plot * sim STEPS solver * patch_id ID of the patch * spec_id ID of the species * data_size Size of the data history * x_range Range of X axis * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = PatchSumSpecsUpdater(plot, sim, patch_id, spec_ids, data_size, x_range, y_range, **kwargs) self.updater[title] = updater return plot
[docs] def addCompSpecDist(self, title, mesh, sim, comp_id, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): """ Add plot to display the distribution of species in a compartment. Parameters: * title Title of the plot * sim STEPS solver * comp_id ID of the compartment * spec_id ID of the species * axis Spatial direction of the distribution * nbins Number of bins for the data * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = CompSpecDistUpdater(plot, mesh, sim, comp_id, spec_id, axis, nbins, y_range, **kwargs) self.updater[title] = updater return plot
[docs] def addPatchSpecDist(self, title, mesh, sim, patch_id, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): """ Add plot to display the distribution of species in a patch. Parameters: * title Title of the plot * sim STEPS solver * mesh STEPS mesh * patch_id ID of the patch * spec_id ID of the species * axis Spatial direction of the distribution * nbins Number of bins for the data * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = PatchSpecDistUpdater(plot, mesh, sim, patch_id, spec_id, axis, nbins, y_range, **kwargs) self.updater[title] = updater return plot
[docs] def addTetsSpecDist(self, title, mesh, sim, tets, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): """ Add plot to display the distribution of species in a list of tetrahedrons. Parameters: * title Title of the plot * sim STEPS solver * mesh STEPS mesh * tets List of tetrahedron indices * spec_id ID of the species * axis Spatial direction of the distribution * nbins Number of bins for the data * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = TetsSpecDistUpdater(plot, mesh, sim, tets, spec_id, axis, nbins, y_range, **kwargs) self.updater[title] = updater return plot
[docs] def addTrisSpecDist(self, title, mesh, sim, tris, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): """ Add plot to display the distribution of species in a list of triangles. Parameters: * title Title of the plot * sim STEPS solver * mesh STEPS mesh * tris List of triangle indices * spec_id ID of the species * axis Spatial direction of the distribution * nbins Number of bins for the data * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) updater = TrisSpecDistUpdater(plot, mesh, sim, tris, spec_id, axis, nbins, y_range, **kwargs) self.updater[title] = updater return plot
[docs] def addROISpecDist(self, title, mesh, sim, roi_id, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): """ Add plot to display the distribution of species in a Region of Interest. Parameters: * title Title of the plot * sim STEPS solver * mesh STEPS mesh * roi_id ID of the Region of Interest * spec_id ID of the species * axis Spatial direction of the distribution * nbins Number of bins for the data * y_range Range of y axis * \*\*kwargs Other keywords that are supported by pygraph.GraphicsWindow class Return: pyqtgraph.PlotItem object """ if title in self.updater: raise NameError('A Plot with name ' + title + " exists.") plot = self.addPlot(title = title) type = mesh.getROIType(roi_id) data = mesh.getROIData(roi_id) if type == sgeom.ELEM_TRI: self.updater[title] = TrisSpecDistUpdater(plot, mesh, sim, data, spec_id, axis, nbins, y_range, **kwargs) elif type == sgeom.ELEM_TET: self.updater[title] = TetsSpecDistUpdater(plot, mesh, sim, data, spec_id, axis, nbins, y_range, **kwargs) return plot
def refresh(self): for p in self.updater.values(): p.update() def reset(self): for p in self.updater.values(): p.reset()
class CompSpecUpdater: def __init__(self, plot, sim, comp_id, spec_id, data_size, x_range = None, y_range = None, measure = "count", **kwargs): self.plot = plot plot.setLabel('bottom', 'Time', units='s') self.sim = sim self.comp_id = comp_id self.spec_id = spec_id self.measure = measure self.data_size = data_size self.time = [sim.getTime()] value = 0 if self.measure == "count": value = sim.getCompSpecCount(self.comp_id, self.spec_id) elif self.measure == "conc": value = sim.getCompSpecConc(self.comp_id, self.spec_id) self.data = [value] self.curve = plot.plot(self.time, self.data, **kwargs) if x_range != None: self.plot.setXRange(x_range[0], x_range[1]) if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) def update(self): self.time.append(self.sim.getTime()) value = 0 if self.measure == "count": value = self.sim.getCompSpecCount(self.comp_id, self.spec_id) elif self.measure == "conc": value = self.sim.getCompSpecConc(self.comp_id, self.spec_id) self.data.append(value) if len(self.time) >self.data_size: self.time.pop(0) self.data.pop(0) self.curve.setData(self.time, self.data) def reset(self): self.time = [self.sim.getTime()] value = 0 if self.measure == "count": value = self.sim.getCompSpecCount(self.comp_id, self.spec_id) elif self.measure == "conc": value = self.sim.getCompSpecConc(self.comp_id, self.spec_id) self.data = [value] self.curve.setData(self.time, self.data) class TetsSpecUpdater: def __init__(self, plot, sim, tets, spec_id, data_size, x_range = None, y_range = None, measure = "count", **kwargs): self.plot = plot plot.setLabel('bottom', 'Time', units='s') self.sim = sim self.tets = tets self.spec_id = spec_id self.measure = measure self.data_size = data_size self.time = [sim.getTime()] value = 0 for t in self.tets: value += sim.getTetSpecCount(t, self.spec_id) self.data = [value] self.curve = plot.plot(self.time, self.data, **kwargs) if x_range != None: self.plot.setXRange(x_range[0], x_range[1]) if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) def update(self): self.time.append(self.sim.getTime()) value = 0 for t in self.tets: value += self.sim.getTetSpecCount(t, self.spec_id) self.data.append(value) if len(self.time) >self.data_size: self.time.pop(0) self.data.pop(0) self.curve.setData(self.time, self.data) def reset(self): self.time = [self.sim.getTime()] value = 0 for t in self.tets: value += self.sim.getTetSpecCount(t, self.spec_id) self.data = [value] self.curve.setData(self.time, self.data) class PatchSpecUpdater: def __init__(self, plot, sim, patch_id, spec_id, data_size, x_range = None, y_range = None, **kwargs): self.plot = plot plot.setLabel('bottom', 'Time', units='s') self.sim = sim self.patch_id = patch_id self.spec_id = spec_id self.data_size = data_size self.time = [sim.getTime()] self.data = [sim.getPatchSpecCount(patch_id, spec_id)] self.curve = plot.plot(self.time, self.data, **kwargs) if x_range != None: self.plot.setXRange(x_range[0], x_range[1]) if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) def update(self): self.time.append(self.sim.getTime()) self.data.append(self.sim.getPatchSpecCount(self.patch_id, self.spec_id)) if len(self.time) >self.data_size: self.time.pop(0) self.data.pop(0) self.curve.setData(self.time, self.data) def reset(self): self.time = [self.sim.getTime()] self.data = [self.sim.getPatchSpecCount(self.patch_id, self.spec_id)] self.curve.setData(self.time, self.data) class TrisSpecUpdater: def __init__(self, plot, sim, tris, spec_id, data_size, x_range = None, y_range = None, **kwargs): self.plot = plot plot.setLabel('bottom', 'Time', units='s') self.sim = sim self.tris = tris self.spec_id = spec_id self.data_size = data_size self.time = [sim.getTime()] value = 0 for t in self.tris: value += sim.getTriSpecCount(t, self.spec_id) self.data = [value] self.curve = plot.plot(self.time, self.data, **kwargs) if x_range != None: self.plot.setXRange(x_range[0], x_range[1]) if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) def update(self): self.time.append(self.sim.getTime()) value = 0 for t in self.tris: value += self.sim.getTriSpecCount(t, self.spec_id) self.data.append(value) if len(self.time) >self.data_size: self.time.pop(0) self.data.pop(0) self.curve.setData(self.time, self.data) def reset(self): self.time = [self.sim.getTime()] value = 0 for t in self.tris: value += self.sim.getTriSpecCount(t, self.spec_id) self.data = [value] self.curve.setData(self.time, self.data) class CompSumSpecsUpdater: def __init__(self, plot, sim, comp_id, spec_ids, data_size, x_range = None, y_range = None, **kwargs): self.plot = plot plot.setLabel('bottom', 'Time', units='s') self.sim = sim self.comp_id = comp_id self.spec_ids = spec_ids self.data_size = data_size self.time = [sim.getTime()] sum = 0 for s in self.spec_ids: sum += sim.getCompSpecCount(comp_id, s) self.data = [sum] self.curve = plot.plot(self.time, self.data, **kwargs) if x_range != None: self.plot.setXRange(x_range[0], x_range[1]) if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) def update(self): self.time.append(self.sim.getTime()) sum = 0 for s in self.spec_ids: sum += self.sim.getCompSpecCount(self.comp_id, s) self.data.append(sum) if len(self.time) >self.data_size: self.time.pop(0) self.data.pop(0) self.curve.setData(self.time, self.data) def reset(self): self.time = [self.sim.getTime()] sum = 0 for s in self.spec_ids: sum += self.sim.getCompSpecCount(self.comp_id, s) self.data = [sum] self.curve.setData(self.time, self.data) class PatchSumSpecsUpdater: def __init__(self, plot, sim, patch_id, spec_ids, data_size, x_range = None, y_range = None, **kwargs): self.plot = plot plot.setLabel('bottom', 'Time', units='s') self.sim = sim self.patch_id = patch_id self.spec_ids = spec_ids self.data_size = data_size self.time = [sim.getTime()] sum = 0 for s in self.spec_ids: sum += sim.getPatchSpecCount(patch_id, s) self.data = [sum] self.curve = plot.plot(self.time, self.data, **kwargs) if x_range != None: self.plot.setXRange(x_range[0], x_range[1]) if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) def update(self): self.time.append(self.sim.getTime()) sum = 0 for s in self.spec_ids: sum += self.sim.getPatchSpecCount(self.patch_id, s) self.data.append(sum) if len(self.time) >self.data_size: self.time.pop(0) self.data.pop(0) self.curve.setData(self.time, self.data) def reset(self): self.time = [self.sim.getTime()] sum = 0 for s in self.spec_ids: sum += self.sim.getPatchSpecCount(self.patch_id, s) self.data = [sum] self.curve.setData(self.time, self.data) class CompSpecDistUpdater: def __init__(self, plot, mesh, sim, comp_id, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): self.plot = plot self.mesh = mesh self.sim = sim self.comp_id = comp_id self.spec_id = spec_id self.nbins = nbins if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) tmcomp = sgeom.castToTmComp(mesh.getComp(comp_id)) self.tets = tmcomp.getAllTetIndices() self.axis = 0 if axis == "x": self.axis = 0 plot.setLabel('bottom', 'X Coordinate', units='m') elif axis == "y": self.axis = 1 plot.setLabel('bottom', 'Y Coordinate', units='m') elif axis == "z": self.axis = 2 plot.setLabel('bottom', 'Z Coordinate', units='m') self.bound_max = tmcomp.getBoundMax()[self.axis] self.bound_min = tmcomp.getBoundMin()[self.axis] bins = np.linspace(self.bound_min, self.bound_max, nbins + 1) centers = [mesh.getTetBarycenter(t)[self.axis] for t in self.tets] self.belongs = np.digitize(centers, bins) self.bin_data = [] for b in range(nbins): self.bin_data.append(bins[b]) self.bin_data.append(bins[b + 1]) data = np.zeros(nbins + 1) for t in range(len(self.tets)): data[self.belongs[t] - 1] += sim.getTetSpecCount(self.tets[t], self.spec_id) y_data = [] for b in range(nbins): y_data.append(data[b]) y_data.append(data[b]) self.curve = plot.plot(self.bin_data, y_data, fillLevel = -0.3, **kwargs) def update(self): data = np.zeros(self.nbins + 1) for t in range(len(self.tets)): data[self.belongs[t] - 1] += self.sim.getTetSpecCount(self.tets[t], self.spec_id) y_data = [] for b in range(self.nbins): y_data.append(data[b]) y_data.append(data[b]) self.curve.setData(self.bin_data, y_data) def reset(self): self.update() class PatchSpecDistUpdater: def __init__(self, plot, mesh, sim, patch_id, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): self.plot = plot self.mesh = mesh self.sim = sim self.patch_id = patch_id self.spec_id = spec_id self.nbins = nbins if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) tmpatch = sgeom.castToTmPatch(mesh.getPatch(patch_id)) self.tris = tmpatch.getAllTriIndices() self.axis = 0 if axis == "x": self.axis = 0 plot.setLabel('bottom', 'X Coordinate', units='m') elif axis == "y": self.axis = 1 plot.setLabel('bottom', 'Y Coordinate', units='m') elif axis == "z": self.axis = 2 plot.setLabel('bottom', 'Z Coordinate', units='m') self.bound_max = tmpatch.getBoundMax()[self.axis] self.bound_min = tmpatch.getBoundMin()[self.axis] bins = np.linspace(self.bound_min, self.bound_max, nbins + 1) centers = [mesh.getTriBarycenter(t)[self.axis] for t in self.tris] self.belongs = np.digitize(centers, bins) self.bin_data = [] for b in range(nbins): self.bin_data.append(bins[b]) self.bin_data.append(bins[b + 1]) data = np.zeros(nbins + 1) for t in range(len(self.tris)): data[self.belongs[t] - 1] += sim.getTriSpecCount(self.tris[t], self.spec_id) y_data = [] for b in range(nbins): y_data.append(data[b]) y_data.append(data[b]) self.curve = plot.plot(self.bin_data, y_data, fillLevel = -0.3, **kwargs) def update(self): data = np.zeros(self.nbins + 1) for t in range(len(self.tris)): data[self.belongs[t] - 1] += self.sim.getTriSpecCount(self.tris[t], self.spec_id) y_data = [] for b in range(self.nbins): y_data.append(data[b]) y_data.append(data[b]) self.curve.setData(self.bin_data, y_data) def reset(self): self.update() class TetsSpecDistUpdater: def __init__(self, plot, mesh, sim, tets, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): self.plot = plot self.mesh = mesh self.sim = sim self.spec_id = spec_id self.nbins = nbins if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) self.tets = tets self.axis = 0 if axis == "x": self.axis = 0 plot.setLabel('bottom', 'X Coordinate', units='m') elif axis == "y": self.axis = 1 plot.setLabel('bottom', 'Y Coordinate', units='m') elif axis == "z": self.axis = 2 plot.setLabel('bottom', 'Z Coordinate', units='m') self.bound_max = -float("Inf") self.bound_min = float("Inf") centers = [] for t in tets: verts = mesh.getTet(t) for v in verts: coordinate = mesh.getVertex(v)[self.axis] if coordinate > self.bound_max: self.bound_max = coordinate if coordinate < self.bound_min: self.bound_min = coordinate centers.append(mesh.getTetBarycenter(t)[self.axis]) bins = np.linspace(self.bound_min, self.bound_max, nbins + 1) self.belongs = np.digitize(centers, bins) self.bin_data = [] for b in range(nbins): self.bin_data.append(bins[b]) self.bin_data.append(bins[b + 1]) data = np.zeros(nbins + 1) for t in range(len(self.tets)): data[self.belongs[t] - 1] += sim.getTetSpecCount(self.tets[t], self.spec_id) y_data = [] for b in range(nbins): y_data.append(data[b]) y_data.append(data[b]) self.curve = plot.plot(self.bin_data, y_data, fillLevel = -0.3, **kwargs) def update(self): data = np.zeros(self.nbins + 1) for t in range(len(self.tets)): data[self.belongs[t] - 1] += self.sim.getTetSpecCount(self.tets[t], self.spec_id) y_data = [] for b in range(self.nbins): y_data.append(data[b]) y_data.append(data[b]) self.curve.setData(self.bin_data, y_data) def reset(self): self.update() class TrisSpecDistUpdater: def __init__(self, plot, mesh, sim, tris, spec_id, axis = "x", nbins = 20, y_range = None, **kwargs): self.plot = plot self.mesh = mesh self.sim = sim self.spec_id = spec_id self.nbins = nbins if y_range != None: self.plot.setYRange(y_range[0], y_range[1]) self.tris = tris self.axis = 0 if axis == "x": self.axis = 0 plot.setLabel('bottom', 'X Coordinate', units='m') elif axis == "y": self.axis = 1 plot.setLabel('bottom', 'Y Coordinate', units='m') elif axis == "z": self.axis = 2 plot.setLabel('bottom', 'Z Coordinate', units='m') self.bound_max = -float("Inf") self.bound_min = float("Inf") centers = [] for t in tris: verts = mesh.getTri(t) for v in verts: coordinate = mesh.getVertex(v)[self.axis] if coordinate > self.bound_max: self.bound_max = coordinate if coordinate < self.bound_min: self.bound_min = coordinate centers.append(mesh.getTriBarycenter(t)[self.axis]) bins = np.linspace(self.bound_min, self.bound_max, nbins + 1) self.belongs = np.digitize(centers, bins) self.bin_data = [] for b in range(nbins): self.bin_data.append(bins[b]) self.bin_data.append(bins[b + 1]) data = np.zeros(nbins + 1) for t in range(len(self.tets)): data[self.belongs[t] - 1] += sim.getTriSpecCount(self.tris[t], self.spec_id) y_data = [] for b in range(nbins): y_data.append(data[b]) y_data.append(data[b]) self.curve = plot.plot(self.bin_data, y_data, fillLevel = -0.3, **kwargs) def update(self): data = np.zeros(self.nbins + 1) for t in range(len(self.tris)): data[self.belongs[t] - 1] += self.sim.getTriSpecCount(self.tris[t], self.spec_id) y_data = [] for b in range(self.nbins): y_data.append(data[b]) y_data.append(data[b]) self.curve.setData(self.bin_data, y_data) def reset(self): self.update()