diff --git a/.vscode/.ropeproject/config.py b/.vscode/.ropeproject/config.py new file mode 100644 index 0000000..0bf7750 --- /dev/null +++ b/.vscode/.ropeproject/config.py @@ -0,0 +1,112 @@ +# The default ``config.py`` +# flake8: noqa + + +def set_prefs(prefs): + """This function is called before opening the project""" + + # Specify which files and folders to ignore in the project. + # Changes to ignored resources are not added to the history and + # VCSs. Also they are not returned in `Project.get_files()`. + # Note that ``?`` and ``*`` match all characters but slashes. + # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' + # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' + # '.svn': matches 'pkg/.svn' and all of its children + # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' + # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' + prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', + '.hg', '.svn', '_svn', '.git', '.tox'] + + # Specifies which files should be considered python files. It is + # useful when you have scripts inside your project. Only files + # ending with ``.py`` are considered to be python files by + # default. + #prefs['python_files'] = ['*.py'] + + # Custom source folders: By default rope searches the project + # for finding source folders (folders that should be searched + # for finding modules). You can add paths to that list. Note + # that rope guesses project source folders correctly most of the + # time; use this if you have any problems. + # The folders should be relative to project root and use '/' for + # separating folders regardless of the platform rope is running on. + # 'src/my_source_folder' for instance. + #prefs.add('source_folders', 'src') + + # You can extend python path for looking up modules + #prefs.add('python_path', '~/python/') + + # Should rope save object information or not. + prefs['save_objectdb'] = True + prefs['compress_objectdb'] = False + + # If `True`, rope analyzes each module when it is being saved. + prefs['automatic_soa'] = True + # The depth of calls to follow in static object analysis + prefs['soa_followed_calls'] = 0 + + # If `False` when running modules or unit tests "dynamic object + # analysis" is turned off. This makes them much faster. + prefs['perform_doa'] = True + + # Rope can check the validity of its object DB when running. + prefs['validate_objectdb'] = True + + # How many undos to hold? + prefs['max_history_items'] = 32 + + # Shows whether to save history across sessions. + prefs['save_history'] = True + prefs['compress_history'] = False + + # Set the number spaces used for indenting. According to + # :PEP:`8`, it is best to use 4 spaces. Since most of rope's + # unit-tests use 4 spaces it is more reliable, too. + prefs['indent_size'] = 4 + + # Builtin and c-extension modules that are allowed to be imported + # and inspected by rope. + prefs['extension_modules'] = [] + + # Add all standard c-extensions to extension_modules list. + prefs['import_dynload_stdmods'] = True + + # If `True` modules with syntax errors are considered to be empty. + # The default value is `False`; When `False` syntax errors raise + # `rope.base.exceptions.ModuleSyntaxError` exception. + prefs['ignore_syntax_errors'] = False + + # If `True`, rope ignores unresolvable imports. Otherwise, they + # appear in the importing namespace. + prefs['ignore_bad_imports'] = False + + # If `True`, rope will insert new module imports as + # `from import ` by default. + prefs['prefer_module_from_imports'] = False + + # If `True`, rope will transform a comma list of imports into + # multiple separate import statements when organizing + # imports. + prefs['split_imports'] = False + + # If `True`, rope will remove all top-level import statements and + # reinsert them at the top of the module when making changes. + prefs['pull_imports_to_top'] = True + + # If `True`, rope will sort imports alphabetically by module name instead of + # alphabetically by import statement, with from imports after normal + # imports. + prefs['sort_imports_alphabetically'] = False + + # Location of implementation of rope.base.oi.type_hinting.interfaces.ITypeHintingFactory + # In general case, you don't have to change this value, unless you're an rope expert. + # Change this value to inject you own implementations of interfaces + # listed in module rope.base.oi.type_hinting.providers.interfaces + # For example, you can add you own providers for Django Models, or disable the search + # type-hinting in a class hierarchy, etc. + prefs['type_hinting_factory'] = 'rope.base.oi.type_hinting.factory.default_type_hinting_factory' + + +def project_opened(project): + """This function is called after opening the project""" + # Do whatever you like here! diff --git a/.vscode/.ropeproject/objectdb b/.vscode/.ropeproject/objectdb new file mode 100644 index 0000000..0a47446 Binary files /dev/null and b/.vscode/.ropeproject/objectdb differ diff --git a/.vscode/settings.json b/.vscode/settings.json index e69de29..e1258fd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "/Users/wjsjwr/.pyenv/versions/anaconda3-5.0.1/bin/python" +} \ No newline at end of file diff --git a/defector_has_neighbor.py b/break_tie.py similarity index 58% rename from defector_has_neighbor.py rename to break_tie.py index 97d0ab1..b8a569b 100644 --- a/defector_has_neighbor.py +++ b/break_tie.py @@ -5,42 +5,45 @@ from island.matches import Matches matches = Matches('wos-data-new') -labels = ['has neighbor', 'no neighbor'] +labels = ['Stay Connected', 'Break Tie'] percents = [0.0, 0.0] +op = 'D' for m in matches.data: info = m.query('game', 'created').select('info').first()['info'] conf = json.loads(info['config']) game_end_at = int(info['game_end_at']) - for row in m.query('action', 'done').where(lambda x: x['act_a'] == 'D' or x['act_b'] == 'D').raw_data: + for row in m.query('action', 'done').where(lambda x: x['act_a'] == op or x['act_b'] == op).raw_data: if row['rno'] == game_end_at: print(row) continue - if row['act_a'] == 'D': + if row['act_a'] == op: a = row['a'] b = row['b'] - o = m.query('action', 'done').where(lambda y: (y['b'] == a or y['a'] == a) and y['rno'] == row['rno'] + 1).raw_data + o = m.query('action', 'done').where(lambda y: ((y['b'] == a and y['a'] == b) or (y['a'] == a and y['b'] == b)) and y['rno'] == row['rno'] + 1).raw_data if o: percents[0] += 1 else: percents[1] += 1 - if row['act_b'] == 'D': + if row['act_b'] == op: a = row['a'] b = row['b'] - o = m.query('action', 'done').where(lambda y: (y['b'] == b or y['a'] == b) and y['rno'] == row['rno'] + 1).raw_data + o = m.query('action', 'done').where(lambda y: ((y['b'] == a and y['a'] == b) or (y['a'] == a and y['b'] == b)) and y['rno'] == row['rno'] + 1).raw_data if o: percents[0] += 1 else: percents[1] += 1 - +print(percents) _all = sum(percents) / 100 percents[0] /= _all percents[1] /= _all + plt.figure() -plt.pie(percents, labels=labels, autopct='%1.1f%%', startangle=90) +plt.pie(percents, labels=labels, autopct="%1.2f%%", pctdistance=1.1, labeldistance=2,startangle=90, colors=['#00b894', '#fdcb6e']) +plt.legend() plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. -plt.show() -# plt.savefig('graph/unlink_has_neighbor.png') \ No newline at end of file +# plt.show() +plt.savefig("graph/break_tie_%s.eps"%op) \ No newline at end of file diff --git a/break_tie_chi2.py b/break_tie_chi2.py new file mode 100644 index 0000000..2279b91 --- /dev/null +++ b/break_tie_chi2.py @@ -0,0 +1,6 @@ +from scipy.stats import chi2_contingency as chi2 +import numpy as np + +obs = np.array([[219,113],[661,25]]) +chi,p,dof,expected = chi2(obs) +print("%f, %f, %f" % (chi, p, dof)) \ No newline at end of file diff --git a/calc_dnc_players.py b/calc_dnc_players.py new file mode 100644 index 0000000..8c511a3 --- /dev/null +++ b/calc_dnc_players.py @@ -0,0 +1,37 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches +import numpy as np + +matches = Matches('wos-data-new') +max_round = 15 + +total_players = 0 +dnc_players = 0 + +survivals = {} +with open('survivals.json', 'r') as f: + survivals = json.load(f) + + +for j in range(len(matches.data)): + players = set() + for r in matches.data[j].query('player', 'join').raw_data: + players.add(r['pid']) + total_players += len(players) + for i in range(int(matches.data[j].query('game', 'created').first()['info']['game_end_at'])): + actions = matches.data[j].query('action', 'done').where(lambda x: x['rno']==i+1) + for r in actions.raw_data: + if r['a'] in players: + if actions.where(lambda y: (y['a'] == r['a'] and y['b'] != r['b']) or (y['b'] == r['a'] and y['a'] != r['b'])).count() > 0: + dnc_players += 1 + players.remove(r['a']) + if r['b'] in players: + if actions.where(lambda y: (y['a'] == r['b'] and y['b'] != r['a']) or (y['b'] == r['b'] and y['a'] != r['a'])).count() > 0: + dnc_players += 1 + players.remove(r['b']) + + + +print("dnc=%d, total=%d, frac=%f" % (dnc_players, total_players, dnc_players / total_players)) \ No newline at end of file diff --git a/calc_participants.py b/calc_participants.py new file mode 100644 index 0000000..4a64cfc --- /dev/null +++ b/calc_participants.py @@ -0,0 +1,19 @@ +# from G254 +import json +from pathlib import Path +from island.match import Match + + + +result = 0 + +for file in Path('wos-data-new').iterdir(): + p = Path(file) + if p.suffix == '.json': + name = p.stem + if int(name[1:]) >= 254: + m = Match.read_from_json(str(file)) + result += len(m.query('player', 'join').select('pid').raw_data) + +print(result) +# 146 users \ No newline at end of file diff --git a/comp_co_per_match.py b/comp_co_per_match.py index 49d8ecf..3ebd15b 100644 --- a/comp_co_per_match.py +++ b/comp_co_per_match.py @@ -4,49 +4,73 @@ from island.match import Match from island.matches import Matches import numpy as np -def calc_co(matches): +def calc_co(matches, is_casual): x = [0,0,0,0,0,0] + count = 0 for j in range(len(matches.data)): if len(matches.data[j].query('action', 'done').raw_data) < 5: continue coop = 0 + total = 0 + count += 1 + players = [] + if is_casual: + for row in matches.data[j].query('player', 'join').where(lambda r: 'bot' not in r).raw_data: + players.append(row['pid']) + rows = matches.data[j].query('action', 'done').raw_data - for row in rows: - if row['act_a'] == 'C' and row['act_b'] == 'C': - coop += 1 + if is_casual: + for row in rows: + if row['a'] in players: + total += 1 + if row['act_a'] == 'C': + coop += 1 + if row['b'] in players: + total += 1 + if row['act_b'] == 'C': + coop += 1 + else: + for row in rows: + if row['act_a'] == 'C': + coop += 1 + if row['act_b'] == 'C': + coop += 1 + total += 2 if rows: - per = float(coop) / len(rows) + per = float(coop) / total x[int(per*100)//20] += 1 x[4] += x[5] x.pop() s = sum(x) for i in range(5): x[i] /= s + + print("Match type: %s, Count: %d" % ('Casual' if is_casual else 'Compete', count)) return x casual = Matches('wos-data-casual') compete = Matches('wos-data-new') -ca = calc_co(casual) -co = calc_co(compete) +ca = calc_co(casual, True) +co = calc_co(compete, False) fig = plt.figure(figsize=(5,4)) ax = fig.gca() index = np.arange(5) bar_width = 0.35 -rects1 = ax.bar(index, ca, bar_width, color='#00b894', label='Casual games') +rects1 = ax.bar(index, ca, bar_width, color='#00b894', label='Casual mode') # rects2 = ax.bar(index + bar_width, co, bar_width, color='#005CAF', label='Competition') -rects2 = ax.bar(index + bar_width, co, bar_width, color='#6c5ce7', label='Competition') +rects2 = ax.bar(index + bar_width, co, bar_width, color='#6c5ce7', label='Competing mode') ax.set_xticks(index + bar_width / 2) ax.set_xticklabels(['0~0.2','0.2~0.4','0.4~0.6','0.6~0.8','0.8~1']) ax.legend() # fig.autofmt_xdate() fig.set_size_inches(5, 4) -plt.xlabel('Frequency of Cooperation Actions per Match') +plt.xlabel('Frequency of Human Cooperations per Match') plt.ylabel('Fraction of Matches') fig.tight_layout() # plt.show() -plt.savefig('graph/comp_co_per_match.eps') \ No newline at end of file +plt.savefig('graph/CompCoPerMatch.eps') \ No newline at end of file diff --git a/coopr_per_match.py b/coopr_per_match.py index 422dd80..1e6d3ea 100644 --- a/coopr_per_match.py +++ b/coopr_per_match.py @@ -1,3 +1,4 @@ +# -*- coding: UTF-8 -*- import json from matplotlib import pyplot as plt import scipy as sp @@ -25,11 +26,13 @@ for j in range(len(matches.data)): info = matches.data[j].query('game', 'created').select('info').raw_data[0]['info'] ns = int(info['next_start']) for row in rows: - if row['act_a'] == 'C' and row['act_b'] == 'C': + if row['act_a'] == 'C': + coop += 1 + if row['act_b'] == 'C': coop += 1 if rows: - data[ns] = float(coop) / len(rows) + data[ns] = float(coop) / len(rows) / 2 x.append(ns) x = sorted(x) @@ -51,5 +54,5 @@ fx = sp.linspace(0,_x[-1],1000) plt.plot(fx,f1(fx),linewidth=1,color='red') -# plt.show() -plt.savefig('graph/co_per_game.png') \ No newline at end of file +plt.show() +# plt.savefig('graph/co_per_game.png') \ No newline at end of file diff --git a/draw_game_history.py b/draw_game_history.py index 620a0b6..453d783 100644 --- a/draw_game_history.py +++ b/draw_game_history.py @@ -1,7 +1,7 @@ import json import math - -from cairo import Context, LineCap, LineJoin, PSSurface, SVGSurface +from pathlib import Path +from cairo import Context, LineCap, LineJoin, PSSurface, SVGSurface, Gradient, LinearGradient # from scipy.integrate import quad from island.match import Match @@ -140,6 +140,7 @@ def draw_action_arrow(ctx, cf, ct, w, al, r, c): ctx.set_source_rgba(c.r, c.g, c.b, c.a) ctx.set_line_width(w) ctx.set_line_cap(LineCap.ROUND) + ctx.set_line_join(LineJoin.ROUND) ltr = 1 if cf.x < ct.x else -1 af = Point(cf.x + ltr * r / SQRT2, cf.y - ltr * r / SQRT2) at = Point(ct.x - ltr * r / SQRT2, ct.y - ltr * r / SQRT2) @@ -155,6 +156,27 @@ def draw_action_arrow(ctx, cf, ct, w, al, r, c): ctx.line_to(at.x + al * math.cos(a + math.pi / 12), at.y + al * math.sin(a + math.pi / 12)) ctx.stroke() +def draw_legend_arrow(ctx, cf, ct, w, al, c): + """ + :param ctx: context + :param cf: from the center point + :param ct: to the center point + :param w: line width + :param al: arrow length + :param c: Color + """ + ctx.set_source_rgba(c.r, c.g, c.b, c.a) + ctx.set_line_width(w) + ctx.set_line_cap(LineCap.ROUND) + ctx.set_line_join(LineJoin.ROUND) + ctx.move_to(cf.x, cf.y) + ctx.line_to(ct.x, ct.y) + ctx.line_to(ct.x - al * math.cos(-math.pi / 12), ct.y + al * math.sin(-math.pi / 12)) + ctx.move_to(ct.x, ct.y) + ctx.line_to(ct.x - al * math.cos(math.pi / 12), ct.y + al * math.sin(math.pi / 12)) + ctx.stroke() + + def draw_food_bar(ctx, refp, food, foodi, w, h): """ :param ctx: context @@ -176,6 +198,30 @@ def draw_food_bar(ctx, refp, food, foodi, w, h): ctx.set_source_rgba(0, 0, 0, 1) ctx.stroke() +def draw_linear_gradient_rect(ctx, tl, br, lw, start, stop, horizonal=True): + """ + :param ctx: context + :param tl: the top-left reference point + :param br: the right-bottom reference point + :param lw: line width + :param start: start color + :param stop: stop color + :param horizonal: if the gradient is horizonal + """ + ctx.set_line_cap(LineCap.SQUARE) + ctx.set_line_join(LineJoin.MITER) + # source = ctx.get_source() + lr = LinearGradient(tl.x, tl.y, br.x, br.y) + lr.add_color_stop_rgba(0, start.r, start.g, start.b, start.a) + lr.add_color_stop_rgba(1, stop.r, stop.g, stop.b, stop.a) + ctx.set_source(lr) + ctx.rectangle(tl.x, tl.y, br.x - tl.x, br.y - tl.y) + ctx.fill() + # ctx.rectangle(tl.x, tl.y, br.x - tl.x, br.y - tl.y) + # ctx.set_line_width(lw) + # ctx.set_source_rgba(0, 0, 0, 1) + # ctx.stroke() + def draw_faces(ctx, p, f, r, lw): """ @@ -187,22 +233,23 @@ def draw_faces(ctx, p, f, r, lw): """ for k in p.keys(): if f[k] > 0: - draw_alive_face(context, p[k], r, lw) + draw_alive_face(ctx, p[k], r, lw) else: - draw_dead_face(context, p[k], r, lw) + draw_dead_face(ctx, p[k], r, lw) draw_food_bar(ctx, p[k].new_rel_point(r / SQRT2 + 20, r / SQRT2), f[k], 5, 10, r * SQRT2) draw_text(ctx, str(k), Point(p[k].x, p[k].y - r - 15), Point(p[k].x, p[k].y - r - 5), CENTER_ALIGNED|MIDDLE_ALIGNED, 12) -def draw_text(ctx, text, tl, rb, align, font_size=None, font_face=None, font_matrix=None, font_options=None): +def draw_text(ctx, text, tl, br, align, font_size=None, color=Color(0,0,0,1), font_face=None, font_matrix=None, font_options=None): """ draw text :param ctx: context :param text: the text :param tl: the top-left reference point - :param rb: the right-bottom reference point + :param br: the right-bottom reference point :param align: alignment :param font_size: float font size + :param color: text color :param font_face: font face :param font_matrix: font matrix :param font_options: font options @@ -219,19 +266,20 @@ def draw_text(ctx, text, tl, rb, align, font_size=None, font_face=None, font_mat te = ctx.text_extents(text) ha = align & 0b00001111 if ha == CENTER_ALIGNED: - x = (rb.x + tl.x - te.width) / 2 - te.x_bearing / 2 + x = (br.x + tl.x - te.width) / 2 - te.x_bearing / 2 elif ha == RIGHT_ALIGNED: - x = rb.x - te.width + x = br.x - te.width else:# ha == LEFT_ALIGNED x = tl.x - te.x_bearing va = align & 0b11110000 if va == MIDDLE_ALIGNED: - y = (rb.y + tl.y + te.height) / 2 - (te.height + te.y_bearing) / 2 + y = (br.y + tl.y + te.height) / 2 - (te.height + te.y_bearing) / 2 elif va == BOTTOM_ALIGNED: - y = rb.y + y = br.y else: #va == TOP_ALIGNED: y = tl.y + te.height - (te.height + te.y_bearing) ctx.move_to(x, y) + set_color(ctx, color) ctx.show_text(text) LEFT_ALIGNED = 0b00000001 @@ -249,28 +297,35 @@ FACE_WIDTH = 100 FACE_INTERVAL = 50 ROUND_HEIGHT = 300 LINEWIDTH = 4 +ROUND_NO_WIDTH = 75 TAMAMOROKOSHI = Color(0.9098039215686275, 0.7137254901960784, 0.2784313725490196, 1) AKE = Color(0.8, 0.3294117647058824, 0.2274509803921569, 1) TOKIWA = Color(0.1058823529411765, 0.5058823529411765, 0.2431372549019608, 1) -if __name__ == '__main__': - M = Match.read_from_json("D:\\code\\python\\swdata\\wos-data-new\\G302.json") +def draw_picture(fin,fout): + M = Match.read_from_json(fin) info = M.query('game', 'created').select('info').first()['info'] conf = json.loads(info['config']) game_end_at = int(info['game_end_at']) - P = {} - F = {} + P = {} # position + F = {} # face R = 30 + for r in M.query('player', 'join').raw_data: - P[r['pid']] = Point(len(F) * FACE_WIDTH + FACE_INTERVAL, ROUND_HEIGHT / 2) + P[r['pid']] = Point(len(F) * FACE_WIDTH + FACE_INTERVAL + ROUND_NO_WIDTH, ROUND_HEIGHT / 2) F[r['pid']] = 5 - surface = SVGSurface("example.svg", len(P)*(FACE_WIDTH)+FACE_WIDTH, (game_end_at+2)*ROUND_HEIGHT) + # surface = SVGSurface("example.svg", len(P)*(FACE_WIDTH)+FACE_WIDTH, (game_end_at+2)*ROUND_HEIGHT) + surface = PSSurface(fout, (len(P)+1)*(FACE_WIDTH) + ROUND_NO_WIDTH, (game_end_at+2)*ROUND_HEIGHT) + surface.set_eps(True) context = Context(surface) + bottom = 0 + for i in range(1, game_end_at + 2): next_f = F.copy() + draw_text(context, "Round %d" % i, Point(5, ROUND_HEIGHT/2+(i-1)*ROUND_HEIGHT), Point(ROUND_NO_WIDTH, ROUND_HEIGHT/2+(i-1)*ROUND_HEIGHT), LEFT_ALIGNED | MIDDLE_ALIGNED, 20) for r in M.query('action', 'done').where(lambda row: row['rno'] == i).raw_data: draw_action_arrow(context, P[r['a']], P[r['b']], LINEWIDTH, 15, R, AKE.shade(r['tr'] / 1440) if r['act_a'] == 'D' else TOKIWA.shade(r['tr']/1440)) draw_action_arrow(context, P[r['b']], P[r['a']], LINEWIDTH, 15, R, AKE.shade(r['tr'] / 1440) if r['act_b'] == 'D' else TOKIWA.shade(r['tr']/1440)) @@ -281,5 +336,24 @@ if __name__ == '__main__': F[k] = next_f[k] - conf['rounds']['consumption'] P[k].rel_move_to(0, ROUND_HEIGHT) - + # draw legend + draw_legend_arrow(context, Point(50, ROUND_HEIGHT * (game_end_at + 1)), Point(75, ROUND_HEIGHT * (game_end_at + 1)), LINEWIDTH, 15, TOKIWA) + draw_legend_arrow(context, Point(50, ROUND_HEIGHT * (game_end_at + 1) + 30), Point(75, ROUND_HEIGHT * (game_end_at + 1) + 30), LINEWIDTH, 15, AKE) + draw_text(context, 'C', Point(100, ROUND_HEIGHT * (game_end_at + 1)), Point(120, ROUND_HEIGHT * (game_end_at + 1)), LEFT_ALIGNED|TOP_ALIGNED, 30) + draw_text(context, 'D', Point(100, ROUND_HEIGHT * (game_end_at + 1) + 30), Point(120, ROUND_HEIGHT * (game_end_at + 1) + 30), LEFT_ALIGNED|TOP_ALIGNED, 30) + draw_linear_gradient_rect(context, Point(200, ROUND_HEIGHT * (game_end_at + 1)), Point(350, ROUND_HEIGHT * (game_end_at + 1) + 20), 2, TOKIWA, TOKIWA.shade(0)) + draw_linear_gradient_rect(context, Point(200, ROUND_HEIGHT * (game_end_at + 1)+30), Point(350, ROUND_HEIGHT * (game_end_at + 1) + 50), 2, AKE, AKE.shade(0)) + + + + surface.finish() + + +if __name__ == '__main__': + # for file in Path('wos-data-new').iterdir(): + # p = Path(file) + # if p.suffix == '.json': + # name = p.stem + # draw_picture(str(p), str(p.parent.parent / 'graph' / ("%s.eps"%name))) + draw_picture("wos-data-new/G285.json", "graph/G285.eps") \ No newline at end of file diff --git a/fail_reason.py b/fail_reason.py index 2eb85ef..6688687 100644 --- a/fail_reason.py +++ b/fail_reason.py @@ -3,12 +3,11 @@ from matplotlib import pyplot as plt from island.match import Match from island.matches import Matches -matches = Matches('wos-data-casual') +matches = Matches('wos-data-new') -labels = ['not enough tr', 'other reason'] percents = [0.0, 0.0] -op = 'D' +op = 'C' def get_reason(m, i, target): r = m.query('action', 'request').where(lambda x: x['rno'] == i+1 and x['from'] == target).raw_data @@ -25,7 +24,7 @@ def get_reason(m, i, target): tr += m.query('action', 'request').where(lambda x: x['rno'] == i+1 and x['from'] == j['to'] and x['to'] == k['from'] and x['log_id'] < k['log_id']).orderby('log_id').raw_data[-1]['tr'] for k in m.query('action', 'approve').where(lambda x: x['rno'] == i+1 and x['from'] == j['to']).raw_data: tr -= k['tr'] - print(tr) + # print(tr) if tr >= j['tr']: percents[1] += 1 else: @@ -47,12 +46,17 @@ for m in matches.data: get_reason(m, i, row['b']) calced.add(row['b']) +print(percents) _all = sum(percents) / 100 percents[0] /= _all percents[1] /= _all + +labels = ['Insufficient Time Resource', 'Sufficient Time Resource'] + plt.figure() -plt.pie(percents, labels=labels, autopct='%1.2f%%', startangle=90) +plt.pie(percents, labels=labels, autopct="%1.2f%%", pctdistance=1.1, labeldistance=2,startangle=90, colors=['#00b894', '#fdcb6e']) +plt.legend() plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. -plt.show() -# plt.savefig('graph/unlink_has_neighbor.png') \ No newline at end of file +# plt.show() +plt.savefig("graph/fail_reason_%s.eps"%op) \ No newline at end of file diff --git a/fail_reason_chi2.py b/fail_reason_chi2.py new file mode 100644 index 0000000..7649cb7 --- /dev/null +++ b/fail_reason_chi2.py @@ -0,0 +1,6 @@ +from scipy.stats import chi2_contingency as chi2 +import numpy as np + +obs = np.array([[159,90],[53,24]]) +chi,p,dof,expected = chi2(obs) +print("%f, %f, %f" % (chi, p, dof)) \ No newline at end of file diff --git a/interactions_per_round.py b/interactions_per_round.py new file mode 100644 index 0000000..ec745dc --- /dev/null +++ b/interactions_per_round.py @@ -0,0 +1,64 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches +import numpy as np + +matches = Matches('wos-data-new') +max_round = 15 + +coopr = [] +yerr_min = [] +yerr_max = [] +x = np.arange(max_round) +bx = [] +y = np.zeros((5, max_round)) +sy = np.zeros(max_round) + +survivals = {} +with open('survivals.json', 'r') as f: + survivals = json.load(f) + + +for i in range(max_round): + co = {} + for j in range(len(matches.data)): + if str(i+1) not in survivals[matches.names[j]]: + continue + for k in survivals[matches.names[j]][str(i+1)]: + co[k] = 0 + rows = matches.data[j].query('action', 'done').where(lambda x: x['rno']==i+1).raw_data + for row in rows: + if row['a'] in co: + co[row['a']] += 1 + if row['b'] in co: + co[row['b']] += 1 + + for j in co.values(): + if j <= 4: + y[j][i] += 1 + else: + y[4][i] += 1 + + sy[i] += 1 + # bx.append(list(co.values())) + +# plt.figure() +# plt.boxplot(bx, showmeans=True, meanline=True) +# plt.show() +labels = ["k = 0 ", "k = 1", "k = 2", "k = 3", "k ⩾ 4"] +colors = ['#0984e3', '#fdcb6e', '#00b894', '#6c5ce7', '#d63031', '#0984e3'] +y /= sy +fig = plt.figure(figsize=(6, 4)) +ax = fig.gca() +ax.stackplot(x+1, y, labels=labels, colors=colors) +ax.set_xticks(x+1) +ax.set_xticklabels(x+1) +ax.set_xlim(1,15) +ax.set_ylim(0, 1) +ax.set_xlabel('Round') +ax.set_ylabel('Fraction of k') +ax.legend() +plt.tight_layout() +# plt.show() +plt.savefig('graph/interaction_per_round.eps') \ No newline at end of file diff --git a/island/match.py b/island/match.py index 8741749..59bbae8 100644 --- a/island/match.py +++ b/island/match.py @@ -78,7 +78,7 @@ class Match: def first(self): """ - return first result + return the first result """ if self.dtype != 'mid': raise RuntimeError("first query on raw data.") @@ -86,6 +86,15 @@ class Match: rawl = len(self.raw_data) return self.raw_data[0] if rawl > 0 else None + def count(self): + """ + return the amount of results + """ + if self.dtype != 'mid': + raise RuntimeError("count query on raw data.") + + return len(self.raw_data) + @staticmethod def read_from_json(json_path): """ diff --git a/neighbor_per_round.py b/neighbor_per_round.py index 1171522..be9b5bb 100644 --- a/neighbor_per_round.py +++ b/neighbor_per_round.py @@ -7,7 +7,7 @@ import numpy as np matches = Matches('wos-data-new') -max_round = 17 +max_round = 15 survivals = {} with open('survivals.json', 'r') as f: @@ -21,6 +21,23 @@ cstd = [] dstd = [] +def is_defector(rows, pid): + m = 0 + mall = 0 + for r in rows: + if pid == r['a'] and r['act_a'] == 'C': + m += 1 + mall += 1 + elif pid == r['a'] and r['act_a'] == 'D': + mall += 1 + elif pid == r['b'] and r['act_b'] == 'C': + m += 1 + mall += 1 + elif pid == r['b'] and r['act_b'] == 'D': + mall += 1 + return m*2 >= mall + + for i in range(len(matches.data)): m = matches.data[i] n = {} @@ -50,7 +67,7 @@ for i in range(max_round): if k in survivals[matches.names[j]][str(i+1)]: nn += 1 - if row['act_a'] == 'C': + if is_defector(rows, row['a']): cneigh.append(nn) else: dneigh.append(nn) @@ -61,12 +78,10 @@ for i in range(max_round): for k in neighbors[matches.names[j]][row['b']]: if k in survivals[matches.names[j]][str(i+1)]: nn += 1 - - if row['act_b'] == 'C': + if is_defector(rows, row['b']): cneigh.append(nn) else: dneigh.append(nn) - calced.add(row['b']) if cneigh: @@ -86,25 +101,27 @@ for i in range(max_round): dmean.append(dm) dstd.append(ds) - -fig, ax = plt.subplots() -index = np.arange(17) -bar_width = 0.35 -opacity = 0.4 -error_config = {'ecolor': '0.3', 'capsize': 4} +fig = plt.figure(figsize=(6.4, 3.6)) +ax = fig.gca() +index = np.arange(max_round) +bar_width = 0.45 +opacity = 1 +error_config = dict(ecolor='#2d3436', capsize=0, elinewidth=1) rects1 = ax.bar(index, cmean, bar_width, - alpha=opacity, color='b', + alpha=opacity, color='#0984e3', yerr=cstd, error_kw=error_config, - label='C') + label='Cooperator') rects2 = ax.bar(index + bar_width, dmean, bar_width, - alpha=opacity, color='r', + alpha=opacity, color='#d63031', yerr=dstd, error_kw=error_config, - label='D') -# ax.set_xlabel('Group') -# ax.set_ylabel('Scores') + label='Defector') + +ax.set_xlabel('Round') +ax.set_ylabel('Size of the Neighborhood') # ax.set_title('Scores by group and gender') ax.set_xticks(index + bar_width / 2) ax.set_xticklabels(index+1) ax.legend() fig.tight_layout() -plt.show() \ No newline at end of file +# plt.show() +plt.savefig('graph/neigh_per_round.eps') \ No newline at end of file diff --git a/neighbors_per_round.py b/neighbors_per_round.py deleted file mode 100644 index 8467e2a..0000000 --- a/neighbors_per_round.py +++ /dev/null @@ -1,45 +0,0 @@ -import json -from matplotlib import pyplot as plt -from island.match import Match -from island.matches import Matches - -matches = Matches('wos-data-new') -max_round = 17 - -coopr = [] -yerr_min = [] -yerr_max = [] -x = [] -bx = [] - -survivals = {} -with open('winner.json','r') as f: - survivals = json.load(f) - -for i in range(max_round): - co = [] - for j in range(len(matches.data)): - nodes = set() - rows = matches.data[j].query('action', 'done').where(lambda x: x['rno']==i+1).raw_data - for row in rows: - nodes.add(row['a']) - nodes.add(row['b']) - - if rows: - co.append(float(len(rows) * 2) / float(len(nodes))) - - bx.append(co) - - if co: - coopr.append(sum(co) / len(co)) - - yerr_min.append(coopr[-1] - min(co)) - yerr_max.append(max(co) - coopr[-1]) - print("%f, %f, %f"%(yerr_min[-1], yerr_max[-1], coopr[-1])) - x.append(i+1) - -plt.figure() -# plt.errorbar(x, coopr, yerr=[yerr_min, yerr_max], fmt='o', capsize=4) -plt.boxplot(bx, showmeans=True, meanline=True) -plt.show() -# plt.savefig('graph/co_per_round.png') \ No newline at end of file diff --git a/plot_defect_alive.py b/plot_defect_alive.py index 03f44d8..a9f31ac 100644 --- a/plot_defect_alive.py +++ b/plot_defect_alive.py @@ -2,15 +2,17 @@ import json from matplotlib import pyplot as plt from island.match import Match from island.matches import Matches +import numpy as np matches = Matches('wos-data-new') -max_round = 17 +max_round = 15 alive = [] -yerr_min = [] -yerr_max = [] +yerr = [] x = [] al_al = [] +d = [] +d_sem = [] survivals = {} with open('winner.json','r') as f: @@ -18,6 +20,7 @@ with open('winner.json','r') as f: for i in range(max_round): defects = [] + count = [] for j in range(len(matches.data)): defector = set() for row in matches.data[j].query('action', 'done').where(lambda x: x['rno']==i+1 and (x['act_a']=='D' or x['act_b']=='D')).raw_data: @@ -34,22 +37,39 @@ for i in range(max_round): incr += 1 # print(k) defects.append(float(incr) / float(len(defector))) - + count.append(len(defector)) print(i) print(defects) + print(count) if defects: - + defects = np.array(defects) al_al.append(defects) - alive.append(sum(defects) / len(defects)) - yerr_min.append(alive[-1] - min(defects)) - yerr_max.append(max(defects) - alive[-1]) - print("%f, %f, %f"%(yerr_min[-1], yerr_max[-1], alive[-1])) - x.append(i+1) + alive.append(np.average(defects)) + yerr.append(np.std(defects)) + count = np.array(count) + d.append(np.average(count)) + d_sem.append(np.std(count)) else: al_al.append([]) + alive.append(0) + yerr.append(0) + d.append(0) + d_sem.append(0) + x.append(i+1) -plt.figure() + +fig = plt.figure(figsize=(6.4, 4)) +flier_marker = dict(markerfacecolor='w', marker='o', markersize=3, markeredgewidth=0.5) +mean_marker = dict(markerfacecolor='w', marker='s', markeredgecolor='#0984e3', markersize=3, markeredgewidth=1) +ax1 = fig.gca() # plt.errorbar(x, alive, yerr=[yerr_min, yerr_max], fmt='o', capsize=4) -plt.boxplot(al_al, showmeans=True, meanline=True) +ax1.boxplot(al_al, showmeans=True, meanprops=mean_marker, flierprops=flier_marker) +plt.xlabel('Round') +plt.ylabel('Frequency of Defection Survivals') +# ax2 = ax1.twinx() +# ax2.errorbar(list(range(1, max_round+1)), d, yerr=d_sem, fmt='o-', capsize=2, color='#00b894', alpha=0.5, linewidth=1, zorder=-1) +# ax2.errorbar(x, alive, yerr=yerr, fmt='o-', capsize=2, color='#00b894', alpha=0.5, linewidth=1, zorder=-1) +# ax2.tick_params(axis='y', labelcolor='#00b894') +plt.tight_layout() plt.show() # plt.savefig('graph/survive_after_defect.png') \ No newline at end of file diff --git a/request_success.py b/request_success.py index 343aff0..18d1b61 100644 --- a/request_success.py +++ b/request_success.py @@ -6,24 +6,16 @@ from numpy import mean, std import numpy as np -matches = Matches('wos-data-casual') -max_round = 17 +matches = Matches('wos-data-new') +max_round = 14 -c_req_suc_mean = [] -d_req_suc_mean = [] -c_req_suc_std = [] -d_req_suc_std = [] +c_req_succ = np.zeros(max_round-2) +c_req = np.zeros(max_round-2) +d_req_succ = np.zeros(max_round-2) +d_req = np.zeros(max_round-2) -c_req_fail_mean = [] -d_req_fail_mean = [] -c_req_fail_std = [] -d_req_fail_std = [] for i in range(max_round): - cReSu = [] - cReFa = [] - dReSu = [] - dReFa = [] for j in range(len(matches.data)): rows = matches.data[j].query('action', 'done').where(lambda x: x['rno'] == i+1).raw_data calced = set() @@ -32,90 +24,81 @@ for i in range(max_round): r = matches.data[j].query('action', 'request').where(lambda x: x['rno'] == i+2 and x['from'] == row['a']).raw_data rs = matches.data[j].query('action', 'approve').where(lambda x: x['rno'] == i+2 and x['to'] == row['a']).raw_data if row['act_a'] == 'C': - cReSu.append(len(rs)) - cReFa.append(len(r) - len(rs)) + c_req_succ[j] += len(rs) + c_req[j] += len(r) else: - dReSu.append(len(rs)) - dReFa.append(len(r) - len(rs)) + d_req_succ[j] += len(rs) + d_req[j] += len(r) calced.add(row['a']) if row['b'] not in calced: r = matches.data[j].query('action', 'request').where(lambda x: x['rno'] == i+2 and x['from'] == row['b']).raw_data rs = matches.data[j].query('action', 'approve').where(lambda x: x['rno'] == i+2 and x['to'] == row['b']).raw_data if row['act_b'] == 'C': - cReSu.append(len(rs)) - cReFa.append(len(r) - len(rs)) + c_req_succ[j] += len(rs) + c_req[j] += len(r) else: - dReSu.append(len(rs)) - dReFa.append(len(r) - len(rs)) + d_req_succ[j] += len(rs) + d_req[j] += len(r) calced.add(row['b']) - if cReSu: - cm = mean(cReSu) - cs = std(cReSu) - else: - cm = 0 - cs = 0 - c_req_suc_mean.append(cm) - c_req_suc_std.append(cs) - if cReFa: - cm = mean(cReFa) - cs = std(cReFa) - else: - cm = 0 - cs = 0 - c_req_fail_mean.append(cm) - c_req_fail_std.append(cs) - if dReSu: - dm = mean(dReSu) - ds = std(dReSu) - else: - dm = 0 - ds = 0 - d_req_suc_mean.append(dm) - d_req_suc_std.append(ds) - if dReFa: - dm = mean(dReFa) - ds = std(dReFa) - else: - dm = 0 - ds = 0 - d_req_fail_mean.append(dm) - d_req_fail_std.append(ds) +c_req_succ_fr = c_req_succ / c_req +d_req_succ_fr = d_req_succ / d_req -fig, ax = plt.subplots() -index = np.arange(17) -bar_width = 0.35 -opacity = 0.6 -error_config = {'ecolor': '0.3', 'capsize': 4} -rects1 = ax.bar(index, c_req_suc_mean, bar_width, - alpha=opacity, color='g', - # yerr=c_req_suc_std, error_kw=error_config, - label='C-Req-Success') -rects2 = ax.bar(index, c_req_fail_mean, bar_width, - alpha=opacity, color='b', - # yerr=c_req_fail_std, error_kw=error_config, - bottom=c_req_suc_mean, - label='C-Req-Fail') +# print(c_req_succ) +# print(c_req) +# print(c_req_succ_fr) +# print(d_req_succ) +# print(d_req) +# print(d_req_succ_fr) + +req_succ_fr_mean = [mean(c_req_succ_fr), mean(d_req_succ_fr)] +req_succ_fr_sem = [std(c_req_succ_fr), std(d_req_succ_fr)] + +req_succ = [c_req_succ_fr, d_req_succ_fr] + +fig = plt.figure(figsize=(4, 3)) +ax = fig.gca() +index = np.arange(2) +bar_width = 0.5 +opacity = 1 +error_config = {'ecolor': '0.3', 'capsize': 2, 'linewidth': 1} +# rects1 = ax.bar(index, req_succ_fr_mean, bar_width, +# alpha=opacity, color='#0984e3', +# yerr=req_succ_fr_sem, error_kw=error_config, +# label='C-Req-Success') +flier_marker = dict(markerfacecolor='w', marker='o', markersize=4, markeredgewidth=0.5) +mean_marker = dict(markerfacecolor='w', marker='s', markeredgecolor='#0984e3', markersize=5, markeredgewidth=1) +ax.boxplot(req_succ, showmeans=True, notch=True, + meanprops=mean_marker, flierprops=flier_marker, + whis=[0.15,99.85], + widths=0.4, + labels=['Cooperation', 'Defection']) + +m1 = np.median(c_req_succ_fr) +m2 = np.median(d_req_succ_fr) +# i1 = np.subtract(*np.percentile(c_req_succ_fr, [75*0.98, 25*0.98])) +# i2 = np.subtract(*np.percentile(d_req_succ_fr, [75*0.98, 25*0.98])) +i1 = np.subtract(*np.percentile(c_req_succ_fr, [75, 25])) +i2 = np.subtract(*np.percentile(d_req_succ_fr, [75, 25])) + + + +print('M=(%f, %f)' % (m1, m2)) +print('IQR=(%f, %f)' % (i1, i2)) -rects3 = ax.bar(index + bar_width, d_req_suc_mean, bar_width, - alpha=opacity, color='y', - # yerr=d_req_suc_mean, error_kw=error_config, - label='D-Req-Success') -rects4 = ax.bar(index + bar_width, d_req_fail_mean, bar_width, - alpha=opacity, color='r', - # yerr=d_req_fail_mean, error_kw=error_config, - bottom=d_req_suc_mean, - label='D-Req-Fail') # ax.set_xlabel('Group') -# ax.set_ylabel('Scores') -# ax.set_title('Scores by group and gender') -ax.set_xticks(index + bar_width / 2) -ax.set_xticklabels(index+1) -ax.legend() +ax.set_ylabel('Rate') +ax.set_title('Request Approving Rate after Specific Actions', fontsize='small', weight='semibold') +# ax.set_xticks(index) +# ax.set_ylim(0, 1) +# ax.set_xlim(-0.75, 1.75) +# ax.set_xticklabels(index+2) +# ax.legend() fig.tight_layout() -plt.show() \ No newline at end of file +# plt.show() +plt.savefig('graph/request_success.eps') \ No newline at end of file diff --git a/request_success_per_round.py b/request_success_per_round.py new file mode 100644 index 0000000..4c84de1 --- /dev/null +++ b/request_success_per_round.py @@ -0,0 +1,124 @@ +import json +from matplotlib import pyplot as plt +from island.match import Match +from island.matches import Matches +from numpy import mean, std +import numpy as np + + +matches = Matches('wos-data-new') +max_round = 13 + +c_req_suc_mean = [] +d_req_suc_mean = [] +c_req_suc_std = [] +d_req_suc_std = [] + +c_req_fail_mean = [] +d_req_fail_mean = [] +c_req_fail_std = [] +d_req_fail_std = [] + +for i in range(max_round): + cReSu = [] + cReFa = [] + dReSu = [] + dReFa = [] + for j in range(len(matches.data)): + rows = matches.data[j].query('action', 'done').where(lambda x: x['rno'] == i+1).raw_data + calced = set() + for row in rows: + if row['a'] not in calced: + r = matches.data[j].query('action', 'request').where(lambda x: x['rno'] == i+2 and x['from'] == row['a']).raw_data + rs = matches.data[j].query('action', 'approve').where(lambda x: x['rno'] == i+2 and x['to'] == row['a']).raw_data + if row['act_a'] == 'C': + cReSu.append(len(rs)) + cReFa.append(len(r) - len(rs)) + else: + dReSu.append(len(rs)) + dReFa.append(len(r) - len(rs)) + calced.add(row['a']) + + if row['b'] not in calced: + r = matches.data[j].query('action', 'request').where(lambda x: x['rno'] == i+2 and x['from'] == row['b']).raw_data + rs = matches.data[j].query('action', 'approve').where(lambda x: x['rno'] == i+2 and x['to'] == row['b']).raw_data + if row['act_b'] == 'C': + cReSu.append(len(rs)) + cReFa.append(len(r) - len(rs)) + else: + dReSu.append(len(rs)) + dReFa.append(len(r) - len(rs)) + calced.add(row['b']) + + if cReSu: + cm = mean(cReSu) + cs = std(cReSu) + else: + cm = 0 + cs = 0 + c_req_suc_mean.append(cm) + c_req_suc_std.append(cs) + + if cReFa: + cm = mean(cReFa) + cs = std(cReFa) + else: + cm = 0 + cs = 0 + c_req_fail_mean.append(cm) + c_req_fail_std.append(cs) + + if dReSu: + dm = mean(dReSu) + ds = std(dReSu) + else: + dm = 0 + ds = 0 + d_req_suc_mean.append(dm) + d_req_suc_std.append(ds) + + if dReFa: + dm = mean(dReFa) + ds = std(dReFa) + else: + dm = 0 + ds = 0 + d_req_fail_mean.append(dm) + d_req_fail_std.append(ds) + +fig = plt.figure(figsize=(6.4, 4)) +ax = fig.gca() +index = np.arange(max_round) +bar_width = 0.35 +opacity = 1 +error_config = {'ecolor': '0.3', 'capsize': 4} +rects1 = ax.bar(index, c_req_suc_mean, bar_width, + alpha=opacity, color='#00b894', + # yerr=c_req_suc_std, error_kw=error_config, + label='Approve after Cooperation') +rects2 = ax.bar(index, c_req_fail_mean, bar_width, + alpha=opacity, color='#0984e3', + # yerr=c_req_fail_std, error_kw=error_config, + bottom=c_req_suc_mean, + label='Deny after Cooperation') + +rects3 = ax.bar(index + bar_width, d_req_suc_mean, bar_width, + alpha=opacity, color='#fdcb6e', + # yerr=d_req_suc_mean, error_kw=error_config, + label='Approve after Defection') + +rects4 = ax.bar(index + bar_width, d_req_fail_mean, bar_width, + alpha=opacity, color='#d63031', + # yerr=d_req_fail_mean, error_kw=error_config, + bottom=d_req_suc_mean, + label='Deny after Defection') + +ax.set_xlabel('Round') +ax.set_ylabel('Number of Requests') +# ax.set_title('Scores by group and gender') +ax.set_xticks(index + bar_width / 2) +ax.set_xticklabels(index+2) +ax.legend() +fig.tight_layout() +# plt.show() +plt.savefig('graph/request_success_per_round.eps') \ No newline at end of file diff --git a/unlink_has_neighbor.py b/unlink_has_neighbor.py index c6ff7d8..a147172 100644 --- a/unlink_has_neighbor.py +++ b/unlink_has_neighbor.py @@ -7,17 +7,18 @@ matches = Matches('wos-data-new') labels = ['has neighbor', 'no neighbor'] percents = [0.0, 0.0] +op = 'C' for m in matches.data: info = m.query('game', 'created').select('info').first()['info'] conf = json.loads(info['config']) game_end_at = int(info['game_end_at']) - for row in m.query('action', 'done').where(lambda x: x['act_a'] == 'D' or x['act_b'] == 'D').raw_data: + for row in m.query('action', 'done').where(lambda x: x['act_a'] == op or x['act_b'] == op).raw_data: if row['rno'] == game_end_at: print(row) continue - if row['act_a'] == 'D': + if row['act_a'] == op: a = row['a'] b = row['b'] n = m.query('action', 'done').where(lambda y: ((y['a'] == a and y['b'] == b) or (y['a'] == b and y['b'] == a)) and y['rno'] == row['rno'] + 1).raw_data @@ -29,7 +30,7 @@ for m in matches.data: percents[0] += 1 else: percents[1] += 1 - if row['act_b'] == 'D': + if row['act_b'] == op: a = row['a'] b = row['b'] n = m.query('action', 'done').where(lambda y: ((y['a'] == a and y['b'] == b) or (y['a'] == b and y['b'] == a)) and y['rno'] == row['rno'] + 1).raw_data