def _buildKrigingAlgo(self, inputSample, outputSample): """ Build the functional chaos algorithm without running it. """ if self._basis is None: # create linear basis only for the defect parameter (1st parameter), # constant otherwise input = ['x' + str(i) for i in range(self._dim)] functions = [] # constant functions.append(ot.SymbolicFunction(input, ['1'])) # linear for the first parameter only functions.append(ot.SymbolicFunction(input, [input[0]])) self._basis = ot.Basis(functions) if self._covarianceModel is None: # anisotropic squared exponential covariance model self._covarianceModel = ot.SquaredExponential([1] * self._dim) # normalization mean = inputSample.computeMean() try: stddev = inputSample.computeStandardDeviation() except AttributeError: stddev = inputSample.computeStandardDeviationPerComponent() linear = ot.SquareMatrix(self._dim) for j in range(self._dim): linear[j, j] = 1.0 / stddev[j] if abs(stddev[j]) > 1e-12 else 1.0 zero = [0.0] * self._dim transformation = ot.LinearFunction(mean, zero, linear) algoKriging = ot.KrigingAlgorithm(transformation(inputSample), outputSample, self._covarianceModel, self._basis) return algoKriging, transformation
def test_two_outputs(): f = ot.SymbolicFunction(['x'], ['x * sin(x)', 'x * cos(x)']) sampleX = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0], [7.0], [8.0]] sampleY = f(sampleX) basis = ot.Basis([ ot.SymbolicFunction(['x'], ['x']), ot.SymbolicFunction(['x'], ['x^2']) ]) covarianceModel = ot.SquaredExponential([1.0]) covarianceModel.setActiveParameter([]) covarianceModel = ot.TensorizedCovarianceModel([covarianceModel] * 2) algo = ot.KrigingAlgorithm(sampleX, sampleY, covarianceModel, basis) algo.run() result = algo.getResult() mm = result.getMetaModel() assert mm.getOutputDimension() == 2, "wrong output dim" ott.assert_almost_equal(mm(sampleX), sampleY) # Check the conditional covariance reference_covariance = ot.Matrix([[4.4527, 0.0, 8.34404, 0.0], [0.0, 2.8883, 0.0, 5.41246], [8.34404, 0.0, 15.7824, 0.0], [0.0, 5.41246, 0.0, 10.2375]]) ott.assert_almost_equal( result([[9.5], [10.0]]).getCovariance() - reference_covariance, ot.Matrix(4, 4), 0.0, 2e-2)
def test_two_outputs(): f = ot.SymbolicFunction(['x'], ['x * sin(x)', 'x * cos(x)']) sampleX = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0], [7.0], [8.0]] sampleY = f(sampleX) basis = ot.Basis([ot.SymbolicFunction(['x'], ['x']), ot.SymbolicFunction(['x'], ['x^2'])]) covarianceModel = ot.SquaredExponential([1.0]) covarianceModel.setActiveParameter([]) algo = ot.KrigingAlgorithm(sampleX, sampleY, covarianceModel, basis) algo.run() result = algo.getResult() mm = result.getMetaModel() assert mm.getOutputDimension() == 2, "wrong output dim" ott.assert_almost_equal(mm(sampleX), sampleY)
def fit(self, X, y, **fit_params): """Fit Kriging regression model. Parameters ---------- X : array-like, shape = (n_samples, n_features) Training data. y : array-like, shape = (n_samples, [n_output_dims]) Target values. Returns ------- self : returns an instance of self. """ if len(X) == 0: raise ValueError( "Can not perform a kriging algorithm with empty sample") # check data type is accurate if (len(np.shape(X)) != 2): raise ValueError("X has incorrect shape.") input_dimension = len(X[1]) if len(np.shape( y)) == 1: # For sklearn.multioutput.MultiOutputRegressor y = np.expand_dims(y, axis=1) if len(np.shape(y)) != 2: raise ValueError("y has incorrect shape.") if type(self.kernel) is str: covarianceModel = eval('ot.' + self.kernel + "(" + str(input_dimension) + ")") else: covarianceModel = ot.CovarianceModel(self.kernel) if type(self.basis) is str: basisCollection = eval('ot.' + self.basis + "BasisFactory(" + str(input_dimension) + ").build()") else: basisCollection = ot.Basis(self.basis) ot.ResourceMap.SetAsString("KrigingAlgorithm-LinearAlgebra", str(self.linalg_meth).upper()) algo = ot.KrigingAlgorithm(X, y, covarianceModel, basisCollection) if self.n_iter_opt: opt_algo = algo.getOptimizationAlgorithm() opt_algo.setMaximumIterationNumber(self.n_iter_opt) algo.setOptimizationAlgorithm(opt_algo) else: algo.setOptimizeParameters(False) algo.run() self.result_ = algo.getResult() return self
def setBasis(self, basis): """ Accessor to the kriging basis. Parameters ---------- basis : :py:class:`openturns.Basis` The basis used as trend in the kriging model. """ try: ot.Basis(basis) except NotImplementedError: raise Exception('The given parameter is not a Basis.') self._basis = basis
def set_mean(self, mean): ''' This function constructs the mean function takes the following argument: -> mean_type ''' if mean.mean_type == 'Linear': self.mean_function = ot.LinearBasisFactory(self.input_dim).build() elif mean.mean_type == 'Constant': self.mean_function = ot.ConstantBasisFactory( self.input_dim).build() elif mean.mean_type == 'Quadratic': self.mean_function = ot.QuadraticBasisFactory( self.input_dim).build() elif mean.mean_type == 'Zero': self.mean_function = ot.Basis() else: self.mean_function = "This library does not support the specified mean function"
def _buildKrigingAlgo(self, inputSample, outputSample): """ Build the functional chaos algorithm without running it. """ if self._basis is None: # create linear basis only for the defect parameter (1st parameter), # constant otherwise input = ['x' + str(i) for i in range(self._dim)] functions = [] # constant functions.append(ot.NumericalMathFunction(input, ['y'], ['1'])) # linear for the first parameter only functions.append(ot.NumericalMathFunction(input, ['y'], [input[0]])) self._basis = ot.Basis(functions) if self._covarianceModel is None: # anisotropic squared exponential covariance model covColl = ot.CovarianceModelCollection(self._dim) for i in range(self._dim): if LooseVersion(ot.__version__) == '1.6': covColl[i] = ot.SquaredExponential(1, 1.) elif LooseVersion(ot.__version__) > '1.6': covColl[i] = ot.SquaredExponential([1], [1.]) self._covarianceModel = ot.ProductCovarianceModel(covColl) if LooseVersion(ot.__version__) == "1.9": algoKriging = ot.KrigingAlgorithm(inputSample, outputSample, self._covarianceModel, self._basis) else: algoKriging = ot.KrigingAlgorithm(inputSample, outputSample, self._basis, self._covarianceModel, True) algoKriging.run() return algoKriging
import openturns as ot from openturns.viewer import View f = ot.SymbolicFunction(['x'], ['x + x * sin(x)']) inputSample = ot.Sample([[1.0], [3.0], [5.0], [6.0], [7.0], [8.0]]) outputSample = f(inputSample) f1 = ot.SymbolicFunction(['x'], ['sin(x)']) f2 = ot.SymbolicFunction(['x'], ['x']) f3 = ot.SymbolicFunction(['x'], ['cos(x)']) basis = ot.Basis([f1, f2, f3]) covarianceModel = ot.SquaredExponential([1.0]) covarianceModel.setActiveParameter([]) algo = ot.GeneralLinearModelAlgorithm(inputSample, outputSample, covarianceModel, basis) algo.run() result = algo.getResult() metamodel = result.getMetaModel() graph = f.draw(0.0, 10.0) graph.add(metamodel.draw(0.0, 10.0)) graph.add(ot.Cloud(inputSample, outputSample)) graph.setColors(['blue', 'red', 'black']) graph.setLegends(['model', 'meta model', 'sample']) graph.setLegendPosition('topleft') graph.setTitle('y(x)=x + x * sin(x)') View(graph, figure_kw={'figsize': (8, 4)})
# Create a trend fTrend = ot.SymbolicFunction(["t"], ["1+2*t+t^2"]) fTemp = ot.TrendTransform(fTrend, myGrid) # Add the trend to the process and get a field myYProcess = ot.CompositeProcess(fTemp, myXProcess) myYField = myYProcess.getRealization() # Create a TrendFactory myBasisSequenceFactory = ot.LARS() myFittingAlgorithm = ot.KFold() func1 = ot.SymbolicFunction(["t"], ["1"]) func2 = ot.SymbolicFunction(["t"], ["t"]) func3 = ot.SymbolicFunction(["t"], ["t^2"]) myBasis = ot.Basis([func1, func2, func3]) myTrendFactory = ot.TrendFactory(myBasisSequenceFactory, myFittingAlgorithm) # Estimate the trend myTrendTransform = myTrendFactory.build(myYField, myBasis) graph = myTrendTransform.getTrendFunction().draw(0.0, 10.0) graph.add(fTrend.draw(0.0, 10.0)) graph.add(ot.Cloud(myYField.getMesh().getVertices(), myYField.getValues())) graph.setColors(['red', 'blue', 'black']) graph.setLegends(['estimated trend', 'real trend', 'sample']) graph.setLegendPosition('topleft') graph.setYTitle('values') graph.setTitle("Trend estimation from a field")
polyColl = [univariateFactory]*dimension # %% enumerateFunction = ot.LinearEnumerateFunction(dimension) productBasis = ot.OrthogonalProductPolynomialFactory(polyColl, enumerateFunction) # %% functions = [] numberOfTrendCoefficients = 12 for i in range(numberOfTrendCoefficients): multivariatepolynomial = productBasis.build(i) print(multivariatepolynomial) functions.append(multivariatepolynomial) # %% basis = ot.Basis(functions) # %% # Create the metamodel # -------------------- # %% # In order to create the kriging metamodel, we first select a constant trend with the `ConstantBasisFactory` class. Then we use a squared exponential covariance model. Finally, we use the `KrigingAlgorithm` class to create the kriging metamodel, taking the training sample, the covariance model and the trend basis as input arguments. # %% covarianceModel = ot.SquaredExponential([1.]*dimension, [1.0]) # %% algo = ot.KrigingAlgorithm(X_train, Y_train, covarianceModel, basis) algo.run() result = algo.getResult()
class pyf2p(ot.OpenTURNSPythonFieldToPointFunction): def __init__(self, mesh): super(pyf2p, self).__init__(mesh, in_dim, out_dim) self.setInputDescription(["x1", "x2", "x3", "x4"]) self.setOutputDescription(['g']) def _exec(self, X): Xs = ot.Sample(X) x1, x2, x3, x4 = Xs.computeMean() y = x1 + x2 + x3 - x4 + x1 * x2 - x3 * x4 - 0.1 * x1 * x2 * x3 return [y] f = ot.FieldToPointFunction(pyf2p(tg)) # First process: elementary process based on a bivariate random vector f1 = ot.SymbolicFunction(['t'], ['sin(t)']) f2 = ot.SymbolicFunction(['t'], ['cos(t)^2']) myBasis = ot.Basis([f1, f2]) coefDis = ot.Normal([1.0] * 2, [0.6] * 2, ot.CorrelationMatrix(2)) p1 = ot.FunctionalBasisProcess(coefDis, myBasis, tg) # Second process: smooth Gaussian process p2 = ot.GaussianProcess(ot.SquaredExponential([1.0], [T / 4.0]), tg) # Third process: elementary process based on a bivariate random vector randomParameters = ot.ComposedDistribution([ot.Uniform(), ot.Normal()]) p3 = ot.FunctionalBasisProcess(randomParameters, ot.Basis([ot.SymbolicFunction(["t"], ["1", "0"]), ot.SymbolicFunction(["t"], ["0", "1"])])) X = ot.AggregatedProcess([p1, p2, p3]) X.setMesh(tg) N = 1000 x = X.getSample(N)
ftest = summary[9][0] # openturns like X = ot.Sample(len(pop15), 0) P = ot.Sample.BuildFromPoint(pop15) X.stack(P) P = ot.Sample.BuildFromPoint(pop75) X.stack(P) X.setDescription(["pop15", "pop75"]) Y = ot.Sample.BuildFromPoint(sr) # Model with pop15 + pop75 without intercept # We do not run mode with pop15 only for the moment f = ot.SymbolicFunction(["pop15", "pop75"], ["pop15"]) g = ot.SymbolicFunction(["pop15", "pop75"], ["pop75"]) h = ot.SymbolicFunction(["pop15", "pop75"], ["1"]) basis = ot.Basis([f, g]) model = ot.LinearModelAlgorithm(X, basis, Y) model.run() result = model.getResult() analysis = ot.LinearModelAnalysis(result) np.testing.assert_almost_equal(result.getRSquared(), r2, 14) np.testing.assert_almost_equal(result.getAdjustedRSquared(), ar2, 14) np.testing.assert_almost_equal(analysis.getFisherScore(), ftest, 14) #--------------------------------------------------------------------- # Model 2 : 2 param + intercepts formula = Formula('sr ~ pop75 + pop15') fit = stats.lm(formula) summary = stats.summary_lm(fit)
#! /usr/bin/env python from __future__ import print_function import openturns as ot from math import * ot.TESTPREAMBLE() try: basis = ot.Basis() print('basis =', basis) basisSize = 3 phis = [] for j in range(basisSize): phis.append(ot.SymbolicFunction(['x'], ['x^' + str(j + 1)])) basis = ot.Basis(phis) print('basis =', basis) print(basis.getSize()) print(basis.getSubBasis([1, 2])) print(basis.isFinite()) print(basis.isOrthogonal()) # print(basis[1]) # print(basis[0:2]) # basis[1] = ot.Function(['x'], ['z'], ['x^42']) # print('basis =', basis) # basis[0:2] = basis[1:3] # print('basis =', basis)
self.setInputDescription(["x1", "x2", "x3", "x4"]) self.setOutputDescription(['g']) def _exec(self, X): Xs = ot.Sample(X) x1, x2, x3, x4 = Xs.computeMean() y = x1 + x2 + x3 - x4 + x1 * x2 - x3 * x4 - 0.1 * x1 * x2 * x3 return [y] f = ot.FieldToPointFunction(pyf2p(tg)) # First process: elementary process based on a bivariate random vector f1 = ot.SymbolicFunction(['t'], ['sin(t)']) f2 = ot.SymbolicFunction(['t'], ['cos(t)^2']) myBasis = ot.Basis([f1, f2]) coefDis = ot.Normal([1.0] * 2, [0.6] * 2, ot.CorrelationMatrix(2)) p1 = ot.FunctionalBasisProcess(coefDis, myBasis, tg) # Second process: smooth Gaussian process p2 = ot.GaussianProcess(ot.SquaredExponential([1.0], [T / 4.0]), tg) # Third process: elementary process based on a bivariate random vector randomParameters = ot.ComposedDistribution([ot.Uniform(), ot.Normal()]) p3 = ot.FunctionalBasisProcess( randomParameters, ot.Basis([ ot.SymbolicFunction(["t"], ["1", "0"]), ot.SymbolicFunction(["t"], ["0", "1"]) ]))
enumerateFunction = ot.EnumerateFunction(dim) factory = ot.OrthogonalProductPolynomialFactory([ot.MonomialFactory()]*dim, enumerateFunction) # Build 'interactions' as a list of list [a1,a2,a3,a4,a5], and we will generate tensorized # polynomials SAL^a1*pH^a2*K^a3*Na^a4*Zn^a5. # BIO~SAL+pH+K+Na+Zn interactions = [] interactions.append([0]*dim) for i in xrange(dim): indices = [0]*dim indices[i] = 1 # Y ~ I(Xi)^1 interactions.append(indices[:]) basis = ot.Basis([factory.build(enumerateFunction.inverse(indices)) for indices in interactions]) ################################################################################################ i_min = [interactions.index([0,0,0,0,0])] i_0 = i_min[:] #---------------- Forward / Backward------------------- # X: input sample # basis : Basis # Y: output sample # i_min: indices of minimal model # direction: Boolean (True FORWARD, False BACKWARD) # penalty: multiplier of number of degrees of freedom # maxiteration: maximum number of iterations #---------------- Both-------------------
#! /usr/bin/env python from __future__ import print_function import openturns as ot R = ot.CorrelationMatrix(2) R[0, 1] = -0.99 d1 = ot.Normal([-1.0, 1.0], [1.0, 1.0], R) R[0, 1] = 0.99 d2 = ot.Normal([1.0, 1.0], [1.0, 1.0], R) distribution = ot.Mixture([d1, d2], [1.0] * 2) classifier = ot.MixtureClassifier(distribution) f1 = ot.SymbolicFunction(['x'], ['-x']) f2 = ot.SymbolicFunction(['x'], ['x']) experts = ot.Basis([f1, f2]) moe = ot.ExpertMixture(experts, classifier) moeNMF = ot.Function(moe) print('Mixture of experts=', moe) # Evaluate the mixture of experts on some points for i in range(2): p = [-0.3 + 0.8 * i / 4.0] print('moe ( %.6g )=' % p[0], moe(p)) print('moeNMF( %.6g )=' % p[0], moeNMF(p)) # and on a sample x = [[-0.3], [0.1]] print('x=', ot.Sample(x), 'moeNMF(x)=', moeNMF(x)) # non-supervised mode (2d) f1 = ot.SymbolicFunction(['x1', 'x2'], ['-8'])
graph = mm2.draw(1e-6, 1.0) view = viewer.View(graph) # %% # Define the mixture R = ot.CorrelationMatrix(2) d1 = ot.Normal([-1.0, -1.0], [1.0] * 2, R) # segment 1 d2 = ot.Normal([1.0, 1.0], [1.0] * 2, R) # segment 2 weights = [1.0] * 2 atoms = [d1, d2] mixture = ot.Mixture(atoms, weights) # %% # Create the classifier based on the mixture classifier = ot.MixtureClassifier(mixture) # %% # Create local experts using the metamodels experts = ot.Basis([mm1, mm2]) # %% # Create a mixture of experts evaluation = ot.ExpertMixture(experts, classifier) moe = ot.Function(evaluation) # %% # Draw the mixture of experts graph = moe.draw(-1.0, 1.0) view = viewer.View(graph) plt.show()
import openturns as ot from openturns.viewer import View f = ot.SymbolicFunction(['x'], ['x * sin(x)']) sampleX = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0], [7.0], [8.0]] sampleY = f(sampleX) basis = ot.Basis([ot.SymbolicFunction(['x'], ['x']), ot.SymbolicFunction(['x'], ['x^2'])]) covarianceModel = ot.SquaredExponential([1.0]) covarianceModel.setActiveParameter([]) algo = ot.KrigingAlgorithm(sampleX, sampleY, covarianceModel, basis) algo.run() result = algo.getResult() graph = f.draw(0.0, 10.0) graph.add(result.getMetaModel().draw(0.0, 10.0)) graph.add(ot.Cloud(sampleX, sampleY)) graph.setColors(['blue', 'red', 'black']) graph.setLegends(['model', 'meta model', 'sample']) graph.setLegendPosition('topleft') graph.setTitle('y(x)=x * sin(x)') View(graph, figure_kwargs={'figsize': (8, 4)})
#! /usr/bin/env python from __future__ import print_function import openturns as ot basisSize = 3 sampleSize = 3 X = ot.NumericalSample(sampleSize, 1) for i in range(sampleSize): X[i, 0] = i + 1.0 Y = ot.NumericalSample(sampleSize, 1) phis = [] for j in range(basisSize): phis.append(ot.NumericalMathFunction(['x'], ['y'], ['x^' + str(j + 1)])) basis = ot.Basis(phis) for i in range(basisSize): print(ot.NumericalMathFunctionCollection(basis)[i](X)) proxy = ot.DesignProxy(X, basis) full = range(basisSize) design = proxy.computeDesign(full) print(design) proxy.setWeight([0.5] * sampleSize) design = proxy.computeDesign(full) print(design)
from matplotlib import pylab as plt import math as m ot.Log.Show(ot.Log.NONE) # %% # Define the coefficients distribution mu = [2.0]*2 sigma = [5.0]*2 R = ot.CorrelationMatrix(2) coefDist = ot.Normal(mu, sigma, R) # %% # Create a basis of functions phi_1 = ot.SymbolicFunction(['t'], ['sin(t)']) phi_2 = ot.SymbolicFunction(['t'], ['cos(t)^2']) myBasis = ot.Basis([phi_1, phi_2]) # %% # Create the mesh myMesh = ot.RegularGrid(0.0, 0.1, 100) # %% # Create the process process = ot.FunctionalBasisProcess(coefDist, myBasis, myMesh) # %% # Draw a sample N = 6 sample = process.getSample(N) graph = sample.drawMarginal(0) graph.setTitle(str(N)+' realizations of functional basis process')
interactions.append([0] * dim) for i in range(dim): indices = [0] * dim indices[i] = 1 # Y ~ I(Xi)^1 interactions.append(indices[:]) funcs = [ factory.build(enumerateFunction.inverse(indices)) for indices in interactions ] description = X.getDescription() description.add('f') [f.setDescription(description) for f in funcs] basis = ot.Basis(funcs) # i_min = [interactions.index([0, 0, 0, 0, 0])] i_0 = i_min[:] penalty_BIC = log(X.getSize()) penalty_AIC = 2. maxiteration = 1000 for k in [penalty_AIC, penalty_BIC]: # Forward / Backward if k == penalty_AIC: IC = " AIC " if k == penalty_BIC: IC = " BIC "
import openturns as ot from math import exp from matplotlib import pyplot as plt from openturns.viewer import View f1 = ot.SymbolicFunction(['t'], ['sin(t)']) f2 = ot.SymbolicFunction(['t'], ['cos(t)*cos(t)']) myBasis = ot.Basis([f1, f2]) coefDis = ot.Normal([2] * 2, [5] * 2, ot.CorrelationMatrix(2)) myTG = ot.RegularGrid(0.0, 0.1, 250) myFBP = ot.FunctionalBasisProcess(coefDis, myBasis, myTG) TS = myFBP.getRealization() graph = TS.draw() graph.add(myFBP.getRealization().draw()) graph.add(myFBP.getRealization().draw()) graph.setColors(['red', 'blue', 'green']) fig = plt.figure(figsize=(10, 4)) plt.suptitle('Functional Basis Process') fbp_axis = fig.add_subplot(111) view = View(graph, figure=fig, axes=[fbp_axis], add_legend=False)
# Define the fitting algorithm using the # Corrected Leave One Out or KFold algorithms myFittingAlgorithm = ot.CorrectedLeaveOneOut() myFittingAlgorithm_2 = ot.KFold() # Define the basis function # For example composed of 5 functions myFunctionBasis = list(map(lambda fst: ot.SymbolicFunction( ['t', 's'], [fst]), ['1', 't', 's', 't^2', 's^2'])) # Define the trend function factory algorithm myTrendFactory = ot.TrendFactory(myBasisSequenceFactory, myFittingAlgorithm) # Create the trend transformation of type TrendTransform myTrendTransform = myTrendFactory.build(myYField, ot.Basis(myFunctionBasis)) # Check the estimated trend function print('Trend function = ', myTrendTransform) # %% # CASE 2 : we impose the trend (or its inverse) # The function g computes the trend : R^2 -> R # g : R^2 --> R # (t,s) --> 1+2t+2s g = ot.SymbolicFunction(['t', 's'], ['1+2*t+2*s']) gTemp = ot.TrendTransform(g, myMesh) # Get the inverse trend transformation # from the trend transform already defined
# # %% import openturns as ot from openturns.viewer import View # %% # First build a process to generate the input data. # We assemble a 4-d process from functional and Gaussian processes. T = 3.0 NT = 32 tg = ot.RegularGrid(0.0, T / NT, NT) f1 = ot.SymbolicFunction(['t'], ['sin(t)']) f2 = ot.SymbolicFunction(['t'], ['cos(t)^2']) coeff1_dist = ot.Normal([1.0] * 2, [0.6] * 2, ot.CorrelationMatrix(2)) p1 = ot.FunctionalBasisProcess(coeff1_dist, ot.Basis([f1, f2]), tg) p2 = ot.GaussianProcess(ot.SquaredExponential([1.0], [T / 4.0]), tg) coeff3_dist = ot.ComposedDistribution([ot.Uniform(), ot.Normal()]) f1 = ot.SymbolicFunction(["t"], ["1", "0"]) f2 = ot.SymbolicFunction(["t"], ["0", "1"]) p3 = ot.FunctionalBasisProcess(coeff3_dist, ot.Basis([f1, f2])) X = ot.AggregatedProcess([p1, p2, p3]) X.setMesh(tg) # %% # Draw some input trajectories from our process ot.RandomGenerator.SetSeed(0) x = X.getSample(10) graph = x.drawMarginal(0) graph.setTitle(f'{x.getSize()} input trajectories') _ = View(graph)