From 2d5c399675cab352b3e6fcdae3061bd9489e7e11 Mon Sep 17 00:00:00 2001 From: Torsten Date: Thu, 21 Feb 2019 01:18:13 +0000 Subject: [PATCH 1/6] Added classes to provide visualization of distributions (histograms and ensembles of CDFs) --- visualisation_distribution_plots.py | 177 ++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 visualisation_distribution_plots.py diff --git a/visualisation_distribution_plots.py b/visualisation_distribution_plots.py new file mode 100644 index 0000000..028f938 --- /dev/null +++ b/visualisation_distribution_plots.py @@ -0,0 +1,177 @@ +"""Auxiliary classes for visualization of distributions. + - Histograms (e.g. of bankruptcy events by size) + - Ensembles of distributions (e.g., of firm sizes at the end of each replication across the ensemble) + These classes should primarily be used from and by classes defined in visualisation.py""" + +from scipy.stats import expon +import numpy as np +import matplotlib.pyplot as plt + +"""Class for plots of ensembles of distributions as CDF (cumulative distribution function) or cCDF (complementary + cumulative distribution function) with mean, median, and quantiles""" +class CDFDistribution(): + def __init__(self, samples_x): + """Constructor. + Arguments: + samples_x: list of list or ndarray of int or float - list of samples to be visualized. + Returns: + Class instance""" + self.samples_x = [] + self.samples_y = [] + for x in samples_x: + x = np.asarray(x, dtype=np.float64) + y = (np.arange(len(x), dtype=np.float64)+1) / len(x) + self.samples_x.append(x) + self.samples_y.append(y) + self.series_y = None + self.median_x = None + self.mean_x = None + self.quantile_series_x = None + self.quantile_series_y_lower = None + self.quantile_series_y_upper = None + + def make_figure(self, upper_quantile=.25, lower_quantile=.75): + """Method to do the necessary computations to create the CDF plot (incl. mean, median, quantiles. + This method populates the variables that are plotted. + Arguments: + upper_quantile: float \in [0,1] - upper quantile threshold + lower_quantile: float \in [0,1] - lower quantile threshold + Returns None.""" + + """Obtain ordered set of all y values""" + self.series_y = np.unique(np.sort(np.hstack(self.samples_y))) + + """Obtain x coordinates corresponding to the full ordered set of all y values (self.series_y) for each series""" + set_of_series_x = [] + for i in range(len(samples_x)): + x = [self.samples_x[i][np.argmax(self.samples_y[i]>=y)] if self.samples_y[i][0]<=y else 0 for y in self.series_y] + set_of_series_x.append(x) + + """Join x coordinates to matrix of size m x n (n: number of series, m: length of ordered set of y values (self.series_y))""" + series_matrix_x = np.vstack(set_of_series_x) + + """Compute x quantiles, median, mean across all series""" + quantile_lower_x = np.quantile(series_matrix_x,.25, axis=0) + quantile_upper_x = np.quantile(series_matrix_x,.75, axis=0) + self.median_x = np.quantile(series_matrix_x,.50, axis=0) + self.mean_x = series_matrix_x.mean(axis=0) + + """Obtain x coordinates for quantile plots. This is the ordered set of all x coordinates in lower and upper quantile series.""" + self.quantile_series_x = np.unique(np.sort(np.hstack([quantile_lower_x, quantile_upper_x]))) + + """Obtain y coordinates for quantile plots. This is one y value for each x coordinate.""" + #self.quantile_series_y_lower = [self.series_y[np.argmax(quantile_lower_x>=x)] if quantile_lower_x[0]<=x else 0 for x in self.quantile_series_x] + self.quantile_series_y_lower = np.asarray([self.series_y[np.argmax(quantile_lower_x>=x)] if np.sum(np.argmax(quantile_lower_x>=x))>0 else np.max(self.series_y) for x in self.quantile_series_x]) + self.quantile_series_y_upper = np.asarray([self.series_y[np.argmax(quantile_upper_x>=x)] if quantile_upper_x[0]<=x else 0 for x in self.quantile_series_x]) + + def reverse_CDF(self): + """Method to reverse the CDFs and obtain the complementary CDFs (survival functions) instead. + The method overwrites the attributes used for plotting. + Arguments: None. + Returns: None.""" + self.series_y = 1. - self.series_y + self.quantile_series_y_lower = 1. - self.quantile_series_y_lower + self.quantile_series_y_upper = 1. - self.quantile_series_y_upper + + def plot(self, ax=None, ylabel="CDF(x)", xlabel="y", upper_quantile=.25, lower_quantile=.75, force_recomputation=False, show=False, outputname=None, color="C2", plot_cCDF=False): + """Method to compile the plot. The plot is added to a provided matplotlib axes object or a new one is created. + Arguments: + ax: matplitlib axes - the system of coordinates into which to plot + ylabel: str - y axis label + xlabel: str - x axis label + upper_quantile: float \in [0,1] - upper quantile threshold + lower_quantile: float \in [0,1] - lower quantile threshold + force_recomputation: bool - force re-computation of plots + show: bool - show plot + outputname: str - output file name without ending + color: str or other admissible matplotlib color label - color to use for the plot + plot_cCDF: bool - plot survival function (cCDF) instead of CDF + Returns: None.""" + + """Create figure if none was provided""" + if ax is None: + fig = plt.figure() + ax = fig.add_subplot(111) + + """Compute plots if not already done or if recomputation was requested""" + if (self.series_y is None) or force_recomputation: + self.make_figure(upper_quantile, lower_quantile) + + """Switch to cCDF if requested""" + if plot_cCDF: + self.reverse_CDF() + + """Plot""" + ax.fill_between(self.quantile_series_x, self.quantile_series_y_lower, self.quantile_series_y_upper, facecolor=color, alpha=0.25) + ax.plot(self.median_x, self.series_y, color=color) + ax.plot(self.mean_x, self.series_y, dashes=[3, 3], color=color) + + """Set plot attributes""" + ax.set_ylabel(ylabel) + ax.set_xlabel(xlabel) + + """Save if filename provided""" + if outputname is not None: + plt.savefig(outputname + ".pdf") + plt.savefig(outputname + ".png", density=300) + + """Show if requested""" + if show: + plt.show() + + +"""Class for histogram plots.""" +class Histogram(): + def __init__(self, sample_x): + self.sample_x = sample_x + + def plot(self, ax=None, ylabel="PDF(x)", xlabel="x", num_bins=50, show=False, outputname=None, color="C2"): + """Method to compile the plot. The plot is added to a provided matplotlib axes object or a new one is created. + Arguments: + ax: matplitlib axes - the system of coordinates into which to plot + ylabel: str - y axis label + xlabel: str - x axis label + num_bins: int - number of bins + show: bool - show plot + outputname: str - output file name without ending + color: str or other admissible matplotlib color label - color to use for the plot + Returns: None.""" + + """Create figure if none was provided""" + if ax is None: + fig = plt.figure() + ax = fig.add_subplot(111) + + """Plot""" + ax.hist(x, bins=num_bins, color=color) + + """Set plot attributes""" + ax.set_ylabel(ylabel) + ax.set_xlabel(xlabel) + + """Save if filename provided""" + if outputname is not None: + plt.savefig(outputname + ".pdf") + plt.savefig(outputname + ".png", density=300) + + """Show if requested""" + if show: + plt.show() + + +if __name__ == "__main__": + + """Unit test for CDF Distribution plot""" + samples_x = [] + for i in range(20): + x = np.sort(expon.rvs(0.1, size=100)) + samples_x.append(x) + + C = CDFDistribution(samples_x) + C.plot(upper_quantile=.25, lower_quantile=.75, show=True) + C.plot(ylabel="cCDF(x)", plot_cCDF=True, show=True) + + """Unit test for Histogram plot""" + x = np.sort(expon.rvs(0.1, size=10000)) + H = Histogram(x) + H.plot(show=True) From 44db2520619367137039bcffad8fc8f48b0a2985 Mon Sep 17 00:00:00 2001 From: Torsten Date: Fri, 22 Feb 2019 02:29:45 +0000 Subject: [PATCH 2/6] Bugfixes --- visualisation_distribution_plots.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/visualisation_distribution_plots.py b/visualisation_distribution_plots.py index 028f938..5d3daec 100644 --- a/visualisation_distribution_plots.py +++ b/visualisation_distribution_plots.py @@ -6,6 +6,7 @@ from scipy.stats import expon import numpy as np import matplotlib.pyplot as plt +import pdb """Class for plots of ensembles of distributions as CDF (cumulative distribution function) or cCDF (complementary cumulative distribution function) with mean, median, and quantiles""" @@ -19,10 +20,11 @@ def __init__(self, samples_x): self.samples_x = [] self.samples_y = [] for x in samples_x: - x = np.asarray(x, dtype=np.float64) - y = (np.arange(len(x), dtype=np.float64)+1) / len(x) - self.samples_x.append(x) - self.samples_y.append(y) + if len(x) > 0: + x = np.sort(np.asarray(x, dtype=np.float64)) + y = (np.arange(len(x), dtype=np.float64)+1) / len(x) + self.samples_x.append(x) + self.samples_y.append(y) self.series_y = None self.median_x = None self.mean_x = None @@ -31,6 +33,7 @@ def __init__(self, samples_x): self.quantile_series_y_upper = None def make_figure(self, upper_quantile=.25, lower_quantile=.75): + #pdb.set_trace() """Method to do the necessary computations to create the CDF plot (incl. mean, median, quantiles. This method populates the variables that are plotted. Arguments: @@ -43,7 +46,7 @@ def make_figure(self, upper_quantile=.25, lower_quantile=.75): """Obtain x coordinates corresponding to the full ordered set of all y values (self.series_y) for each series""" set_of_series_x = [] - for i in range(len(samples_x)): + for i in range(len(self.samples_x)): x = [self.samples_x[i][np.argmax(self.samples_y[i]>=y)] if self.samples_y[i][0]<=y else 0 for y in self.series_y] set_of_series_x.append(x) @@ -63,6 +66,9 @@ def make_figure(self, upper_quantile=.25, lower_quantile=.75): #self.quantile_series_y_lower = [self.series_y[np.argmax(quantile_lower_x>=x)] if quantile_lower_x[0]<=x else 0 for x in self.quantile_series_x] self.quantile_series_y_lower = np.asarray([self.series_y[np.argmax(quantile_lower_x>=x)] if np.sum(np.argmax(quantile_lower_x>=x))>0 else np.max(self.series_y) for x in self.quantile_series_x]) self.quantile_series_y_upper = np.asarray([self.series_y[np.argmax(quantile_upper_x>=x)] if quantile_upper_x[0]<=x else 0 for x in self.quantile_series_x]) + + """The first value of lower must be zero""" + self.quantile_series_y_lower[0] = 0.0 def reverse_CDF(self): """Method to reverse the CDFs and obtain the complementary CDFs (survival functions) instead. @@ -143,7 +149,7 @@ def plot(self, ax=None, ylabel="PDF(x)", xlabel="x", num_bins=50, show=False, ou ax = fig.add_subplot(111) """Plot""" - ax.hist(x, bins=num_bins, color=color) + ax.hist(self.sample_x, bins=num_bins, color=color) """Set plot attributes""" ax.set_ylabel(ylabel) @@ -160,11 +166,10 @@ def plot(self, ax=None, ylabel="PDF(x)", xlabel="x", num_bins=50, show=False, ou if __name__ == "__main__": - """Unit test for CDF Distribution plot""" samples_x = [] for i in range(20): - x = np.sort(expon.rvs(0.1, size=100)) + x = expon.rvs(0.1, size=100) samples_x.append(x) C = CDFDistribution(samples_x) From 5a678677f8bcf314a24945565c60b45701e9be5d Mon Sep 17 00:00:00 2001 From: Torsten Date: Fri, 22 Feb 2019 02:33:11 +0000 Subject: [PATCH 3/6] Implemented cCDF distribution in visualisation.py --- visualisation.py | 76 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/visualisation.py b/visualisation.py index 2ce6814..8f7f98e 100644 --- a/visualisation.py +++ b/visualisation.py @@ -2,8 +2,9 @@ import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation +import visualisation_distribution_plots import argparse - +import pdb class TimeSeries(object): @@ -201,6 +202,61 @@ def show(self): def save(self): # logic to save plots pass + + +"""Class for CDF/cCDF distribution plots using auxiliary class from visualisation_distribution_plots.py. + This class arranges as many such plots stacked in one diagram as there are series in the history + logs they are created from, i.e. len(vis_list).""" +class CDF_distribution_plot(): + def __init__(self, vis_list, colour_list, quantiles=[.25, .75], variable="reinsurance_firms_cash", timestep=-1, plot_cCDF=True): + """Constructor. + Arguments: + vis_list: list of visualisation objects - objects hilding the data + colour list: list of str - colors to be used for each plot + quantiles: list of float of length 2 - lower and upper quantile for inter quantile range in plot + variable: string (must be a valid dict key in vis_list[i].history_logs_list + - the history log variable for which the distribution is plotted + (will be either "insurance_firms_cash" or "reinsurance_firms_cash") + timestep: int - timestep at which the distribution to be plotted is taken + plot_cCDF: bool - plot survival function (cCDF) instead of CDF + Returns class instance.""" + self.vis_list = vis_list + self.colour_list = colour_list + self.lower_quantile, self.upper_quantile = quantiles + self.variable = variable + self.timestep = timestep + + def generate_plot(self, xlabel=None, filename=None): + """Method to generate and save the plot. + Arguments: + xlabel: str or None - the x axis label + filename: str or None - the filename without ending + Returns None.""" + + """Set x axis label and filename to default if not provided""" + xlabel = xlabel if xlabel is not None else self.variable + filename = filename if filename is not None else "CDF_plot_" + self.variable + + """Create figure with correct number of subplots""" + self.fig, self.ax = plt.subplots(nrows=len(self.vis_list)) + + """Loop through simulation record series, populate subplot by subplot""" + for i in range(len(self.vis_list)): + """Extract firm records from history logs""" + series_x = [replication[self.variable][self.timestep] for replication in self.vis_list[i].history_logs_list] + """Extract the capital holdings from the tuple""" + for j in range(len(series_x)): + series_x[j] = [firm[0] for firm in series_x[j] if firm[2]] + """Create CDFDistribution object and populate the subfigure using it""" + VDP = visualisation_distribution_plots.CDFDistribution(series_x) + #VDP.make_figure(upper_quantile=self.upper_quantile, lower_quantile=self.lower_quantile) + c_xlabel = "" if i < len(self.vis_list) - 1 else xlabel + VDP.plot(ax=self.ax[i], ylabel="cCDF " + str(i) + "RM", xlabel=c_xlabel, upper_quantile=self.upper_quantile, lower_quantile=self.lower_quantile, color=self.colour_list[i], plot_cCDF=True) + + """Finish and save figure""" + self.fig.tight_layout() + self.fig.savefig(filename + ".pdf") + self.fig.savefig(filename + ".png", density=300) if __name__ == "__main__": @@ -209,6 +265,8 @@ def save(self): parser = argparse.ArgumentParser(description='Model the Insurance sector') parser.add_argument("--single", action="store_true", help="plot time series of a single run of the insurance model") parser.add_argument("--comparison", action="store_true", help="plot the result of an ensemble of replicatons of the insurance model") + parser.add_argument("--firmdistribution", action="store_true", help="plot the cCDFs of firm size distributions with quantiles indicating variation across ensemble") + parser.add_argument("--bankruptcydistribution", action="store_true", help="plot the histograms of bankruptcy events across ensemble") args = parser.parse_args() @@ -228,8 +286,8 @@ def save(self): N = len(history_logs_list) - if args.comparison: - + if args.comparison or args.firmdistribution or args.bankruptcydistribution: + # for each run, generate an animation and time series for insurer and reinsurer # TODO: provide some way for these to be lined up nicely rather than having to manually arrange screen #for i in range(N): @@ -245,8 +303,18 @@ def save(self): history_logs_list = [eval(k) for k in rfile] # one dict on each line vis_list.append(visualisation(history_logs_list)) - colour_list = ['blue', 'yellow', 'red', 'green'] + colour_list = ['red', 'blue', 'green', 'yellow'] + #pdb.set_trace() + + if args.comparison: + cmp_rsk = compare_riskmodels(vis_list, colour_list) cmp_rsk.create_insurer_timeseries(percentiles=[10,90]) cmp_rsk.create_reinsurer_timeseries(percentiles=[10,90]) cmp_rsk.show() + + if args.firmdistribution: + CP = CDF_distribution_plot(vis_list, colour_list, variable="insurance_firms_cash", timestep=-1, plot_cCDF=True) + CP.generate_plot() + CP = CDF_distribution_plot(vis_list, colour_list, variable="reinsurance_firms_cash", timestep=-1, plot_cCDF=True) + CP.generate_plot() From 1d2f2f4b41f01ace3e52513a739eb2cb1ae1a06e Mon Sep 17 00:00:00 2001 From: Torsten Date: Fri, 22 Feb 2019 02:43:23 +0000 Subject: [PATCH 4/6] Implemented Histogram plots in visualisation.py --- visualisation.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/visualisation.py b/visualisation.py index 8f7f98e..a9d41c8 100644 --- a/visualisation.py +++ b/visualisation.py @@ -83,6 +83,7 @@ def show(self): class visualisation(object): def __init__(self, history_logs_list): self.history_logs_list = history_logs_list + self.scatter_data = {} # unused data in history_logs #self.excess_capital = history_logs['total_excess_capital'] #self.reinexcess_capital = history_logs['total_reinexcess_capital'] @@ -175,6 +176,70 @@ def metaplotter_timescale(self): catbonds_number = np.median([history_logs['total_catbondsoperational'] for history_logs in self.history_logs_list],axis=0) return + def aux_clustered_exit_records(self, exits): + """Auxiliary method for creation of data series on clustered events such as firm market exits. + Will take an unclustered series and aggregate every series of non-zero elements into + the first element of that series. + Arguments: + exits: numpy ndarray or list - unclustered series + Returns: + numpy ndarray of the same length as argument "exits": the clustered series.""" + exits2 = [] + ci = False + cidx = 0 + for ee in exits: + if ci: + exits2.append(0) + if ee > 0: + exits2[cidx] += ee + else: + ci = False + else: + exits2.append(ee) + if ee > 0: + ci = True + cidx = len(exits2) - 1 + + return np.asarray(exits2, dtype=np.float64) + + def populate_scatter_data(self): + """Method to generate data samples that do not have a time component (e.g. the size of bankruptcy events, i.e. + how many firms exited each time. + The method saves these in the instance variable self.scatter_data. This variable is of type dict. + Arguments: None. + Returns: None.""" + + """Record data on sizes of unrecovered_claims""" + self.scatter_data["unrecovered_claims"] = [] + for hlog in self.history_logs_list: # for each replication + urc = np.diff(np.asarray(hlog["cumulative_unrecovered_claims"])) + self.scatter_data["unrecovered_claims"] = np.hstack([self.scatter_data["unrecovered_claims"], np.extract(urc>0, urc)]) + + """Record data on sizes of bankruptcy_events""" + self.scatter_data["bankruptcy_events"] = [] + self.scatter_data["bankruptcy_events_relative"] = [] + self.scatter_data["bankruptcy_events_clustered"] = [] + self.scatter_data["bankruptcy_events_relative_clustered"] = [] + for hlog in self.history_logs_list: # for each replication + """Obtain numbers of operational firms. This is for computing the relative share of exiting firms.""" + in_op = np.asarray(hlog["total_operational"])[:-1] + rein_op = np.asarray(hlog["total_reinoperational"])[:-1] + op = in_op + rein_op + + """Obtain exits and relative exits""" + exits = np.diff(np.asarray(hlog["cumulative_market_exits"], dtype=np.float64)) + rel_exits = exits / op + + """Obtain clustered exits (absolute and relative)""" + exits2 = self.aux_clustered_exit_records(exits) + rel_exits2 = exits2 / op + + """Record data""" + self.scatter_data["bankruptcy_events"] = np.hstack([self.scatter_data["bankruptcy_events"], np.extract(exits>0, exits)]) + self.scatter_data["bankruptcy_events_relative"] = np.hstack([self.scatter_data["bankruptcy_events_relative"], np.extract(rel_exits>0, rel_exits)]) + self.scatter_data["bankruptcy_events_clustered"] = np.hstack([self.scatter_data["bankruptcy_events_clustered"], np.extract(exits2>0, exits2)]) + self.scatter_data["bankruptcy_events_relative_clustered"] = np.hstack([self.scatter_data["bankruptcy_events_relative_clustered"], np.extract(rel_exits2>0, rel_exits2)]) + def show(self): plt.show() return @@ -251,12 +316,57 @@ def generate_plot(self, xlabel=None, filename=None): VDP = visualisation_distribution_plots.CDFDistribution(series_x) #VDP.make_figure(upper_quantile=self.upper_quantile, lower_quantile=self.lower_quantile) c_xlabel = "" if i < len(self.vis_list) - 1 else xlabel - VDP.plot(ax=self.ax[i], ylabel="cCDF " + str(i) + "RM", xlabel=c_xlabel, upper_quantile=self.upper_quantile, lower_quantile=self.lower_quantile, color=self.colour_list[i], plot_cCDF=True) + VDP.plot(ax=self.ax[i], ylabel="cCDF " + str(i+1) + "RM", xlabel=c_xlabel, upper_quantile=self.upper_quantile, lower_quantile=self.lower_quantile, color=self.colour_list[i], plot_cCDF=True) """Finish and save figure""" self.fig.tight_layout() self.fig.savefig(filename + ".pdf") self.fig.savefig(filename + ".png", density=300) + + +"""Class for CDF/cCDF distribution plots using auxiliary class from visualisation_distribution_plots.py. + This class arranges as many such plots stacked in one diagram as there are series in the history + logs they are created from, i.e. len(vis_list).""" +class Histogram_plot(): + def __init__(self, vis_list, colour_list, variable="bankruptcy_events"): + """Constructor. + Arguments: + vis_list: list of visualisation objects - objects hilding the data + colour list: list of str - colors to be used for each plot + variable: string (must be a valid dict key in vis_list[i].scatter_data + - the history log variable for which the distribution is plotted + Returns class instance.""" + self.vis_list = vis_list + self.colour_list = colour_list + self.variable = variable + + def generate_plot(self, xlabel=None, filename=None): + """Method to generate and save the plot. + Arguments: + xlabel: str or None - the x axis label + filename: str or None - the filename without ending + Returns None.""" + + """Set x axis label and filename to default if not provided""" + xlabel = xlabel if xlabel is not None else self.variable + filename = filename if filename is not None else "Histogram_plot_" + self.variable + + """Create figure with correct number of subplots""" + self.fig, self.ax = plt.subplots(nrows=len(self.vis_list)) + + """Loop through simulation record series, populate subplot by subplot""" + for i in range(len(self.vis_list)): + """Extract records from history logs""" + scatter_data = self.vis_list[i].scatter_data[self.variable] + """Create Histogram object and populate the subfigure using it""" + H = visualisation_distribution_plots.Histogram(scatter_data) + c_xlabel = "" if i < len(self.vis_list) - 1 else xlabel + H.plot(ax=self.ax[i], ylabel="cCDF " + str(i+1) + "RM", xlabel=c_xlabel, color=self.colour_list[i]) + + """Finish and save figure""" + self.fig.tight_layout() + self.fig.savefig(filename + ".pdf") + self.fig.savefig(filename + ".png", density=300) if __name__ == "__main__": @@ -297,7 +407,7 @@ def generate_plot(self, xlabel=None, filename=None): # vis.reinsurer_time_series(runs=[i]) # vis.show() vis_list = [] - filenames = ["./data/"+x+"_history_logs.dat" for x in ["one","two","three","four"]] + filenames = ["./data/" + x + "_history_logs.dat" for x in ["one","two","three","four"]] for filename in filenames: with open(filename,'r') as rfile: history_logs_list = [eval(k) for k in rfile] # one dict on each line @@ -318,3 +428,17 @@ def generate_plot(self, xlabel=None, filename=None): CP.generate_plot() CP = CDF_distribution_plot(vis_list, colour_list, variable="reinsurance_firms_cash", timestep=-1, plot_cCDF=True) CP.generate_plot() + + if args.bankruptcydistribution: + for vis in vis_list: + vis.populate_scatter_data() + HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events") + HP.generate_plot() + HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_relative") + HP.generate_plot() + HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_clustered") + HP.generate_plot() + HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_relative_clustered") + HP.generate_plot() + HP = Histogram_plot(vis_list, colour_list, variable="unrecovered_claims") + HP.generate_plot() From 3e2806f00859f58fd883779b4619ef5e8b084ef0 Mon Sep 17 00:00:00 2001 From: Torsten Date: Tue, 26 Feb 2019 04:00:59 +0000 Subject: [PATCH 5/6] Bugfixes, histograms in log, fixed x axis limits --- visualisation.py | 38 +++++++++++++++++++++-------- visualisation_distribution_plots.py | 16 +++++++++++- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/visualisation.py b/visualisation.py index a9d41c8..3ac5464 100644 --- a/visualisation.py +++ b/visualisation.py @@ -5,7 +5,7 @@ import visualisation_distribution_plots import argparse import pdb - +import isleconfig class TimeSeries(object): def __init__(self, series_list, title="",xlabel="Time", colour='k', axlst=None, fig=None, percentiles=None, alpha=0.7): @@ -340,7 +340,7 @@ def __init__(self, vis_list, colour_list, variable="bankruptcy_events"): self.colour_list = colour_list self.variable = variable - def generate_plot(self, xlabel=None, filename=None): + def generate_plot(self, xlabel=None, filename=None, logscale=False): """Method to generate and save the plot. Arguments: xlabel: str or None - the x axis label @@ -354,6 +354,23 @@ def generate_plot(self, xlabel=None, filename=None): """Create figure with correct number of subplots""" self.fig, self.ax = plt.subplots(nrows=len(self.vis_list)) + #pdb.set_trace() + + """find max and min values""" + """combine all data sets""" + all_data = [np.asarray(vl.scatter_data[self.variable]) for vl in self.vis_list] + all_data = np.hstack(all_data) + + """Catch empty data sets""" + if len(all_data) == 0: + return + #all_data = [] + #for vl in self.vis_list: + # for item in vl.scatter_data[self.variable]: + # all_data += item + minmax = (np.min(all_data), np.max(all_data)) + num_bins = min(25, len(np.unique(all_data))) + """Loop through simulation record series, populate subplot by subplot""" for i in range(len(self.vis_list)): """Extract records from history logs""" @@ -361,7 +378,7 @@ def generate_plot(self, xlabel=None, filename=None): """Create Histogram object and populate the subfigure using it""" H = visualisation_distribution_plots.Histogram(scatter_data) c_xlabel = "" if i < len(self.vis_list) - 1 else xlabel - H.plot(ax=self.ax[i], ylabel="cCDF " + str(i+1) + "RM", xlabel=c_xlabel, color=self.colour_list[i]) + H.plot(ax=self.ax[i], ylabel="Dens. " + str(i+1) + "RM", xlabel=c_xlabel, color=self.colour_list[i], num_bins=num_bins, logscale=logscale, xlims=minmax) """Finish and save figure""" self.fig.tight_layout() @@ -426,19 +443,20 @@ def generate_plot(self, xlabel=None, filename=None): if args.firmdistribution: CP = CDF_distribution_plot(vis_list, colour_list, variable="insurance_firms_cash", timestep=-1, plot_cCDF=True) CP.generate_plot() - CP = CDF_distribution_plot(vis_list, colour_list, variable="reinsurance_firms_cash", timestep=-1, plot_cCDF=True) - CP.generate_plot() + if not isleconfig.simulation_parameters["reinsurance_off"]: + CP = CDF_distribution_plot(vis_list, colour_list, variable="reinsurance_firms_cash", timestep=-1, plot_cCDF=True) + CP.generate_plot() if args.bankruptcydistribution: for vis in vis_list: vis.populate_scatter_data() HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events") - HP.generate_plot() + HP.generate_plot(logscale=True) HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_relative") - HP.generate_plot() + HP.generate_plot(logscale=True) HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_clustered") - HP.generate_plot() + HP.generate_plot(logscale=True) HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_relative_clustered") - HP.generate_plot() + HP.generate_plot(logscale=True) HP = Histogram_plot(vis_list, colour_list, variable="unrecovered_claims") - HP.generate_plot() + HP.generate_plot(logscale=True) diff --git a/visualisation_distribution_plots.py b/visualisation_distribution_plots.py index 5d3daec..34076e9 100644 --- a/visualisation_distribution_plots.py +++ b/visualisation_distribution_plots.py @@ -94,6 +94,10 @@ def plot(self, ax=None, ylabel="CDF(x)", xlabel="y", upper_quantile=.25, lower_q plot_cCDF: bool - plot survival function (cCDF) instead of CDF Returns: None.""" + """If data set is empty, return without plotting""" + if self.samples_x == []: + return + """Create figure if none was provided""" if ax is None: fig = plt.figure() @@ -131,7 +135,7 @@ class Histogram(): def __init__(self, sample_x): self.sample_x = sample_x - def plot(self, ax=None, ylabel="PDF(x)", xlabel="x", num_bins=50, show=False, outputname=None, color="C2"): + def plot(self, ax=None, ylabel="PDF(x)", xlabel="x", num_bins=50, show=False, outputname=None, color="C2", logscale=False, xlims=None): """Method to compile the plot. The plot is added to a provided matplotlib axes object or a new one is created. Arguments: ax: matplitlib axes - the system of coordinates into which to plot @@ -141,6 +145,8 @@ def plot(self, ax=None, ylabel="PDF(x)", xlabel="x", num_bins=50, show=False, ou show: bool - show plot outputname: str - output file name without ending color: str or other admissible matplotlib color label - color to use for the plot + logscale: bool - y axis logscale + xlims: tuple, array of len 2, or none - x axis limits Returns: None.""" """Create figure if none was provided""" @@ -155,6 +161,14 @@ def plot(self, ax=None, ylabel="PDF(x)", xlabel="x", num_bins=50, show=False, ou ax.set_ylabel(ylabel) ax.set_xlabel(xlabel) + """Set xlim if requested""" + if xlims is not None: + ax.set_xlim(xlims[0], xlims[1]) + + """Set yscale to log if requested""" + if logscale: + ax.set_yscale("log") + """Save if filename provided""" if outputname is not None: plt.savefig(outputname + ".pdf") From bab62d05937a3275cf5aaef6cdf59a4e2377ffec Mon Sep 17 00:00:00 2001 From: Torsten Date: Wed, 6 Mar 2019 22:18:25 +0100 Subject: [PATCH 6/6] Fixed x-axis labels in histogram and ccdf plots --- visualisation.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/visualisation.py b/visualisation.py index 3ac5464..b57ce11 100644 --- a/visualisation.py +++ b/visualisation.py @@ -442,21 +442,21 @@ def generate_plot(self, xlabel=None, filename=None, logscale=False): if args.firmdistribution: CP = CDF_distribution_plot(vis_list, colour_list, variable="insurance_firms_cash", timestep=-1, plot_cCDF=True) - CP.generate_plot() + CP.generate_plot(xlabel="Firm size (capital)") if not isleconfig.simulation_parameters["reinsurance_off"]: CP = CDF_distribution_plot(vis_list, colour_list, variable="reinsurance_firms_cash", timestep=-1, plot_cCDF=True) - CP.generate_plot() + CP.generate_plot(xlabel="Firm size (capital)") if args.bankruptcydistribution: for vis in vis_list: vis.populate_scatter_data() HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events") - HP.generate_plot(logscale=True) + HP.generate_plot(logscale=True, xlabel="Number of bankruptcies") HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_relative") - HP.generate_plot(logscale=True) + HP.generate_plot(logscale=True, xlabel="Share of bankrupt firms") HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_clustered") - HP.generate_plot(logscale=True) + HP.generate_plot(logscale=True, xlabel="Number of bankruptcies") HP = Histogram_plot(vis_list, colour_list, variable="bankruptcy_events_relative_clustered") - HP.generate_plot(logscale=True) + HP.generate_plot(logscale=True, xlabel="Share of bankrupt firms") HP = Histogram_plot(vis_list, colour_list, variable="unrecovered_claims") - HP.generate_plot(logscale=True) + HP.generate_plot(logscale=True, xlabel="Damages not recovered")