def plot_index_size(): compile_command = compile_base_command + " " + cpp_ipmt_source run(compile_command, print_output=True) for textfile_name in textfiles_names: textfile_path = textfiles_dir + textfile_name textfile_idx_path = textfiles_dir + textfile_name + ".idx" plot_values = [] plot_labels = [] for compression_algorithm in compression_algorithms: for index_algorithm in index_algorithms: plot_labels += [compression_algorithm + '-' + index_algorithm] for compression_algorithm in compression_algorithms: for index_algorithm in index_algorithms: index_command = "./a.out index -v %s --compression=%s --indextype=%s" % ( textfile_path, compression_algorithm, index_algorithm) run(index_command) index_size = os.path.getsize(textfile_idx_path) plot_values += [index_size] PlotUtils.bar_plot(plot_values=plot_values, plot_labels=plot_labels, colors=colors, ylabel="size in bytes", title="Index size of " + textfile_name, save_filename='plots/index-size-' + textfile_name)
def plot_index_time(): compile_command = compile_base_command + " " + cpp_ipmt_source run(compile_command, print_output=True) for textfile_name in textfiles_names: textfile_path = textfiles_dir + textfile_name plot_values = [] plot_labels = [] for compression_algorithm in compression_algorithms: for index_algorithm in index_algorithms: plot_labels += [compression_algorithm + '-' + index_algorithm] for compression_algorithm in compression_algorithms: for index_algorithm in index_algorithms: index_command = "./a.out index -v %s --compression=%s --indextype=%s" % ( textfile_path, compression_algorithm, index_algorithm) r = functools.partial(run, index_command, print_output=True) run_time = get_run_time(r, runs=num_of_runs) plot_values += [run_time] # plot_data[textfile_name] += [gzip_compressed_size] PlotUtils.bar_plot(plot_values=plot_values, plot_labels=plot_labels, colors=colors, ylabel="time in seconds", title="Index time of " + textfile_name, save_filename='plots/index-time-' + textfile_name)
def plot_search_time(): compile_command = compile_base_command + " " + cpp_ipmt_source run(compile_command, print_output=True) for textfile_name in textfiles_names: textfile_path = textfiles_dir + textfile_name textfile_idx_path = textfiles_dir + textfile_name + '.idx' plot_data = {} for compression_algorithm in compression_algorithms: for index_algorithm in index_algorithms: plot_data[compression_algorithm + '-' + index_algorithm] = {} plot_data[compression_algorithm + '-' + index_algorithm]['x'] = pattern_sizes plot_data[compression_algorithm + '-' + index_algorithm]['y'] = [] plot_data['grep'] = {} plot_data['grep']['x'] = pattern_sizes plot_data['grep']['y'] = [] for pattern_size in pattern_sizes: patterns_path = '%s-%d' % (textfile_path, pattern_size) for compression_algorithm in compression_algorithms: for index_algorithm in index_algorithms: # index index_command = "./a.out index -v %s --compression=%s --indextype=%s " % ( textfile_path, compression_algorithm, index_algorithm) run(index_command, print_output=True) # search search_command = "./a.out search %s %s -c" % ( 'pattern', textfile_idx_path) search_command = "./a.out search -c --compression=%s --indextype=%s -p %s %s" % ( compression_algorithm, index_algorithm, patterns_path, textfile_idx_path) r = functools.partial(run, search_command, print_output=True) run_time = get_run_time(r, runs=num_of_runs) plot_data[compression_algorithm + '-' + index_algorithm]['y'] += [run_time] grep_command = 'grep pattern "%s" -o | wc -l' % (textfile_path) # grep_command = 'grep -f "%s" "%s" -o | wc -l' % (patterns_path, # textfile_path) r = functools.partial(run, grep_command) run_time = get_run_time(r, runs=num_of_runs) plot_data['grep']['y'] += [run_time] PlotUtils.line_plot(plots=plot_data, xlabel='Pattern sizes', ylabel='Time in seconds', title='Search time ' + textfile_name, save_filename='plots/search-time-' + textfile_name)
def evaluate(self, test_data, test_labels, batch_size=64, verbose=0): predictions_raw = self.model.predict(test_data, batch_size=batch_size, verbose=verbose) predictions_labels_indexes = np.argmax(predictions_raw, axis=1) test_labels_indexes = np.argmax(test_labels, axis=1) confusion_matrix = sklearn_cm(test_labels_indexes, predictions_labels_indexes) PlotUtils.plot_confusion_matrix(confusion_matrix, class_names=LABELS) return MathUtils.calculate_loss( test_labels, predictions_raw), MathUtils.calculate_accuracy( test_labels, predictions_raw), predictions_raw
def plot_trainingdata(self): count = self.trainingdata_count() fig, ax = PlotUtils.prepare_figure(len(count)) ax.bar(range(0, len(count)), count, width=0.7) ax.bar(range(0, len(count)), count, width=0.7) plt.ylabel(_("Number of training data")) return fig
def plot_decompression_time(): compile_command = compile_base_command + " " + cpp_compression_source run(compile_command, print_output=True) for textfile_name in textfiles_names: textfile_path = textfiles_dir + textfile_name textfile_zip_path = textfile_path + ".myzip" plot_values = [] plot_labels = [] for algorithm in compression_algorithms: plot_labels += [algorithm] plot_labels += ['gzip'] for algorithm in compression_algorithms: compression_command = run_base_command + ' %s %s compress' % ( algorithm, textfile_path) decompression_command = run_base_command + ' %s %s decompress' % ( algorithm, textfile_zip_path) run(compression_command, print_output=True) r = functools.partial(run, decompression_command, print_output=True) run_time = get_run_time(r, runs=num_of_runs) plot_values += [run_time] textfile_gzip_path = textfile_path + ".gz" gzip_compress_command = "gzip -k -f " + textfile_path gzip_decompress_command = "gzip -k -f -d " + textfile_gzip_path run(gzip_compress_command) r = functools.partial(run, gzip_decompress_command, print_output=True) run_time = get_run_time(r, runs=num_of_runs) plot_values += [run_time] print(plot_values) PlotUtils.bar_plot(plot_values=plot_values, plot_labels=plot_labels, colors=colors, ylabel="time in seconds", title="Decompression time of " + textfile_name, save_filename='plots/decompress-time-' + textfile_name)
def __init__(self, settings, function): # TODO add settings parameter super(self.__class__, self).__init__() # read in settings num_dims = settings['number_of_dimensions'] population_size = settings['population_size'] bounds = settings['bounds'] if settings['velocity_type'] == 'constriction': phi = max(settings['cp'] + settings['cg'], 4.0) self.k = 2.0 / abs(2.0 - phi - sqrt(phi * phi - 4.0 * phi)) else: self.k = 1 # check to make sure num_dims and number of bounds provided match if len(bounds) != num_dims: raise ValueError( "Number of dimensions doesn't match number of bounds provided") # set instance variables self.settings = settings self.function = function # initialize population self.population = PSO.__gen_population(bounds, population_size, function) self.total_population = population_size self.best_x = PSO.__get_best_particle(self.population) self.num_iterations = 1 if settings['plot']: try: self.plotutils = PlotUtils(num_dims, bounds, function) self.__plot_state() except ValueError: print("Can not plot more than 2 dimensions") settings['plot'] = False if settings['print_iterations']: self.__display_state() if settings['step_through']: oa_utils.pause()
def plot_compression_size(): compile_command = '%s %s' % (compile_base_command, cpp_compression_source) run(compile_command, print_output=True) for textfile_name in textfiles_names: textfile_path = textfiles_dir + textfile_name textfile_zip_path = textfile_path + ".myzip" plot_values = [] plot_labels = [] for algorithm in compression_algorithms: plot_labels += [algorithm] plot_labels += ['gzip'] for algorithm in compression_algorithms: run_command = run_base_command + ' %s %s compress' % ( algorithm, textfile_path) if os.path.exists(textfile_zip_path): os.remove(textfile_zip_path) run(run_command, print_output=True) compressed_size = os.path.getsize(textfile_zip_path) plot_values += [compressed_size] gzip_command = "gzip -k -f " + textfile_path run(gzip_command) textfile_gzip_path = textfile_path + ".gz" gzip_size = os.path.getsize(textfile_gzip_path) plot_values += [gzip_size] print(plot_values) PlotUtils.bar_plot(plot_values, plot_labels=plot_labels, colors=colors, ylabel="size in bytes", title="Compression size of " + textfile_name, save_filename='plots/compress-size-' + textfile_name)
def __init__(self, settings, function): # TODO add settings parameter super(self.__class__, self).__init__() # read in settings num_dims = settings['number_of_dimensions'] population_size = settings['population_size'] bounds = settings['bounds'] # check to make sure num_dims and number of bounds provided match if len(bounds) != num_dims: raise ValueError("Number of dimensions doesn't match number of bounds provided") # set instance variables self.settings = settings self.function = function # initialize population self.population = GA.__gen_population(bounds, population_size, function) self.total_organisms = len(self.population) self.best_x = self.population[0] self.num_generations = 1 # stopping criteria variables self.func_val_improvement = 0 self.num_iter_since_improvement = 0 if settings['plot']: try: self.plotutils = PlotUtils(num_dims, bounds, function) self.__plot_state() except ValueError: print("Can not plot more than 2 dimensions") settings['plot'] = False if settings['print_iterations']: self.__display_state() if settings['step_through']: oa_utils.pause()
def plot_y_stats(self): norm = self.y.norm() stdev = self.y.stdev_s() upper = [norm[i] + stdev[i] for i in range(0, len(stdev))] lower = [norm[i] - stdev[i] for i in range(0, len(stdev))] fig, ax = PlotUtils.prepare_figure(len(stdev)) [ ax.plot(self.y.data_by_year(year).values, label='individual years', color='blue', alpha=.2) for year in range(self.y.timeseries.index[0].year, self.y.timeseries.index[-1].year + 1) ] ax.plot(upper, color='black') ax.plot(lower, color='black', label="+/- STDEV") ax.plot(norm, label="NORM", color='red') handles, labels = ax.get_legend_handles_labels() ax.legend(handles[-3:], labels[-3:]) plt.ylabel(self.y.label) return fig
def write_html(self, username, organization, site_code, site_name, forecast_model_name, forecast_method, forecast_model_params, forecast_method_params, filename=None, htmlpage=None, language='en'): activate(language) if self.y.mode == 'p': frequency = 'fiveday' elif self.y.mode == 'd': frequency = 'decade' elif self.y.mode == 'm': frequency = 'monthly' page = self.load_template_file() scatter_plot = PlotUtils.plot_ts_comparison( self.y_adj.timeseries, self.forecast.timeseries, frequency, language=language, ) scaled_error_title = _('Scaled Error [RMSE/STDEV]') scaled_error_plot = PlotUtils.plot_rel_error(self.rel_error, frequency, title=scaled_error_title) scaled_error_table = self.rel_error_table(frequency) p_plot_title = _('P% Plot') p_plot_plot = PlotUtils.plot_p(self.p, frequency, title=p_plot_title) p_plot_table = self.p_plot_table(frequency) quality_assessment_table = self.summary_table(frequency) report_data = { 'SITE_INFO': _('Station: {code} - {name}').format(code=to_str(site_code), name=to_str(site_name)), 'USERNAME': username, 'ORGANIZATION': organization, 'TITLE': _('Forecast Model Training Report'), 'REPORT_DATE': format_date(format='long', locale=language), 'PLOTS_HEADER': _('{frequency} Forecast Model Quality Assessment').format( frequency=frequency.capitalize()), 'SCATTER_PLOT_LABEL': _('Scatter Plot: Observed versus Predicted values'), 'SCALED_ERROR_LABEL': scaled_error_title, 'P_PLOT_LABEL': p_plot_title, 'QUALITY_ASSESSMENT_LABEL': _('Quality Assessment'), 'SCATTER_PLOT_IMAGE': scatter_plot, 'SCALED_ERROR_PLOT_IMAGE': scaled_error_plot, 'SCALED_ERROR_TABLE': scaled_error_table, 'P_PLOT_IMAGE': p_plot_plot, 'P_PLOT_TABLE': p_plot_table, 'QUALITY_ASSESSMENT_TABLE': quality_assessment_table, 'FORECAST_MODEL_INFO': _('Forecast model info:'), 'FORECAST_MODEL_NAME': _('Name: ') + forecast_model_name, 'FORECAST_METHOD': _('Method: ') + forecast_method, 'FORECAST_MODEL_PARAMS': _('Model parameters: ') + str(forecast_model_params), 'FORECAST_METHOD_PARAMS': _('Method parameters: ') + str(forecast_method_params), } report_data.update(self.get_spacers(frequency, language)) self.encode_utf8(report_data) if filename: htmlpage = open(filename, 'w') htmlpage.write(page.safe_substitute(**report_data)) htmlpage.close() return filename elif htmlpage: htmlpage.write(page.safe_substitute(**report_data)) return htmlpage
class GA(Timer, object): """A genetic algorithm class that contains methods for handling the population over generations/iterations Attributes: There are not attributes for this class. All settings/attributes are read in from ga_settings.py which should be located in the same directory as this file NOTE: The GA methods assume the population array is sorted """ def __init__(self, settings, function): # TODO add settings parameter super(self.__class__, self).__init__() # read in settings num_dims = settings['number_of_dimensions'] population_size = settings['population_size'] bounds = settings['bounds'] # check to make sure num_dims and number of bounds provided match if len(bounds) != num_dims: raise ValueError("Number of dimensions doesn't match number of bounds provided") # set instance variables self.settings = settings self.function = function # initialize population self.population = GA.__gen_population(bounds, population_size, function) self.total_organisms = len(self.population) self.best_x = self.population[0] self.num_generations = 1 # stopping criteria variables self.func_val_improvement = 0 self.num_iter_since_improvement = 0 if settings['plot']: try: self.plotutils = PlotUtils(num_dims, bounds, function) self.__plot_state() except ValueError: print("Can not plot more than 2 dimensions") settings['plot'] = False if settings['print_iterations']: self.__display_state() if settings['step_through']: oa_utils.pause() # def __del__(self): # del(self.plotutils) # @staticmethod def __gen_organism(id, bounds, function): # use gen_random_numbers to get a list of positions within the bounds return Organism(id, oa_utils.gen_random_numbers(bounds), function) @staticmethod def __gen_population(bounds, size, function): b = bounds f = function # generate a list of organisms p = [GA.__gen_organism(i+1, b, f) for i in range(0, size)] return GA.__sort_population(p) @staticmethod def __sort_population(p): return sorted(p, key=lambda o: o.fitness) ########################### ### GA steps and loop ### ########################### ''' Three possible ways of doing this. 1. have a setting that says we kill of last 20% of array or population 2. the further you are down the array the higher your probability of dieing 3. kill off the worst based on their distance from the best TODO write a test for this. simple 10 population w/ .5 cutoff test will do ''' @staticmethod def __selection(population, cutoff, print_action=False): size = len(population) max_f = population[0].fitness min_f = population[size-1].fitness # denominator in probability of surviving den = (max_f - min_f) # if den == 0: # print("Every organism has same objective function value.") for (i, organism) in enumerate(population): f = organism.fitness # check for division by zero if den == 0: normalized_f = 0 else: # get normalized value normalized_f = float(f - min_f) / den if normalized_f > cutoff: # delete the organism from the population del population[i] if print_action: print("Selection: Deleting organism %s" % str(organism)) return population @staticmethod def __get_parent_index(cdf_value, arr): norm_sum = 0 for i, o in enumerate(arr): norm_sum += o['probability'] if norm_sum >= cdf_value: return i return -1 @staticmethod def __mate_parents(id, parent1, parent2, function): n = len(parent1.pos) # randomly choose split position split = random.randint(0, n-1) # split parent positions pos1 = parent1.pos[0:split] + parent2.pos[split:] pos2 = parent2.pos[0:split] + parent1.pos[split:] # get id numbers id1 = id + 1 id2 = id + 2 # return the two newly created organisms return (Organism(id1, pos1, function), Organism(id2, pos2, function)) """ population: population size: size that the population should be after crossover NOTE: population must be sorted. crossover will return an unsorted array of the new population. """ @staticmethod def __crossover(id, population, size, function, print_action=False): new_population = [] length = len(population) max_f = population[length-1].fitness min_f = population[0].fitness den = max_f - min_f # if size is odd if size % 2 == 1: raise ValueError("Populations with an odd size hasn't been implemented. Talk to Jesse") # get inversed normalized values of fitness # normalized value of 1 is the best. 0 is the worst probabilities = [] normalized_sum = 0.0 for o in population: if den == 0: normalized_f = 1 else: normalized_f = (max_f - o.fitness)/den normalized_sum += normalized_f probabilities.append({'normalized_f': normalized_f}) # calculate weight of each normalized value for i, p in enumerate(probabilities): probabilities[i]['probability'] = probabilities[i]['normalized_f']/normalized_sum # generate new population while len(new_population) < size: # get cdf input values cdf1 = random.random() cdf2 = random.random() # get index of parent from output of cdf i = GA.__get_parent_index(cdf1, probabilities) j = GA.__get_parent_index(cdf2, probabilities) # mate parents child1, child2 = GA.__mate_parents(id, population[i], population[j], function) id += 2 # append children to new_population new_population.extend((child1, child2)) if print_action: for organism in new_population: print("Crossover: New oganism %s" % str(organism)) return new_population @staticmethod def __mutation(population, bounds, rate, max_mutation_amount, print_action=False): for organism in population: if random.random() < rate: new_pos = [] # for each dimension for i in range(0, len(bounds)): # take some percentage of the max mutation amount x = random.uniform(0.01, 1.00) delta_pos = (-1.0*log(1-x))*max_mutation_amount # should we go positive or negative if random.randint(0,1) == 1: delta_pos = -1.0*delta_pos new_dim_pos = organism.pos[i] + delta_pos # cap where we can go if we are beyond the bounds of the design space if new_dim_pos < bounds[i][0]: new_dim_pos = bounds[i][0] elif new_dim_pos > bounds[i][1]: new_dim_pos = bounds[i][1] new_pos.append(new_dim_pos) if print_action: new_pos_str = "[" for x in new_pos: new_pos_str += "%6.3f " % x new_pos_str += "]" print("Mutation: Moving organism %s to %s" % \ (str(organism), new_pos_str)) organism.pos = new_pos organism.fitness = organism.get_fval() return population def __display_state(self): print("The best organism in generation %d is %s" \ % (self.num_generations, str(self.get_best_x()))) def __plot_state(self): pts = [(organism.pos[0], organism.pos[1]) for organism in self.population] self.plotutils.plot(pts) def __str__(self): return "Iteration %d Best Fitness: %8.4f by organism %s" % \ (self.num_generations, self.get_best_f(), str(self.get_best_x())) #################################### # These are the only methods that # # should be called outside of this # # class # #################################### def get_best_x(self): return self.best_x def get_best_f(self): return self.best_x.fitness def do_loop(self): population = self.population population = GA.__selection(population, \ self.settings['selection_cutoff'], \ self.settings['print_actions']) population = GA.__crossover(self.total_organisms, \ population, \ self.settings['population_size'], \ self.function, \ self.settings['print_actions']) self.total_organisms += len(population) population = GA.__mutation(population, \ self.settings['bounds'], \ self.settings['mutation_rate'], \ self.settings['max_mutation_amount'], \ self.settings['print_actions']) self.population = GA.__sort_population(population) self.num_generations += 1 if self.population[0].fitness < self.best_x.fitness: # add on the improvement in function value self.func_val_improvement += (self.best_x.fitness - self.population[0].fitness) self.best_x = self.population[0] if self.settings['plot']: self.__plot_state() if self.settings['print_iterations']: self.__display_state() if self.settings['step_through']: oa_utils.pause() def run(self): # iterate over generations while self.settings['num_iterations'] > self.num_generations: self.do_loop() # check if we've improved our function value if self.func_val_improvement > self.settings['stopping_criteria']: self.func_val_improvement = 0 self.num_iter_since_improvement = 0 else: self.num_iter_since_improvement += 1 # check if we haven't improved at all in num of stopping criteria steps if self.num_iter_since_improvement > self.settings['num_iter_stop_criteria']: if self.settings['print_actions'] or self.settings['print_iterations']: print("Stopping criteria met after %d number of iterations" % self.num_generations) break # pause for a bit if setting is set time.sleep(self.settings['time_delay']) if self.num_generations > self.settings['num_iterations']: if self.settings['print_actions'] or self.settings['print_iterations']: print("Maximum number of iterations hit (%d)" % self.num_generations) @staticmethod def get_name(): return "Genetic Algorithm"
class PSO(Timer, object): """A particle swarm class that contains methods for handling the population over iterations Attributes: There are not attributes for this class. All settings/attributes are read in from pso_settings.py which should be located in the same directory as this file """ def __init__(self, settings, function): # TODO add settings parameter super(self.__class__, self).__init__() # read in settings num_dims = settings['number_of_dimensions'] population_size = settings['population_size'] bounds = settings['bounds'] if settings['velocity_type'] == 'constriction': phi = max(settings['cp'] + settings['cg'], 4.0) self.k = 2.0 / abs(2.0 - phi - sqrt(phi * phi - 4.0 * phi)) else: self.k = 1 # check to make sure num_dims and number of bounds provided match if len(bounds) != num_dims: raise ValueError( "Number of dimensions doesn't match number of bounds provided") # set instance variables self.settings = settings self.function = function # initialize population self.population = PSO.__gen_population(bounds, population_size, function) self.total_population = population_size self.best_x = PSO.__get_best_particle(self.population) self.num_iterations = 1 if settings['plot']: try: self.plotutils = PlotUtils(num_dims, bounds, function) self.__plot_state() except ValueError: print("Can not plot more than 2 dimensions") settings['plot'] = False if settings['print_iterations']: self.__display_state() if settings['step_through']: oa_utils.pause() @staticmethod def __gen_particle(id, bounds, function): # use gen_random_numbers to get a list of positions within the bounds return Particle(id, oa_utils.gen_random_numbers(bounds), function) @staticmethod def __gen_population(bounds, size, function): b = bounds f = function # generate a list of organisms p = [PSO.__gen_particle(i + 1, b, f) for i in range(0, size)] return p ########################### ### PSO steps and loop ### ########################### @staticmethod def __update_velocity(population, velocity_type, print_actions, gbest, cp, cg, k, w): for p in population: if (velocity_type == 'normal'): p.velocity = PSO.__get_velocity(1, cp, cg, gbest, p, 1) elif (velocity_type == 'inertia'): p.velocity = PSO.__get_velocity(k, cp, cg, gbest, p, w) elif (velocity_type == 'constriction'): p.velocity = PSO.__get_velocity(k, cp, cg, gbest, p, 1) return population @staticmethod def __get_velocity(k, c1, c2, gbest, p, w): velocity_array = [] for i, v in enumerate(p.velocity): velocity_array.append( k * (w * v + c1 * random.random() * (p.pbest[i] - p.pos[i]) + c2 * random.random() * (gbest[i] - p.pos[i]))) return velocity_array @staticmethod def __update_position( population): # TODO put bounds on what position can be updated to for p in population: p.pos = list(map(add, p.pos, p.velocity)) p.fval = p.get_fval() return population @staticmethod def __get_best_particle(population): return copy.deepcopy(min(population, key=attrgetter('fval'))) def __display_state(self): print("The best organism in generation %d is %s" \ % (self.num_generations, str(self.get_best_x()))) def __plot_state(self): pts = [(organism.pos[0], organism.pos[1]) for organism in self.population] self.plotutils.plot(pts) def __str__(self): return "Best Fitness: %8.4f by particle %s" % \ (self.get_best_f(), str(self.get_best_x())) #################################### # These are the only methods that # # should be called outside of this # # class # #################################### def get_best_x(self): return self.best_x def get_best_f(self): return self.best_x.fval def do_loop(self): population = self.population population = PSO.__update_velocity(population, \ self.settings['velocity_type'], \ self.settings['print_actions'], \ self.get_best_x().pos, \ self.settings['cp'], \ self.settings['cg'], \ self.k, \ self.settings['weight']) if self.settings['cg_plus']: self.settings['cg'] += 0.1 phi = max(self.settings['cp'] + self.settings['cg'], 4.0) self.k = 2.0 / abs(2.0 - phi - sqrt(phi * phi - 4.0 * phi)) population = PSO.__update_position(population) self.num_iterations += 1 self.population = population current_best = PSO.__get_best_particle(self.population) if current_best.get_fval() < self.best_x.get_fval(): self.best_x = current_best if self.settings['plot']: self.__plot_state() if self.settings['print_iterations']: self.__display_state() if self.settings['step_through']: oa_utils.pause() def run(self): # iterate over generations while self.settings['num_iterations'] > self.num_iterations: self.do_loop() time.sleep(self.settings['time_delay']) @staticmethod def get_name(): return "Particle Swarm"
# then we can import PlotUtils from plot_utils import PlotUtils # you could import settings from a separate file like so from settings import settings # plot util variable. probably make this an instance # variable in a class plotutils = None if settings['plot']: try: # Create PlotUtils instance # 2 params. number of dimensions and an array of 2D lists with # the bounds for each dimension. ex [(-10,10), (-10,10)] plotutils = PlotUtils(settings['num_dims'], settings['bounds']) except ValueError: print("Can not plot more than 2 dimensions!") # set this to false so that we don't try to use # the plotutils variable later on settings['plot'] = False # data should be an array of 2D lists with x1 and x2 data data = [(1, 1), (8, 4), (-4, -9)] # open or update plot if settings['plot']: plotutils.plot(data) # you can put plotutils.plot(data) in a loop and continually update # the plot. Here I just wait for you to press enter, after which the