1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
#!/usr/bin/env python
"""
An example of the XDiGraph class with multiple
edges (multiedges=True)).
The function chess_pgn_graph reads a collection of chess
matches stored in the specified PGN file
(PGN ="Portable Game Notation")
Here the (compressed) default file ---
chess_masters_WCC.pgn.bz2 ---
contains all 685 World Chess Championship matches
from 1886 - 1985.
(data from http://chessproblem.my-free-games.com/chess/games/Download-PGN.php)
The chess_pgn_graph() function returns an XDiGraph
with multiple edges but no self-loops. Each node is
the last name of a chess master. Each edge is directed
from white to black and contains selected game info.
The key statement in chess_pgn_graph below is
G.add_edge(white, black, game_info)
where game_info is a dict describing each game.
"""
# Copyright (C) 2006 by
# Aric Hagberg <hagberg@lanl.gov>
# Dan Schult <dschult@colgate.edu>
# Pieter Swart <swart@lanl.gov>
# Distributed under the terms of the GNU Lesser General Public License
# http://www.gnu.org/copyleft/lesser.html
from networkx import *
# tag names specifying what game info should be
# stored in the dict on each digraph edge
game_details=[
"Event",
"Date",
"Result",
"ECO",
"Site"
]
def chess_pgn_graph(pgn_file="chess_masters_WCC.pgn.bz2"):
"""Read chess games in pgn format in pgn_file.
Filenames ending in .gz or .bz2 will be uncompressed.
Return the XDiGraph of players connected by a chess game.
Edges contain game data in a dict.
"""
try:# use networkx.io._get_fh to uncompress
# pgn file if required
datafile=io._get_fh(pgn_file,mode='rb')
except IOError:
print "Could not read file %s."%(pgn_file)
raise
G=XDiGraph(multiedges=True)
game_info={}
for line in datafile.read().splitlines():
# check for tag pairs
if len(line)>0 and line[0]=='[':
line=line[1:-1] # remove extra quotes
tag = line.split()[0]
value=line[len(tag)+2:-1]
if tag=='White':
white=value.split(',')[0]
elif tag=='Black':
black=value.split(',')[0]
elif tag in game_details:
game_info[tag]=value
# empty line after tag set indicates
# we finished reading game info
elif len(line)==0:
if len(game_info)>0:
G.add_edge(white, black, game_info)
game_info={}
return G
if __name__ == '__main__':
from networkx import *
try:
import pylab as P
except:
print """pylab not found:
see https://networkx.lanl.gov/Drawing.html for info"""
raise
G=chess_pgn_graph()
ngames=G.number_of_edges()
nplayers=G.number_of_nodes()
print "Loaded %d chess games between %d players\n"\
% (ngames,nplayers)
# identify connected components
# of the undirected version
Gcc=connected_component_subgraphs(G.to_undirected())
if len(Gcc)>1:
print "Note the disconnected component consisting of:"
print Gcc[1].nodes()
# find all games with B97 opening (as described in ECO)
openings=set([game_info['ECO'] for (white,black,game_info) in G.edges()])
print "\nFrom a total of %d different openings,"%len(openings)
print 'the following games used the Sicilian opening'
print 'with the Najdorff 7...Qb6 "Poisoned Pawn" variation.\n'
for (white,black,game_info) in G.edges():
if game_info['ECO']=='B97':
print white,"vs",black
for k,v in game_info.items():
print " ",k,": ",v
print "\n"
try: # drawing
P.figure(figsize=(8,8))
# make new undirected graph H without multi-edges
H=G.copy()
H.ban_multiedges()
H=H.to_undirected()
# edge width is proportional number of games played
edgewidth=[]
for (u,v,d) in H.edges():
edgewidth.append(len(G.get_edge(u,v)))
# node size is proportional to number of games won
wins=dict.fromkeys(G.nodes(),0.0)
for (u,v,d) in G.edges():
r=d['Result'].split('-')
if r[0]=='1':
wins[u]+=1.0
elif r[0]=='1/2':
wins[u]+=0.5
wins[v]+=0.5
else:
wins[v]+=1.0
pos=graphviz_layout(H)
draw_networkx_edges(H,pos,
alpha=0.3,
width=edgewidth,
edge_color='m'
)
draw_networkx_nodes(H,pos,
node_size=[wins[v]*35 for v in H],
node_color='r',
alpha=0.4,
)
draw_networkx_edges(H,pos,
alpha=0.4,
node_size=0,
width=1,
edge_color='k'
)
draw_networkx_labels(H,pos,
fontsize=14)
font = {'fontname' : 'Helvetica',
'color' : 'k',
'fontweight' : 'bold',
'fontsize' : 14}
P.title("World Chess Championship Games: 1886 - 1985", font)
# change font and write text (using data coordinates)
font = {'fontname' : 'Helvetica',
'color' : 'r',
'fontweight' : 'bold',
'fontsize' : 14}
xmin, xmax, ymin, ymax = P.axis()
dx = xmax - xmin
dy = ymax - ymin
x = 0.1*dx + xmin
y = 0.9*dy + ymin
P.text(x, y, "edge width = # games played")
y = 0.85*dy + ymin
P.text(x, y, "node size = # games won")
# turn off x and y axes labels in pylab
P.xticks([])
P.yticks([])
P.savefig("chess_masters_graph.png",dpi=75)
print "Wrote chess_masters_graph.png"
P.show() # display
except:
print "Unable to draw: problem with graphviz or pylab"
|