From 0b5427f4870887388add3a3e352802a4ef101637 Mon Sep 17 00:00:00 2001 From: Marc Harper Date: Sun, 11 Oct 2015 23:02:41 -0700 Subject: [PATCH 1/6] Plot for distribution of wins --- axelrod/plot.py | 42 ++++++++++++++++++++++++++++++++++- axelrod/tournament_manager.py | 2 +- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/axelrod/plot.py b/axelrod/plot.py index 0a6341a60..860fdfafc 100644 --- a/axelrod/plot.py +++ b/axelrod/plot.py @@ -1,3 +1,5 @@ +import numpy + matplotlib_installed = True try: import matplotlib.pyplot as plt @@ -11,7 +13,6 @@ class Plot(object): def __init__(self, result_set): self.result_set = result_set - # self._nplayers = self.result_set.nplayers self.matplotlib_installed = matplotlib_installed @property @@ -55,6 +56,45 @@ def boxplot(self): plt.title(self._boxplot_title) return figure + @property + def _winplot_dataset(self): + # Sort wins by median + wins = self.result_set.wins + ranked_names = self.result_set.ranked_names + medians = map(numpy.median, wins) + players = self.result_set.players + medians = sorted([(m, i) for (i, m) in enumerate(medians)], reverse=True) + # Reorder and grab names + wins = [wins[x[1]] for x in medians] + ranked_names = [str(players[x[1]]) for x in medians] + #zipped = [(wins[i], str(self.players[i])) for (m, i) in medians] + #wins, ranked_names = zip(*zipped) # unzip! + return wins, ranked_names + + @property + def _winplot_title(self): + return ("Distribution of wins" + " {} turns repeated {} times ({} strategies)").format( + self.result_set.turns, + self.result_set.repetitions, + len(self.result_set.ranking)) + + def winplot(self): + if not self.matplotlib_installed: + return None + + wins, ranked_names = self._winplot_dataset + + figure = plt.figure() + plt.boxplot(wins) + plt.xticks( + self._boxplot_xticks_locations, + ranked_names, + rotation=90) + plt.tick_params(axis='both', which='both', labelsize=7) + plt.title(self._winplot_title) + return figure + def payoff(self): if not self.matplotlib_installed: diff --git a/axelrod/tournament_manager.py b/axelrod/tournament_manager.py index c12a8b406..7d00ee97b 100644 --- a/axelrod/tournament_manager.py +++ b/axelrod/tournament_manager.py @@ -126,7 +126,7 @@ def _save_plots(self, tournament, ecosystem=None, image_format="svg"): self._logger.error('The matplotlib library is not installed. ' 'No plots will be produced') return - for plot_type in ('boxplot', 'payoff'): + for plot_type in ('boxplot', 'payoff', 'winplot'): figure = getattr(plot, plot_type)() file_name = self._output_file_path( tournament.name + '_' + plot_type, image_format) From 5ffb8fbbd5ba98337fa965e347a57a58bb467ba9 Mon Sep 17 00:00:00 2001 From: Marc Harper Date: Sun, 11 Oct 2015 23:03:35 -0700 Subject: [PATCH 2/6] Remove commented lines --- axelrod/plot.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/axelrod/plot.py b/axelrod/plot.py index 860fdfafc..fa8e6301a 100644 --- a/axelrod/plot.py +++ b/axelrod/plot.py @@ -67,8 +67,6 @@ def _winplot_dataset(self): # Reorder and grab names wins = [wins[x[1]] for x in medians] ranked_names = [str(players[x[1]]) for x in medians] - #zipped = [(wins[i], str(self.players[i])) for (m, i) in medians] - #wins, ranked_names = zip(*zipped) # unzip! return wins, ranked_names @property From a395fa4aa4f778becd9b93b5ebf64776320ea30b Mon Sep 17 00:00:00 2001 From: Marc Harper Date: Mon, 12 Oct 2015 09:27:40 -0700 Subject: [PATCH 3/6] Cleanup --- axelrod/plot.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/axelrod/plot.py b/axelrod/plot.py index fa8e6301a..cd65763c3 100644 --- a/axelrod/plot.py +++ b/axelrod/plot.py @@ -60,9 +60,8 @@ def boxplot(self): def _winplot_dataset(self): # Sort wins by median wins = self.result_set.wins - ranked_names = self.result_set.ranked_names - medians = map(numpy.median, wins) players = self.result_set.players + medians = map(numpy.median, wins) medians = sorted([(m, i) for (i, m) in enumerate(medians)], reverse=True) # Reorder and grab names wins = [wins[x[1]] for x in medians] @@ -71,7 +70,7 @@ def _winplot_dataset(self): @property def _winplot_title(self): - return ("Distribution of wins" + return ("Distributions of wins:" " {} turns repeated {} times ({} strategies)").format( self.result_set.turns, self.result_set.repetitions, From 52f6349b766fcfcbe45ab7df448149e4eaccb4f5 Mon Sep 17 00:00:00 2001 From: Marc Harper Date: Mon, 12 Oct 2015 09:44:23 -0700 Subject: [PATCH 4/6] Update docs with Win plots --- axelrod/plot.py | 2 + .../_static/usage/demo_strategies_winplot.svg | 1287 +++++++++++++++++ docs/usage.rst | 47 + 3 files changed, 1336 insertions(+) create mode 100644 docs/_static/usage/demo_strategies_winplot.svg diff --git a/axelrod/plot.py b/axelrod/plot.py index cd65763c3..a69c735d5 100644 --- a/axelrod/plot.py +++ b/axelrod/plot.py @@ -81,6 +81,7 @@ def winplot(self): return None wins, ranked_names = self._winplot_dataset + maximum = max(max(w) for w in wins) figure = plt.figure() plt.boxplot(wins) @@ -90,6 +91,7 @@ def winplot(self): rotation=90) plt.tick_params(axis='both', which='both', labelsize=7) plt.title(self._winplot_title) + plt.ylim(-0.5, 0.5 + maximum) return figure def payoff(self): diff --git a/docs/_static/usage/demo_strategies_winplot.svg b/docs/_static/usage/demo_strategies_winplot.svg new file mode 100644 index 000000000..d38fe3061 --- /dev/null +++ b/docs/_static/usage/demo_strategies_winplot.svg @@ -0,0 +1,1287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/usage.rst b/docs/usage.rst index b4d099e29..1054fc6ce 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -303,6 +303,27 @@ The resulting wins matrix is:: which shows, for example, that Cooperator had 0 wins, Defector won 8 times in each repetition and Random won 4 times in the first repetition and twice in the second. +For any tournament, a plot of the distribution of wins is created, much like the +plot for the distribution of mean scores. For the demo strategies we create the +plot as follows:: + + import axelrod + strategies = [s() for s in axelrod.demo_strategies] + tournament = axelrod.Tournament(strategies, game=Game(30, 0, 50, 10)) + results = tournament.play() + plot = axelrod.Plot(results) + p = plot.winplot() + p.show() + +This produces: + +.. image:: _static/usage/demo_strategies_winplot.svg + :width: 50% + :align: center + +In this case most of the strategies are deterministic, so there is not much +variation in the distributions. See below for a more complex example. + Noisy Tournaments ^^^^^^^^^^^^^^^^^ @@ -365,6 +386,25 @@ and accordingly to the ranking of strategies overall: | |boxplot_no_noise| | |boxplot_5_noise| | +--------------------+-------------------+ +as well as the distributions of wins: + +and accordingly to the ranking of strategies overall: + +.. |winplot_no_noise| image:: http://axelrod-python.github.io/tournament/assets/strategies_winplot.svg + :width: 75% + :align: middle + :alt: Strategy performance without noise + +.. |winplot_5_noise| image:: http://axelrod-python.github.io/tournament/assets/strategies_winplot_noise_5.svg + :width: 75% + :align: middle + :alt: Strategy performance with 5% noise + ++--------------------+-------------------+ +| |winplot_no_noise| | |winplot_5_noise| | ++--------------------+-------------------+ + + To run a noisy tournament, just use the keyword argument `noise` when creating tournaments. Both `run_axelrod` and the utility function `run_tournaments` accept and passthrough the noise argument. To run the @@ -528,6 +568,13 @@ The results from the tournament itself (ordered by median score): :width: 50% :align: center +The distributions of head-to-head wins for each strategy: + +.. image:: http://axelrod-python.github.io/tournament/assets/strategies_winplot.svg + :width: 50% + :align: center + + The payoff matrix from that tournament: .. image:: http://axelrod-python.github.io/tournament/assets/strategies_payoff.svg From 79f3f40dedbaeafbe44a3949f7d5426e3107de0d Mon Sep 17 00:00:00 2001 From: Marc Harper Date: Mon, 12 Oct 2015 10:52:45 -0700 Subject: [PATCH 5/6] Tests for Win Plot --- axelrod/tests/unit/test_plot.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/axelrod/tests/unit/test_plot.py b/axelrod/tests/unit/test_plot.py index 0a6274b38..83728ea87 100644 --- a/axelrod/tests/unit/test_plot.py +++ b/axelrod/tests/unit/test_plot.py @@ -26,11 +26,13 @@ def setUpClass(cls): cls.expected_boxplot_xticks_labels = ['Player3', 'Player1', 'Player2'] cls.expected_boxplot_title = ('Mean score per stage game over 5 turns' ' repeated 2 times (3 strategies)') - cls.expected_payoff_dataset = [ [0.0, 3.2, 3.2], [4.2, 0.0, 2.0], [3.6, 1.8, 0.0]] + cls.expected_winplot_dataset = ([[2, 4], [0, 2], [0, 0]], + ['Player1', 'Player2', 'Player3']) + cls.expected_winplot_title = "Distributions of wins: 5 turns repeated 2 times (3 strategies)" def test_init(self): result_set = self.test_result_set @@ -67,6 +69,23 @@ def test_boxplot(self): else: self.skipTest('matplotlib not installed') + def test_winplot_dataset(self): + plot = axelrod.Plot(self.test_result_set) + self.assertSequenceEqual( + plot._winplot_dataset, + self.expected_winplot_dataset) + + def test_winplot_title(self): + plot = axelrod.Plot(self.test_result_set) + self.assertEqual(plot._winplot_title, self.expected_winplot_title) + + def test_winplot(self): + if matplotlib_installed: + plot = axelrod.Plot(self.test_result_set) + self.assertIsInstance(plot.winplot(), matplotlib.pyplot.Figure) + else: + self.skipTest('matplotlib not installed') + def test_payoff_dataset(self): plot = axelrod.Plot(self.test_result_set) self.assertSequenceEqual( From 4303228c4e800b6a1506372cdc7df9dd739cecb1 Mon Sep 17 00:00:00 2001 From: Marc Harper Date: Mon, 12 Oct 2015 11:32:03 -0700 Subject: [PATCH 6/6] Update docs --- docs/usage.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index 1054fc6ce..72733e4b7 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -388,8 +388,6 @@ and accordingly to the ranking of strategies overall: as well as the distributions of wins: -and accordingly to the ranking of strategies overall: - .. |winplot_no_noise| image:: http://axelrod-python.github.io/tournament/assets/strategies_winplot.svg :width: 75% :align: middle