Skip to content

Commit b4251cb

Browse files
committed
Merge pull request #351 from marcharper/win_plot
Plot for distribution of head-to-head wins
2 parents c202f7f + 4293127 commit b4251cb

File tree

4 files changed

+106
-3
lines changed

4 files changed

+106
-3
lines changed

axelrod/plot.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import numpy
2+
13
matplotlib_installed = True
24
try:
35
import matplotlib.pyplot as plt
@@ -11,7 +13,6 @@ class Plot(object):
1113

1214
def __init__(self, result_set):
1315
self.result_set = result_set
14-
# self._nplayers = self.result_set.nplayers
1516
self.matplotlib_installed = matplotlib_installed
1617

1718
@property
@@ -55,6 +56,44 @@ def boxplot(self):
5556
plt.title(self._boxplot_title)
5657
return figure
5758

59+
@property
60+
def _winplot_dataset(self):
61+
# Sort wins by median
62+
wins = self.result_set.wins
63+
players = self.result_set.players
64+
medians = map(numpy.median, wins)
65+
medians = sorted([(m, i) for (i, m) in enumerate(medians)], reverse=True)
66+
# Reorder and grab names
67+
wins = [wins[x[1]] for x in medians]
68+
ranked_names = [str(players[x[1]]) for x in medians]
69+
return wins, ranked_names
70+
71+
@property
72+
def _winplot_title(self):
73+
return ("Distributions of wins:"
74+
" {} turns repeated {} times ({} strategies)").format(
75+
self.result_set.turns,
76+
self.result_set.repetitions,
77+
len(self.result_set.ranking))
78+
79+
def winplot(self):
80+
if not self.matplotlib_installed:
81+
return None
82+
83+
wins, ranked_names = self._winplot_dataset
84+
maximum = max(max(w) for w in wins)
85+
86+
figure = plt.figure()
87+
plt.boxplot(wins)
88+
plt.xticks(
89+
self._boxplot_xticks_locations,
90+
ranked_names,
91+
rotation=90)
92+
plt.tick_params(axis='both', which='both', labelsize=7)
93+
plt.title(self._winplot_title)
94+
plt.ylim(-0.5, 0.5 + maximum)
95+
return figure
96+
5897
def payoff(self):
5998

6099
if not self.matplotlib_installed:

axelrod/tests/unit/test_plot.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ def setUpClass(cls):
2626
cls.expected_boxplot_xticks_labels = ['Player3', 'Player1', 'Player2']
2727
cls.expected_boxplot_title = ('Mean score per stage game over 5 turns'
2828
' repeated 2 times (3 strategies)')
29-
3029
cls.expected_payoff_dataset = [
3130
[0.0, 3.2, 3.2],
3231
[4.2, 0.0, 2.0],
3332
[3.6, 1.8, 0.0]]
33+
cls.expected_winplot_dataset = ([[2, 4], [0, 2], [0, 0]],
34+
['Player1', 'Player2', 'Player3'])
35+
cls.expected_winplot_title = "Distributions of wins: 5 turns repeated 2 times (3 strategies)"
3436

3537
def test_init(self):
3638
result_set = self.test_result_set
@@ -67,6 +69,23 @@ def test_boxplot(self):
6769
else:
6870
self.skipTest('matplotlib not installed')
6971

72+
def test_winplot_dataset(self):
73+
plot = axelrod.Plot(self.test_result_set)
74+
self.assertSequenceEqual(
75+
plot._winplot_dataset,
76+
self.expected_winplot_dataset)
77+
78+
def test_winplot_title(self):
79+
plot = axelrod.Plot(self.test_result_set)
80+
self.assertEqual(plot._winplot_title, self.expected_winplot_title)
81+
82+
def test_winplot(self):
83+
if matplotlib_installed:
84+
plot = axelrod.Plot(self.test_result_set)
85+
self.assertIsInstance(plot.winplot(), matplotlib.pyplot.Figure)
86+
else:
87+
self.skipTest('matplotlib not installed')
88+
7089
def test_payoff_dataset(self):
7190
plot = axelrod.Plot(self.test_result_set)
7291
self.assertSequenceEqual(

axelrod/tournament_manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def _save_plots(self, tournament, ecosystem=None, image_format="svg"):
126126
self._logger.error('The matplotlib library is not installed. '
127127
'No plots will be produced')
128128
return
129-
for plot_type in ('boxplot', 'payoff'):
129+
for plot_type in ('boxplot', 'payoff', 'winplot'):
130130
figure = getattr(plot, plot_type)()
131131
file_name = self._output_file_path(
132132
tournament.name + '_' + plot_type, image_format)

docs/usage.rst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,27 @@ The resulting wins matrix is::
303303

304304
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.
305305

306+
For any tournament, a plot of the distribution of wins is created, much like the
307+
plot for the distribution of mean scores. For the demo strategies we create the
308+
plot as follows::
309+
310+
import axelrod
311+
strategies = [s() for s in axelrod.demo_strategies]
312+
tournament = axelrod.Tournament(strategies, game=Game(30, 0, 50, 10))
313+
results = tournament.play()
314+
plot = axelrod.Plot(results)
315+
p = plot.winplot()
316+
p.show()
317+
318+
This produces:
319+
320+
.. image:: _static/usage/demo_strategies_winplot.svg
321+
:width: 50%
322+
:align: center
323+
324+
In this case most of the strategies are deterministic, so there is not much
325+
variation in the distributions. See below for a more complex example.
326+
306327
Noisy Tournaments
307328
^^^^^^^^^^^^^^^^^
308329

@@ -365,6 +386,23 @@ and accordingly to the ranking of strategies overall:
365386
| |boxplot_no_noise| | |boxplot_5_noise| |
366387
+--------------------+-------------------+
367388

389+
as well as the distributions of wins:
390+
391+
.. |winplot_no_noise| image:: http://axelrod-python.github.io/tournament/assets/strategies_winplot.svg
392+
:width: 75%
393+
:align: middle
394+
:alt: Strategy performance without noise
395+
396+
.. |winplot_5_noise| image:: http://axelrod-python.github.io/tournament/assets/strategies_winplot_noise_5.svg
397+
:width: 75%
398+
:align: middle
399+
:alt: Strategy performance with 5% noise
400+
401+
+--------------------+-------------------+
402+
| |winplot_no_noise| | |winplot_5_noise| |
403+
+--------------------+-------------------+
404+
405+
368406
To run a noisy tournament, just use the keyword argument `noise` when
369407
creating tournaments. Both `run_axelrod` and the utility function
370408
`run_tournaments` accept and passthrough the noise argument. To run the
@@ -528,6 +566,13 @@ The results from the tournament itself (ordered by median score):
528566
:width: 50%
529567
:align: center
530568

569+
The distributions of head-to-head wins for each strategy:
570+
571+
.. image:: http://axelrod-python.github.io/tournament/assets/strategies_winplot.svg
572+
:width: 50%
573+
:align: center
574+
575+
531576
The payoff matrix from that tournament:
532577

533578
.. image:: http://axelrod-python.github.io/tournament/assets/strategies_payoff.svg

0 commit comments

Comments
 (0)