Update GuiSessionViewer.

Still horribly broken, but on its way
This commit is contained in:
Worros 2009-10-21 17:22:47 +08:00
parent 4f754fa881
commit 58707d2022
2 changed files with 170 additions and 138 deletions

292
pyfpdb/GuiSessionViewer.py Normal file → Executable file
View File

@ -15,6 +15,7 @@
#In the "official" distribution you can find the license in #In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package. #agpl-3.0.txt in the docs folder of the package.
import sys
import threading import threading
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
@ -22,7 +23,10 @@ import gtk
import os import os
from time import time, strftime, localtime from time import time, strftime, localtime
try: try:
from numpy import diff, nonzero from numpy import diff, nonzero, sum
# from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \
# DayLocator, MONDAY, timezone
except: except:
print """Failed to load numpy in Session Viewer""" print """Failed to load numpy in Session Viewer"""
print """This is of no consequence as the module currently doesn't do anything.""" print """This is of no consequence as the module currently doesn't do anything."""
@ -34,10 +38,13 @@ import Filters
import FpdbSQLQueries import FpdbSQLQueries
class GuiSessionViewer (threading.Thread): class GuiSessionViewer (threading.Thread):
def __init__(self, config, querylist, debug=True): def __init__(self, config, querylist, mainwin, debug=True):
self.debug = debug self.debug = debug
self.conf = config self.conf = config
self.sql = querylist self.sql = querylist
self.liststore = None
self.MYSQL_INNODB = 2 self.MYSQL_INNODB = 2
self.PGSQL = 3 self.PGSQL = 3
self.SQLITE = 4 self.SQLITE = 4
@ -56,55 +63,63 @@ class GuiSessionViewer (threading.Thread):
self.filterText = {'handhead':'Hand Breakdown for all levels listed above' self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
} }
filters_display = { "Heroes" : True, filters_display = { "Heroes" : True,
"Sites" : True, "Sites" : True,
"Games" : False, "Games" : False,
"Limits" : True, "Limits" : True,
"LimitSep" : True, "LimitSep" : True,
"Seats" : True, "LimitType" : True,
"SeatSep" : True, "Type" : True,
"Dates" : False, "Seats" : True,
"Groups" : True, "SeatSep" : True,
"Button1" : True, "Dates" : True,
"Button2" : True "Groups" : True,
"GroupsAll" : True,
"Button1" : True,
"Button2" : True
} }
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display) self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
self.filters.registerButton2Name("_Refresh") self.filters.registerButton1Name("_Refresh")
self.filters.registerButton2Callback(self.refreshStats) self.filters.registerButton1Callback(self.refreshStats)
# ToDo: store in config # ToDo: store in config
# ToDo: create popup to adjust column config # ToDo: create popup to adjust column config
# columns to display, keys match column name returned by sql, values in tuple are: # columns to display, keys match column name returned by sql, values in tuple are:
# is column displayed, column heading, xalignment, formatting # is column displayed, column heading, xalignment, formatting
self.columns = [ ("game", True, "Game", 0.0, "%s") self.columns = [ ("sid", True, "SID", 0.0, "%s")
, ("hand", False, "Hand", 0.0, "%s") # true not allowed for this line , ("hand", False, "Hand", 0.0, "%s") # true not allowed for this line
, ("n", True, "Hds", 1.0, "%d") , ("n", True, "Hds", 1.0, "%d")
, ("avgseats", True, "Seats", 1.0, "%3.1f") , ("start", True, "Start", 1.0, "%d")
, ("vpip", True, "VPIP", 1.0, "%3.1f") , ("end", True, "End", 1.0, "%d")
, ("pfr", True, "PFR", 1.0, "%3.1f") , ("hph", True, "Hands/h", 1.0, "%d")
, ("pf3", True, "PF3", 1.0, "%3.1f") , ("profit", True, "Profit", 1.0, "%s")
, ("steals", True, "Steals", 1.0, "%3.1f") #, ("avgseats", True, "Seats", 1.0, "%3.1f")
, ("saw_f", True, "Saw_F", 1.0, "%3.1f") #, ("vpip", True, "VPIP", 1.0, "%3.1f")
, ("sawsd", True, "SawSD", 1.0, "%3.1f") #, ("pfr", True, "PFR", 1.0, "%3.1f")
, ("wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f") #, ("pf3", True, "PF3", 1.0, "%3.1f")
, ("wmsd", True, "W$SD", 1.0, "%3.1f") #, ("steals", True, "Steals", 1.0, "%3.1f")
, ("flafq", True, "FlAFq", 1.0, "%3.1f") #, ("saw_f", True, "Saw_F", 1.0, "%3.1f")
, ("tuafq", True, "TuAFq", 1.0, "%3.1f") #, ("sawsd", True, "SawSD", 1.0, "%3.1f")
, ("rvafq", True, "RvAFq", 1.0, "%3.1f") #, ("wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f")
, ("pofafq", False, "PoFAFq", 1.0, "%3.1f") #, ("wmsd", True, "W$SD", 1.0, "%3.1f")
, ("net", True, "Net($)", 1.0, "%6.2f") #, ("flafq", True, "FlAFq", 1.0, "%3.1f")
, ("bbper100", True, "BB/100", 1.0, "%4.2f") #, ("tuafq", True, "TuAFq", 1.0, "%3.1f")
, ("rake", True, "Rake($)", 1.0, "%6.2f") #, ("rvafq", True, "RvAFq", 1.0, "%3.1f")
, ("variance", True, "Variance", 1.0, "%5.2f") #, ("pofafq", False, "PoFAFq", 1.0, "%3.1f")
#, ("net", True, "Net($)", 1.0, "%6.2f")
#, ("bbper100", True, "BB/100", 1.0, "%4.2f")
#, ("rake", True, "Rake($)", 1.0, "%6.2f")
#, ("variance", True, "Variance", 1.0, "%5.2f")
] ]
self.stats_frame = None self.stats_frame = None
self.stats_vbox = None self.stats_vbox = None
self.detailFilters = [] # the data used to enhance the sql select self.detailFilters = [] # the data used to enhance the sql select
self.main_hbox = gtk.HBox(False, 0) #self.main_hbox = gtk.HBox(False, 0)
self.main_hbox.show() #self.main_hbox.show()
self.main_hbox = gtk.HPaned()
self.stats_frame = gtk.Frame() self.stats_frame = gtk.Frame()
self.stats_frame.show() self.stats_frame.show()
@ -112,21 +127,46 @@ class GuiSessionViewer (threading.Thread):
self.stats_vbox = gtk.VBox(False, 0) self.stats_vbox = gtk.VBox(False, 0)
self.stats_vbox.show() self.stats_vbox.show()
self.stats_frame.add(self.stats_vbox) self.stats_frame.add(self.stats_vbox)
self.fillStatsFrame(self.stats_vbox) # self.fillStatsFrame(self.stats_vbox)
self.main_hbox.pack_start(self.filters.get_vbox())
self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
################################
#self.main_hbox.pack_start(self.filters.get_vbox())
#self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
self.main_hbox.pack1(self.filters.get_vbox())
self.main_hbox.pack2(self.stats_frame)
self.main_hbox.show()
# make sure Hand column is not displayed # make sure Hand column is not displayed
[x for x in self.columns if x[0] == 'hand'][0][1] == False #[x for x in self.columns if x[0] == 'hand'][0][1] = False
def get_vbox(self): def get_vbox(self):
"""returns the vbox of this thread""" """returns the vbox of this thread"""
return self.main_hbox return self.main_hbox
def generateGraph(self):
fig = figure()
fig.subplots_adjust(bottom=0.2)
ax = fig.add_subplot(111)
ax.xaxis.set_major_locator(mondays)
ax.xaxis.set_minor_locator(alldays)
ax.xaxis.set_major_formatter(weekFormatter)
#ax.xaxis.set_minor_formatter(dayFormatter)
#plot_day_summary(ax, quotes, ticksize=3)
# candlestick(ax, quotes, width=0.6)
# candlestick2(ax, opens, closes, highs, lows, width=4, colorup='k', colordown='r', alpha=0.75)
# Represent the open, close as a bar line and high low range as a vertical line.
# ax : an Axes instance to plot to
# width : the bar width in points
# colorup : the color of the lines where close >= open
# colordown : the color of the lines where close < open
# alpha : bar transparency
# return value is lineCollection, barCollection
ax.xaxis_date()
ax.autoscale_view()
setp( gca().get_xticklabels(), rotation=45, horizontalalignment='right')
show()
def refreshStats(self, widget, data): def refreshStats(self, widget, data):
try: self.stats_vbox.destroy() try: self.stats_vbox.destroy()
except AttributeError: pass except AttributeError: pass
@ -209,105 +249,97 @@ class GuiSessionViewer (threading.Thread):
if not flags: holecards = False if not flags: holecards = False
else: holecards = flags[0] else: holecards = flags[0]
# pre-fetch some constant values:
cols_to_show = [x for x in self.columns if x[colshow]]
self.stats_table = gtk.Table(1, 1, False) self.liststore = gtk.ListStore(*([str] * len(cols_to_show)))
self.stats_table.set_col_spacings(4)
self.stats_table.show() view = gtk.TreeView(model=self.liststore)
view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
self.db.cursor.execute("""select UNIX_TIMESTAMP(handStart) as time, id from Hands ORDER BY time""") vbox.add(view)
textcell = gtk.CellRendererText()
textcell50 = gtk.CellRendererText()
textcell50.set_property('xalign', 0.5)
numcell = gtk.CellRendererText()
numcell.set_property('xalign', 1.0)
listcols = []
# Create header row eg column: ("game", True, "Game", 0.0, "%s")
for col, column in enumerate(cols_to_show):
s = column[colheading]
listcols.append(gtk.TreeViewColumn(s))
view.append_column(listcols[col])
if column[colformat] == '%s':
if column[colxalign] == 0.0:
listcols[col].pack_start(textcell, expand=True)
listcols[col].add_attribute(textcell, 'text', col)
else:
listcols[col].pack_start(textcell50, expand=True)
listcols[col].add_attribute(textcell50, 'text', col)
listcols[col].set_expand(True)
else:
listcols[col].pack_start(numcell, expand=True)
listcols[col].add_attribute(numcell, 'text', col)
listcols[col].set_expand(True)
# Get a list of all handids and their timestampts
# FIXME: Will probably want to be able to filter this list eventually
# FIXME: Join on handsplayers for Hero to get other useful stuff like total profit?
q = """
select UNIX_TIMESTAMP(h.handStart) as time, hp.handId, hp.startCash, hp.winnings, hp.totalProfit
from HandsPlayers hp
inner join Hands h on (h.id = hp.handId)
inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId)
inner join Players p on (p.Id = hp.playerId)
where hp.playerId in (2)
order by time
"""
self.db.cursor.execute(q)
THRESHOLD = 1800 THRESHOLD = 1800
hands = self.db.cursor.fetchall() hands = self.db.cursor.fetchall()
# Take that list and create an array of the time between hands
times = map(lambda x:long(x[0]), hands) times = map(lambda x:long(x[0]), hands)
handids = map(lambda x:int(x[1]), hands) handids = map(lambda x:int(x[1]), hands)
winnings = map(lambda x:int(x[4]), hands)
print "DEBUG: len(times) %s" %(len(times)) print "DEBUG: len(times) %s" %(len(times))
diffs = diff(times) diffs = diff(times) # This array is the difference in starttime between consecutive hands
print "DEBUG: len(diffs) %s" %(len(diffs)) index = nonzero(diff(times) > THRESHOLD) # This array represents the indexes into 'times' for start/end times of sessions
index = nonzero(diff(times) > THRESHOLD) # ie. times[index[0][0]] is the end of the first session
print "DEBUG: len(index[0]) %s" %(len(index[0])) #print "DEBUG: len(index[0]) %s" %(len(index[0]))
print "DEBUG: index %s" %(index) #print "DEBUG: index %s" %(index)
print "DEBUG: index[0][0] %s" %(index[0][0]) #print "DEBUG: index[0][0] %s" %(index[0][0])
total = 0 total = 0
last_idx = 0 last_idx = 0
lowidx = 0
uppidx = 0
results = []
# Take all results and format them into a list for feeding into gui model.
for i in range(len(index[0])): for i in range(len(index[0])):
print "Hands in session %4s: %4s Start: %s End: %s Total: %s" %(i, index[0][i] - last_idx, strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])), strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])), times[index[0][i]] - times[last_idx]) sid = i # Session id
hds = index[0][i] - last_idx # Number of hands in session
stime = strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])) # Formatted start time
etime = strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])) # Formatted end time
hph = (times[index[0][i]] - times[last_idx])/60 # Hands per hour
won = sum(winnings[last_idx:index[0][i]])
print "DEBUG: range: %s - %s" %(last_idx, index[0][i])
results.append([sid, hds, stime, etime, hph, won])
print "Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won)
total = total + (index[0][i] - last_idx) total = total + (index[0][i] - last_idx)
last_idx = index[0][i] + 1 last_idx = index[0][i] + 1
print "Total: ", total for row in results:
# iter = self.liststore.append(row)
# colnames = [desc[0].lower() for desc in self.cursor.description]
#
# # pre-fetch some constant values:
# cols_to_show = [x for x in self.columns if x[colshow]]
# hgametypeid_idx = colnames.index('hgametypeid')
#
# liststore = gtk.ListStore(*([str] * len(cols_to_show)))
# view = gtk.TreeView(model=liststore)
# view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
# vbox.pack_start(view, expand=False, padding=3)
# textcell = gtk.CellRendererText()
# numcell = gtk.CellRendererText()
# numcell.set_property('xalign', 1.0)
# listcols = []
#
# # Create header row eg column: ("game", True, "Game", 0.0, "%s")
# for col, column in enumerate(cols_to_show):
# if column[colalias] == 'game' and holecards:
# s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading]
# else:
# s = column[colheading]
# listcols.append(gtk.TreeViewColumn(s))
# view.append_column(listcols[col])
# if column[colformat] == '%s':
# if col == 1 and holecards:
# listcols[col].pack_start(textcell, expand=True)
# else:
# listcols[col].pack_start(textcell, expand=False)
# listcols[col].add_attribute(textcell, 'text', col)
# else:
# listcols[col].pack_start(numcell, expand=False)
# listcols[col].add_attribute(numcell, 'text', col)
#
# rows = len(result) # +1 for title row
#
# while sqlrow < rows:
# treerow = []
# if(row%2 == 0):
# bgcolor = "white"
# else:
# bgcolor = "lightgrey"
# for col,column in enumerate(cols_to_show):
# if column[colalias] in colnames:
# value = result[sqlrow][colnames.index(column[colalias])]
# else:
# if column[colalias] == 'game':
# if holecards:
# value = Card.twoStartCardString( result[sqlrow][hgametypeid_idx] )
# else:
# minbb = result[sqlrow][colnames.index('minbigblind')]
# maxbb = result[sqlrow][colnames.index('maxbigblind')]
# value = result[sqlrow][colnames.index('limittype')] + ' ' \
# + result[sqlrow][colnames.index('category')].title() + ' ' \
# + result[sqlrow][colnames.index('name')] + ' $'
# if 100 * int(minbb/100.0) != minbb:
# value += '%.2f' % (minbb/100.0)
# else:
# value += '%.0f' % (minbb/100.0)
# if minbb != maxbb:
# if 100 * int(maxbb/100.0) != maxbb:
# value += ' - $' + '%.2f' % (maxbb/100.0)
# else:
# value += ' - $' + '%.0f' % (maxbb/100.0)
# else:
# continue
# if value and value != -999:
# treerow.append(column[colformat] % value)
# else:
# treerow.append(' ')
# iter = liststore.append(treerow)
# sqlrow += 1
# row += 1
vbox.show_all() vbox.show_all()
def main(argv=None):
config = Configuration.Config()
i = GuiBulkImport(settings, config)
if __name__ == '__main__':
sys.exit(main())

View File

@ -155,12 +155,6 @@ class fpdb:
def dia_database_stats(self, widget, data=None): def dia_database_stats(self, widget, data=None):
self.warning_box("Unimplemented: Database Stats") self.warning_box("Unimplemented: Database Stats")
def dia_database_sessions(self, widget, data=None):
new_sessions_thread = GuiSessionViewer.GuiSessionViewer(self.config, self.sql)
self.threads.append(new_sessions_thread)
sessions_tab=new_sessions_thread.get_vbox()
self.add_and_display_tab(sessions_tab, "Sessions")
def dia_delete_db_parts(self, widget, data=None): def dia_delete_db_parts(self, widget, data=None):
self.warning_box("Unimplemented: Delete Database Parts") self.warning_box("Unimplemented: Delete Database Parts")
self.obtain_global_lock() self.obtain_global_lock()
@ -368,6 +362,7 @@ class fpdb:
<menuitem action="playerdetails"/> <menuitem action="playerdetails"/>
<menuitem action="playerstats"/> <menuitem action="playerstats"/>
<menuitem action="posnstats"/> <menuitem action="posnstats"/>
<menuitem action="sessionstats"/>
<menuitem action="sessionreplay"/> <menuitem action="sessionreplay"/>
<menuitem action="tableviewer"/> <menuitem action="tableviewer"/>
</menu> </menu>
@ -377,7 +372,6 @@ class fpdb:
<menuitem action="createtabs"/> <menuitem action="createtabs"/>
<menuitem action="rebuildhudcache"/> <menuitem action="rebuildhudcache"/>
<menuitem action="stats"/> <menuitem action="stats"/>
<menuitem action="sessions"/>
</menu> </menu>
<menu action="help"> <menu action="help">
<menuitem action="Abbrev"/> <menuitem action="Abbrev"/>
@ -409,6 +403,7 @@ class fpdb:
('playerdetails', None, 'Player _Details (todo)', None, 'Player Details (todo)', self.not_implemented), ('playerdetails', None, 'Player _Details (todo)', None, 'Player Details (todo)', self.not_implemented),
('playerstats', None, '_Player Stats (tabulated view)', '<control>P', 'Player Stats (tabulated view)', self.tab_player_stats), ('playerstats', None, '_Player Stats (tabulated view)', '<control>P', 'Player Stats (tabulated view)', self.tab_player_stats),
('posnstats', None, 'P_ositional Stats (tabulated view)', '<control>O', 'Positional Stats (tabulated view)', self.tab_positional_stats), ('posnstats', None, 'P_ositional Stats (tabulated view)', '<control>O', 'Positional Stats (tabulated view)', self.tab_positional_stats),
('sessionstats', None, 'Session Stats', None, 'Session Stats', self.tab_session_stats),
('sessionreplay', None, '_Session Replayer (todo)', None, 'Session Replayer (todo)', self.not_implemented), ('sessionreplay', None, '_Session Replayer (todo)', None, 'Session Replayer (todo)', self.not_implemented),
('tableviewer', None, 'Poker_table Viewer (mostly obselete)', None, 'Poker_table Viewer (mostly obselete)', self.tab_table_viewer), ('tableviewer', None, 'Poker_table Viewer (mostly obselete)', None, 'Poker_table Viewer (mostly obselete)', self.tab_table_viewer),
('database', None, '_Database'), ('database', None, '_Database'),
@ -417,7 +412,6 @@ class fpdb:
('createtabs', None, 'Create or Recreate _Tables', None, 'Create or Recreate Tables ', self.dia_recreate_tables), ('createtabs', None, 'Create or Recreate _Tables', None, 'Create or Recreate Tables ', self.dia_recreate_tables),
('rebuildhudcache', None, 'Rebuild HUD Cache', None, 'Rebuild HUD Cache', self.dia_recreate_hudcache), ('rebuildhudcache', None, 'Rebuild HUD Cache', None, 'Rebuild HUD Cache', self.dia_recreate_hudcache),
('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats), ('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats),
('sessions', None, 'Sessions', None, 'View Sessions', self.dia_database_sessions),
('help', None, '_Help'), ('help', None, '_Help'),
('Abbrev', None, '_Abbrevations (todo)', None, 'List of Abbrevations', self.tab_abbreviations), ('Abbrev', None, '_Abbrevations (todo)', None, 'List of Abbrevations', self.tab_abbreviations),
('About', None, 'A_bout', None, 'About the program', self.dia_about), ('About', None, 'A_bout', None, 'About the program', self.dia_about),
@ -554,6 +548,12 @@ class fpdb:
ps_tab=new_ps_thread.get_vbox() ps_tab=new_ps_thread.get_vbox()
self.add_and_display_tab(ps_tab, "Positional Stats") self.add_and_display_tab(ps_tab, "Positional Stats")
def tab_session_stats(self, widget, data=None):
new_ps_thread = GuiSessionViewer.GuiSessionViewer(self.config, self.sql, self.window)
self.threads.append(new_ps_thread)
ps_tab=new_ps_thread.get_vbox()
self.add_and_display_tab(ps_tab, "Session Stats")
def tab_main_help(self, widget, data=None): def tab_main_help(self, widget, data=None):
"""Displays a tab with the main fpdb help screen""" """Displays a tab with the main fpdb help screen"""
mh_tab=gtk.Label("""Welcome to Fpdb! mh_tab=gtk.Label("""Welcome to Fpdb!