Exemple #1
0
    def _plot_selection_probabilities(self):
        r"""
        Plot pie charts of the selection probabilities of prospective parents at each generation.
        Models are signified by their F score.
        """
        generations = sorted(
            self.genetic_algorithm.gene_pool.generation.unique())
        self.log_print(
            ["[_plot_selection_probabilities] generations:", generations])
        lf = LatexFigure(auto_gridspec=len(generations))

        for g in generations:
            ax = lf.new_axis()
            this_gen_genes = self.genetic_algorithm.gene_pool[
                self.genetic_algorithm.gene_pool.generation == g]
            f_scores = this_gen_genes.f_score
            colours = [self.f_score_cmap(f) for f in f_scores]
            probabilities = this_gen_genes.probability

            ax.pie(
                probabilities,
                colors=colours,
                radius=2,
            )

        save_to_file = os.path.join(self.save_directory,
                                    "selection_probabilities")
        lf.save(save_to_file, figure_format=self.figure_format)
Exemple #2
0
    def __plot_gene_pool_progression(self, ):
        r"""
        Succinct representation of the progression of gene pool with respect to F score. 
        """
        lf = LatexFigure()
        ax = lf.new_axis()
        gene_pool = self.genetic_algorithm.gene_pool
        gene_pool.sort_values('f_score', inplace=True, ascending=False)

        self.gene_pool_progression(
            gene_pool=gene_pool,
            ax=ax,
            f_score_cmap=self.f_score_cmap,
        )
        lf.save(save_to_file=os.path.join(self.save_directory,
                                          'gene_pool_progression'),
                file_format=self.figure_format)
Exemple #3
0
    def _plot_model_ratings(self, ):
        r"""
        Plot ratings of models on all generations, as determined by the RatingSystem
        """

        plt.clf()
        ratings = self.ratings_class.all_ratings
        generations = [int(g) for g in ratings.generation.unique()]
        num_generations = len(generations)

        lf = LatexFigure(use_gridspec=True,
                         gridspec_layout=(num_generations, 1))

        # TODO : unique linestyle and colour combo for each model ID and tracks across subplots
        ratings["Model ID"] = ratings["model_id"]

        for gen in generations:
            ax = lf.new_axis()

            this_gen_ratings = ratings[ratings.generation == gen]
            colours = {
                m: self.f_score_cmap(self.model_f_scores[m])
                for m in this_gen_ratings["model_id"]
            }
            sns.lineplot(
                x="idx",
                y="rating",
                hue=r"Model ID",
                hue_order=sorted(this_gen_ratings.model_id.unique()),
                data=this_gen_ratings,
                ax=ax,
                legend="full",
                palette=colours,
            )

            ax.set_title("Generation {}".format(gen), pad=-15)
            ax.set_xlabel("")
            ax.set_ylabel("Elo rating")
            ax.legend(bbox_to_anchor=(1, 1))

        save_to_file = os.path.join(self.save_directory,
                                    "ratings".format(self.qmla_id))

        lf.save(save_to_file, file_format=self.figure_format)
    def plot_heuristic_attributes(self, save_to_file, **kwargs):
        """
        Summarise the heuristic used for the model training through several plots.

            volume of distribution at each experiment

            time designed by heuristic for each experiment

            effecitve sample size at each experiment, used to determine when to resample

        :param save_to_file: path to which the summary figure is stored
        :type save_to_file: path
        """

        plots_to_include = ["volume", "times_used", "effective_sample_size"]

        plt.clf()
        nrows = len(plots_to_include)
        lf = LatexFigure(gridspec_layout=(nrows, 1))

        if "volume" in plots_to_include:
            ax = lf.new_axis()
            self._plot_volumes(ax=ax)
            ax.legend()

        if "times_used" in plots_to_include:
            ax = lf.new_axis()
            self._plot_suggested_times(ax=ax)
            ax.legend()

        if "effective_sample_size" in plots_to_include:
            ax = lf.new_axis()
            self._plot_effective_sample_size(ax=ax)
            ax.legend()

        # Save figure
        self.log_print(["LatexFigure has size:", lf.size])
        lf.save(save_to_file, file_format=self._figure_format)
    def plot_heuristic_attributes(self, save_to_file, **kwargs):
        """Plot results related to the experiment design heuristic.
        Plots

            times generated by the heuristic;

            metric distances: distance between the two sampled particles under various measures;

            volume of the parameter distribution at each experiment.

        :param save_to_file: path to which to save the resultant figure.
        :type save_to_file: path
        """

        plots_to_include = [
            "volume",
            "metric_distances",
            "times_used",  #'derivatives',
        ]

        plt.clf()
        nrows = len(plots_to_include)
        lf = LatexFigure(gridspec_layout=(nrows, 1))

        # Volume
        if "volume" in plots_to_include:
            ax = lf.new_axis()
            self._plot_volumes(ax=ax)
            self.add_time_factor_change_points_to_ax(ax=ax)
            ax.legend()

        if "times_used" in plots_to_include:
            ax = lf.new_axis()

            self._plot_suggested_times(ax=ax)
            self.add_time_factor_change_points_to_ax(ax=ax)
            ax.legend()

        if "derivatives" in plots_to_include:
            # Volume Derivatives
            ax = lf.new_axis()
            ## first derivatives
            derivs = self.derivatives[1]
            epochs = sorted(derivs.keys())
            first_derivatives = [
                derivs[e] if e in derivs else None for e in epochs
            ]
            ax.plot(
                epochs,
                first_derivatives,
                label=r"$\frac{dV}{dE}$",
                color="darkblue",
                marker="x",
            )

            ## second derivatives
            derivs = self.derivatives[2]
            epochs = sorted(derivs.keys())
            second_derivatives = [
                derivs[e] if e in derivs else None for e in epochs
            ]
            ax.plot(
                epochs,
                second_derivatives,
                label=r"$\frac{d^2V}{dE^2}$",
                color="maroon",
                marker="+",
            )

            ax.axhline(0, ls="--", alpha=0.3)
            ax.legend(loc="upper right")
            ax.set_yscale("symlog")
            ax.set_ylabel("Derivatives", fontsize=self._label_fontsize)
            ax.set_xlabel("Epoch", fontsize=self._label_fontsize)

            if len(self.time_factor_changes["decreasing"]) > 0:
                ax.axvline(
                    self.time_factor_changes["decreasing"][0],
                    ls="--",
                    color="red",
                    label="decrease k",
                    alpha=0.5,
                )

                for e in self.time_factor_changes["decreasing"][1:]:
                    ax.axvline(e, ls="--", color="red", alpha=0.5)
            if len(self.time_factor_changes["increasing"]) > 0:
                ax.axvline(
                    self.time_factor_changes["increasing"][0],
                    ls="--",
                    color="green",
                    label="increase k",
                    alpha=0.5,
                )

                for e in self.time_factor_changes["increasing"][1:]:
                    ax.axvline(e, ls="--", color="green", alpha=0.5)
            ax.legend(loc="lower right")

        if "metric_distances" in plots_to_include:
            # Times by distance metrics
            ax = lf.new_axis()

            linestyles = itertools.cycle(["--", ":", "-."])
            for method in self.designed_times:
                times_of_method = self.designed_times[method]
                epochs = sorted(times_of_method.keys())
                time_by_epoch = [times_of_method[e] for e in epochs]

                lb = method
                if self.distance_metric_to_use == method:
                    ls = "-"
                    lb += " (used)"
                    alpha = 1
                else:
                    ls = next(linestyles)
                    alpha = 0.75

                ax.plot(epochs, time_by_epoch, label=lb, ls=ls, alpha=alpha)
            ax.legend(title="Distance metric")
            ax.set_title("Raw time chosen by distance metrics",
                         fontsize=self._label_fontsize)
            ax.set_ylabel("Time", fontsize=self._label_fontsize)
            ax.set_xlabel("Epoch", fontsize=self._label_fontsize)
            ax.semilogy()

        # Save figure
        self.log_print(["LatexFigure has size:", lf.size])
        lf.save(save_to_file, file_format=self._figure_format)
    def plot_heuristic_attributes(self, save_to_file, **kwargs):
        """Plot results related to the experiment design heuristic.
        Plots

            times generated by the heuristic;

            metric distances: distance between the two sampled particles under various measures;

            volume of the parameter distribution at each experiment.

        :param save_to_file: path to which to save the resultant figure.
        :type save_to_file: path
        """

        plots_to_include = [
            'volume',
            'metric_distances',
            'times_used',  #'derivatives',
        ]

        plt.clf()
        nrows = len(plots_to_include)
        lf = LatexFigure(gridspec_layout=(nrows, 1))

        # Volume
        if 'volume' in plots_to_include:
            ax = lf.new_axis()
            self._plot_volumes(ax=ax)
            self.add_time_factor_change_points_to_ax(ax=ax)
            ax.legend()

        if 'times_used' in plots_to_include:
            ax = lf.new_axis()

            self._plot_suggested_times(ax=ax)
            self.add_time_factor_change_points_to_ax(ax=ax)
            ax.legend()

        if 'derivatives' in plots_to_include:
            # Volume Derivatives
            ax = lf.new_axis()
            ## first derivatives
            derivs = self.derivatives[1]
            epochs = sorted(derivs.keys())
            first_derivatives = [
                derivs[e] if e in derivs else None for e in epochs
            ]
            ax.plot(epochs,
                    first_derivatives,
                    label=r"$\frac{dV}{dE}$",
                    color='darkblue',
                    marker='x')

            ## second derivatives
            derivs = self.derivatives[2]
            epochs = sorted(derivs.keys())
            second_derivatives = [
                derivs[e] if e in derivs else None for e in epochs
            ]
            ax.plot(epochs,
                    second_derivatives,
                    label=r"$\frac{d^2V}{dE^2}$",
                    color='maroon',
                    marker='+')

            ax.axhline(0, ls='--', alpha=0.3)
            ax.legend(loc='upper right')
            ax.set_yscale('symlog')
            ax.set_ylabel('Derivatives', fontsize=self._label_fontsize)
            ax.set_xlabel('Epoch', fontsize=self._label_fontsize)

            if len(self.time_factor_changes['decreasing']) > 0:
                ax.axvline(self.time_factor_changes['decreasing'][0],
                           ls='--',
                           color='red',
                           label='decrease k',
                           alpha=0.5)

                for e in self.time_factor_changes['decreasing'][1:]:
                    ax.axvline(e, ls='--', color='red', alpha=0.5)
            if len(self.time_factor_changes['increasing']) > 0:
                ax.axvline(self.time_factor_changes['increasing'][0],
                           ls='--',
                           color='green',
                           label='increase k',
                           alpha=0.5)

                for e in self.time_factor_changes['increasing'][1:]:
                    ax.axvline(e, ls='--', color='green', alpha=0.5)
            ax.legend(loc='lower right')

        if 'metric_distances' in plots_to_include:
            # Times by distance metrics
            ax = lf.new_axis()

            linestyles = itertools.cycle(['--', ':', '-.'])
            for method in self.designed_times:
                times_of_method = self.designed_times[method]
                epochs = sorted(times_of_method.keys())
                time_by_epoch = [times_of_method[e] for e in epochs]

                lb = method
                if self.distance_metric_to_use == method:
                    ls = '-'
                    lb += ' (used)'
                    alpha = 1
                else:
                    ls = next(linestyles)
                    alpha = 0.75

                ax.plot(epochs, time_by_epoch, label=lb, ls=ls, alpha=alpha)
            ax.legend(title='Distance metric')
            ax.set_title('Raw time chosen by distance metrics',
                         fontsize=self._label_fontsize)
            ax.set_ylabel('Time', fontsize=self._label_fontsize)
            ax.set_xlabel('Epoch', fontsize=self._label_fontsize)
            ax.semilogy()

        # Save figure
        self.log_print(["LatexFigure has size:", lf.size])
        lf.save(save_to_file, file_format=self._figure_format)
def plot_dynamics_from_models(models,
                              exp_msmts,
                              bf_times,
                              bayes_factor,
                              save_directory,
                              figure_format="png"):
    """Plot the dynamics of the pair of models considered in a Bayes factor comparison. 

    :param models: list of 2 models which were compared during this calculation, [model_a, model_b].
    :type models: :class:`~qmla.ModelInstanceForLearning`
    :param exp_msmts: times and expectation values for the system. 
    :type exp_msmts: dict
    :param bf_times: Times used for the BF calculation
    :type bf_times: list
    :param bayes_factor: Bayes factor between the two input models, to be read as BF(model_a, model_b)
    :type bayes_factor: float
    :param save_directory: path where the generated figure is to be saved
    :type save_directory: path
    """

    times = list(sorted(exp_msmts.keys()))
    lf = LatexFigure(fraction=0.45, auto_label=False)
    ax1 = lf.new_axis()
    lines = []

    for model in models:
        l = model.plot_dynamics(ax=ax1, times=times)
        lines.extend(l)
    ax1.set_xlim((min(times), max(times)))

    # Plot system measurements
    l = ax1.scatter(times, [exp_msmts[t] for t in times],
                    label=r"$Q$",
                    color='red',
                    alpha=0.6,
                    s=5)
    lines.append(l)

    # Overlay times
    try:
        # in background, show how often that time was considered
        ax2 = ax1.twinx()
        num_times = int(len(times)) - 1
        l = ax2.hist(
            bf_times,
            bins=num_times,
            # TODO put on separate plot to see when higher times compared on
            range=(min(times), max(times)),
            histtype='stepfilled',
            fill=False,
            label=r"$t$",
            alpha=0.25)
        ax2.set_ylabel('Frequency')
        max_freq = max(l[0])
        ax2.set_ylim(0, 1.6 * max_freq)
        ax2.set_yticks([0, int(max_freq / 2), max_freq])

        lines.append(l[-1][0])
    except BaseException:
        raise
        # pass

    bf = np.log10(bayes_factor)
    labels = [l.get_label() for l in lines]
    ax1.set_ylim(0, 1.6)
    ax1.set_yticks([0, 0.5, 1])
    ax1.set_ylabel('Expectation Value')
    ax1.set_xlabel("Time")

    ax1.legend(lines, labels, ncol=2, loc="upper center")

    plot_path = os.path.join(
        save_directory, 'BF_{}_{}'.format(str(models[0].model_id),
                                          str(models[1].model_id)))
    # plt.savefig(plot_path)
    lf.save(plot_path, file_format=figure_format)
Exemple #8
0
def plot_qmla_branches(q, show_fscore_cmap=False, return_graphs=False):
    trees = list(q.trees.values())
    q.log_print(["Plotting QMLA branch graphs. Trees:", trees])
    plt.rcParams.update(
        get_latex_rc_params(
            font_scale=1.5,
        )
    )

    for tree in trees:
        # tree = trees[0] # TODO loop over trees
        q.log_print(["Working on tree ", tree.exploration_strategy])
        graphs = {}

        branches = [tree.branches[b] for b in sorted(tree.branches.keys())]
        if len(branches) > 1:
            branches = branches[:-1]

        num_branches = len(branches)
        ncols = int(np.ceil(np.sqrt(num_branches)))
        if num_branches == 1:
            ncols = 1
            nrows = 1
        elif num_branches == 2:
            ncols = 1
            nrows = 2
        else:
            nrows = int(np.ceil(num_branches / ncols))

        # Generate plot
        widths = [1] * ncols
        widths.append(0.1)
        if show_fscore_cmap:
            widths.append(0.1)
        total_ncols = len(widths)

        size_scaler = min(2, 4 / num_branches)
        label_fontsize = 15 * size_scaler

        lf = LatexFigure(
            auto_label=False,
            gridspec_layout=(nrows, total_ncols),
            gridspec_params={
                "width_ratios": widths,
                "wspace": 0.3,
                "hspace": 0.2,
            },
        )

        # colour maps
        f_score_cmap = q.exploration_class.f_score_cmap
        bf_cmap = q.exploration_class.bf_cmap
        min_bf = q.bayes_factors_df.log10_bayes_factor.min()
        max_bf = q.bayes_factors_df.log10_bayes_factor.max()
        norm = plt.Normalize(vmin=min_bf, vmax=max_bf)
        bf_cmapper = plt.cm.ScalarMappable(norm=norm, cmap=bf_cmap)
        bf_cmapper.set_array([])  # still no idea what this is for??

        # BF cmap
        cbar_ax = lf.new_axis(
            force_position=(0, total_ncols - 1 - int(show_fscore_cmap)), span=("all", 1)
        )
        lf.fig.colorbar(bf_cmapper, cax=cbar_ax, ticks=[min_bf, 0, max_bf])
        cbar_ax.set_title(r"$\\log_{10}(BF)$", loc="center")
        cbar_ax.yaxis.set_ticks_position("left")

        # F score cmap
        if show_fscore_cmap:
            ax = lf.new_axis(force_position=[0, total_ncols - 1], span=("all", 1))

            sm = plt.cm.ScalarMappable(
                cmap=f_score_cmap, norm=plt.Normalize(vmin=0, vmax=1)
            )
            sm.set_array([])
            lf.fig.colorbar(
                sm,
                cax=ax,
                orientation="vertical",
                label=r"$F_1$-score",
                ticks=[0, 0.5, 1],
            )
            # ax.set_ylabel(
            #     r"F-score",
            # )
            # ax.set_yticks([0, 0.5, 1])

        # Plot graphs

        min_seen_bf = 0
        max_seen_bf = 0
        for branch in branches:
            ax = lf.new_axis()

            models = branch.models.keys()
            pairs = branch.pairs_to_compare

            graph = nx.Graph()
            for m in models:
                graph.add_node(
                    m,
                    model_id=int(m),
                    model_name=branch.models[m],
                    f_score=q.model_f_scores[m],
                    colour=f_score_cmap(q.model_f_scores[m]),
                    longest_path_to_any_target=0,
                )

            for edge in pairs:
                e = (min(edge), max(edge))  # edges go A->B low -> high
                bf = q.all_bayes_factors[e[0]][e[1]][-1]
                lbf = np.log10(bf)
                colour = bf_cmapper.to_rgba(lbf)
                graph.add_edge(e[0], e[1], log_bf=lbf, colour=colour)

            pos = nx.kamada_kawai_layout(graph)  # could use spring_layout or other
            labels = nx.get_node_attributes(graph, "model_id")
            node_colours = [graph.nodes[m]["colour"] for m in models]
            edge_colours = [graph.edges[e]["colour"] for e in graph.edges]

            nx.draw_networkx_nodes(
                graph,
                pos,
                alpha=0.7,
                node_color=node_colours,
                node_size=400 * size_scaler,
                ax=ax,
            )
            nx.draw_networkx_labels(graph, pos, labels, font_size=label_fontsize, ax=ax)

            nx.draw_networkx_edges(
                graph,
                pos,
                edgelist=graph.edges,
                edge_color=edge_colours,
                ax=ax,
                alpha=1,
                width=4,
            )

            # summarise this graph in a text box
            node_edges = {n: len(graph.edges(n)) for n in graph.nodes}
            lowest_connectivity = min(node_edges.values())
            highest_connectivity = max(node_edges.values())

            for n in graph:
                for target in graph:
                    if n != target:
                        try:
                            shortest_path = nx.shortest_path_length(
                                graph, source=n, target=target
                            )
                        except:
                            # can't connect to some other node
                            shortest_path = -1

                        this_node_current_longest_path = graph.nodes[n][
                            "longest_path_to_any_target"
                        ]
                        if shortest_path > this_node_current_longest_path:
                            graph.nodes[n]["longest_path_to_any_target"] = shortest_path

            distance_between_nodes = [
                graph.nodes[n]["longest_path_to_any_target"] for n in graph.nodes
            ]

            lowest_distance_between_nodes = min(distance_between_nodes)
            highest_distance_between_nodes = max(distance_between_nodes)

            short_summary = "{}".format(
                branch.branch_id,
            )
            summary = "Branch {} \n{} models \n {} edges\n ${} \leq  C \leq{}$\n $d \leq {}$".format(
                branch.branch_id,
                len(graph.nodes),
                len(graph.edges),
                lowest_connectivity,
                highest_connectivity,
                highest_distance_between_nodes,
            )
            props = dict(boxstyle="round", facecolor="wheat", alpha=0.5)

            ax.text(
                -0.05,
                0.95,
                short_summary,  # summary,
                transform=ax.transAxes,
                # fontsize = label_fontsize,
                bbox=props,
                ha="center",
                va="center",
            )
            ax.axis("off")

            graphs[branch.branch_id] = graph

        # Save figure
        save_file = "graphs_of_branches_{}".format(tree.exploration_strategy)
        q.log_print(["Storing ", save_file])
        lf.save(
            os.path.join(q.qmla_controls.plots_directory, save_file),
            file_format=q.qmla_controls.figure_format,
        )
Exemple #9
0
    def plot_rating_progress_single_model_static(
        ratings_df, target_model_id, return_df=False, return_lf=None, save_to_file=None
    ):
        # First isolate the ratings for this model
        model_identifiers = ["a", "b"]
        ratings_of_single_model = pd.DataFrame(
            columns=[
                "target",
                "opponent",
                "initial_rating_target",
                "initial_rating_opponent",
                "f_score_target",
                "f_score_opponent",
                "delta_r_target",
                "final_rating_target",
                "idx",
                "bayes_factor",
                "generation",
                "weight",
            ]
        )
        for target in model_identifiers:
            opponent = list(set(model_identifiers) - set(target))[0]

            target_ratings = ratings_df[
                ratings_df["model_{}".format(target)] == target_model_id
            ][
                [
                    "model_{}".format(target),
                    "model_{}".format(opponent),
                    "r_{}_initial".format(target),
                    "r_{}_initial".format(opponent),
                    "f_score_{}".format(target),
                    "f_score_{}".format(opponent),
                    "delta_r_{}".format(target),
                    "r_{}_new".format(target),
                    "idx",
                    "bayes_factor",
                    "generation",
                    "weight",
                    "winner",
                ]
            ]

            target_ratings.rename(
                columns={
                    "model_{}".format(target): "target",
                    "model_{}".format(opponent): "opponent",
                    "r_{}_initial".format(target): "initial_rating_target",
                    "r_{}_initial".format(opponent): "initial_rating_opponent",
                    "f_score_{}".format(target): "f_score_target",
                    "f_score_{}".format(opponent): "f_score_opponent",
                    "r_{}_new".format(target): "final_rating_target",
                    "delta_r_{}".format(target): "delta_r_target",
                },
                inplace=True,
            )

            ratings_of_single_model = ratings_of_single_model.append(
                target_ratings, ignore_index=True
            )

        ratings_of_single_model["won_comparison"] = (
            ratings_of_single_model.winner == ratings_of_single_model.target
        )
        ratings_of_single_model.won_comparison.replace(
            {True: "Won", False: "Lost"}, inplace=True
        )
        ratings_of_single_model.sort_values("idx", inplace=True)
        ratings_of_single_model["new_idx"] = list(range(len(ratings_of_single_model)))

        # Plot 3 perspectives on this data:
        # 1. How rating changes
        # 2. relative change per comparison
        # 3. strength of evidence each comparison

        plots_to_include = ["ratings_progress", "delta_r", "bf"]
        include_f_ax = True

        lf = LatexFigure(
            fraction=0.9,
            use_gridspec=True,
            gridspec_layout=(len(plots_to_include), 1),
            gridspec_params={"height_ratios": [0.35, 0.95, 0.35]},
        )

        if "bf" in plots_to_include:

            # Bayes factor comparisons
            ax2 = lf.new_axis()
            sns.barplot(
                data=ratings_of_single_model,
                y="weight",
                x="new_idx",
                hue="won_comparison",
                palette={"Won": "green", "Lost": "purple"},
                dodge=False,
                ax=ax2,
            )
            ax2.legend(title=None, loc="upper left")
            ax2.set_ylabel(r"$\left| \log_{10}(B_{ij}) \right|$")

            generations = ratings_of_single_model.generation.unique()
            generation_change_indices = {
                g: ratings_of_single_model[
                    ratings_of_single_model.generation == g
                ].new_idx.max()
                + 0.5
                for g in generations
            }

        # Actual ratings
        if "ratings_progress" in plots_to_include:
            ax0 = lf.new_axis(ax_params={"sharex": ax2})
            sns.scatterplot(
                data=ratings_of_single_model,
                x="new_idx",
                y="initial_rating_target",
                label=r"$\hat{H}_i$ \ before",
                color="green",
                marker="x",
                s=50,
                ax=ax0,
            )

            sns.lineplot(
                data=ratings_of_single_model,
                x="new_idx",
                y="final_rating_target",
                label=r"$\hat{H}_i$ \ after",
                color="green",
                ax=ax0,
            )

            sns.scatterplot(
                x="new_idx",
                y="initial_rating_opponent",
                data=ratings_of_single_model,
                label=r"$\hat{H}_j$",
                color="purple",
                marker="+",
                s=50,
                ax=ax0,
            )
            ax0.legend()
            ax0.set_ylabel("Rating")
            ax0.set_xticks([])
            ax0.set_xlabel("")
            ax0.legend(title="Ratings", loc="upper left", ncol=3)

        if include_f_ax:
            f_score_ax = ax0.twinx()
            sns.scatterplot(
                x="new_idx",
                y="f_score_opponent",
                data=ratings_of_single_model,
                label=r"$\hat{H}_j$",
                marker="d",
                s=50,
                color="purple",
                ax=f_score_ax,
            )
            target_f_score = ratings_of_single_model.f_score_target.values[0]
            f_score_ax.axhline(
                target_f_score,
                color="green",
                ls="--",
                label=r"$\hat{H}_i$",
            )
            f_score_ax.set_ylabel(r"$F_1$-score")

            f_score_ax.legend(title=r"$F_1$-score", loc="lower left", ncol=2)
            f_score_ax.set_ylim(-0.1, 1.1)
            f_score_ax.set_yticks([0, 0.5, 1])

        if "delta_r" in plots_to_include:
            ax1 = lf.new_axis(ax_params={"sharex": ax2})
            sns.barplot(
                data=ratings_of_single_model,
                y="delta_r_target",
                x="new_idx",
                hue="won_comparison",
                palette={"Won": "green", "Lost": "purple"},
                dodge=False,
                ax=ax1,
            )
            ax1.set_ylabel(r"$\Delta R_i$")
            ax1.set_xticks([])
            ax1.set_xlabel("")
            ax1.get_legend().remove()

        for ax in lf.gridspec_axes.values():
            ax.set_xlabel("")
            ax.set_xticks([])

        bottom_ax = lf.gridspec_axes[(lf.num_rows - 1, 0)]
        if len(generations) > 1:
            # vertical lines separating generations
            for ax in lf.gridspec_axes.values():
                for g in generation_change_indices.values():
                    ax.axvline(
                        g,
                        ls="--",
                        c="grey",
                        alpha=0.6,
                    )

            # label x-axis with generations
            xtick_locations = [generation_change_indices[g] for g in generations]
            xtick_locations.insert(0, 0)
            centred_xticks = [
                np.mean([xtick_locations[i], xtick_locations[i + 1]])
                for i in range(len(xtick_locations) - 1)
            ]

            bottom_ax.set_xticklabels(generations)
            bottom_ax.set_xticks(centred_xticks)
            bottom_ax.set_xlabel("Generation")
        else:
            bottom_ax.set_xticks(
                range(len(ratings_of_single_model["new_idx"])),
            )
            bottom_ax.set_xticklabels(
                range(1, 1 + len(ratings_of_single_model["new_idx"]))
            )
            bottom_ax.set_xlabel("Comparison")

        if save_to_file is not None:
            lf.save(save_to_file)
        if return_df:
            return ratings_of_single_model
Exemple #10
0
    def plot_models_ratings_against_generation(
        self,
        f_scores,
        f_score_cmap,
        save_directory,
        show_fscore_cmap=False,
        figure_format="png",
    ):
        self.figure_format = figure_format

        all_model_ratings_by_generation = pd.DataFrame()
        models = self.all_ratings.model_id.unique()

        for model in models:
            model_ratings = self.all_ratings[self.all_ratings.model_id == model]
            generations = model_ratings.generation.unique()

            for g in generations:
                mod_ratings_this_generation = model_ratings[
                    model_ratings.generation == g
                ]

                start_idx = mod_ratings_this_generation.idx.min()
                final_idx = mod_ratings_this_generation.idx.max()

                start_rating = self.all_ratings[
                    (self.all_ratings.model_id == model)
                    & (self.all_ratings.generation == g)
                    & (self.all_ratings.idx == start_idx)
                ].rating.item()
                final_rating = self.all_ratings[
                    (self.all_ratings.model_id == model)
                    & (self.all_ratings.generation == g)
                    & (self.all_ratings.idx == final_idx)
                ].rating.item()

                new_data = [
                    pd.Series(
                        {"model_id": model, "generation": g, "rating": start_rating}
                    ),
                    pd.Series(
                        {
                            "model_id": model,
                            "generation": g + 0.8,
                            "rating": final_rating,
                        }
                    ),
                ]

                for d in new_data:
                    all_model_ratings_by_generation = (
                        all_model_ratings_by_generation.append(d, ignore_index=True)
                    )

        # First prepare a dictionary to map model id to a colour corresponding to F-score
        f_granularity = 0.05
        available_f_scores = np.linspace(0, 1, 1 + (1 / f_granularity))

        model_coloured_by_f = {
            # m : colour_by_f[ qmla.utilities.round_nearest(f_scores[m], f_granularity) ]
            m: f_score_cmap(f_scores[m])
            for m in all_model_ratings_by_generation.model_id.unique()
        }

        # Plot
        widths = [1]
        if show_fscore_cmap:
            widths.append(0.1)
            legend_axis = (0, 1)
        else:
            legend_axis = None
        lf = LatexFigure(
            # via https://github.com/flynnbr11/lfig-py
            use_gridspec=True,
            gridspec_layout=(1, len(widths)),
            gridspec_params={
                "width_ratios": widths,
            },
            legend_axis=legend_axis,
        )
        ax = lf.new_axis()
        sns.lineplot(
            x="generation",
            y="rating",
            hue="model_id",
            data=all_model_ratings_by_generation,
            palette=model_coloured_by_f,
            legend=False,
            ax=ax,
        )
        for g in self.all_ratings.generation.unique():
            ax.axvline(g, ls="--", c="black")
        ax.axhline(self.initial_rating, ls=":", color="black")

        label_fontsize = 25
        ax.set_xlabel(
            "Generation",
            # fontsize = label_fontsize
        )
        ax.set_ylabel(r"$R$")
        ax.set_xticks(list(self.all_ratings.generation.unique()))

        if show_fscore_cmap:
            ax = lf.legend_ax
            sm = plt.cm.ScalarMappable(
                cmap=f_score_cmap, norm=plt.Normalize(vmin=0, vmax=1)
            )
            sm.set_array(available_f_scores)
            plt.colorbar(sm, cax=ax, orientation="vertical")
            ax.set_ylabel(
                "F-score",
                # fontsize=label_fontsize
            )

        lf.save(
            os.path.join(save_directory, "elo_ratings_of_all_models"),
            file_format=self.figure_format,
        )