2 # -*- coding: utf-8 -*-
4 #Copyright 2008-2011 Carl Gherardi
5 #This program is free software: you can redistribute it and/or modify
6 #it under the terms of the GNU Affero General Public License as published by
7 #the Free Software Foundation, version 3 of the License.
9 #This program is distributed in the hope that it will be useful,
10 #but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 #GNU General Public License for more details.
14 #You should have received a copy of the GNU Affero General Public License
15 #along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #In the "official" distribution you can find the license in agpl-3.0.txt.
19 _
= L10n
.get_translation()
29 from datetime
import datetime
38 calluse
= not 'matplotlib' in sys
.modules
41 matplotlib
.use('GTKCairo')
42 from matplotlib
.figure
import Figure
43 from matplotlib
.backends
.backend_gtk
import FigureCanvasGTK
as FigureCanvas
44 from matplotlib
.backends
.backend_gtkagg
import NavigationToolbar2GTKAgg
as NavigationToolbar
45 from matplotlib
.font_manager
import FontProperties
46 from numpy
import arange
, cumsum
48 except ImportError, inst
:
49 print _("""Failed to load libs for graphing, graphing will not function. Please install numpy and matplotlib if you want to use graphs.""")
50 print _("""This is of no consequence for other parts of the program, e.g. import and HUD are NOT affected by this problem.""")
51 print "ImportError: %s" % inst
.args
53 class GuiTourneyGraphViewer (threading
.Thread
):
55 def __init__(self
, querylist
, config
, parent
, debug
=True):
56 """Constructor for GraphViewer"""
61 #print "start of GraphViewer constructor"
62 self
.db
= Database
.Database(self
.conf
, sql
=self
.sql
)
65 filters_display
= { "Heroes" : True,
81 self
.filters
= Filters
.Filters(self
.db
, self
.conf
, self
.sql
, display
= filters_display
)
82 self
.filters
.registerButton1Name(_("Refresh _Graph"))
83 self
.filters
.registerButton1Callback(self
.generateGraph
)
84 self
.filters
.registerButton2Name(_("_Export to File"))
85 self
.filters
.registerButton2Callback(self
.exportGraph
)
87 self
.mainHBox
= gtk
.HBox(False, 0)
90 self
.leftPanelBox
= self
.filters
.get_vbox()
92 self
.hpane
= gtk
.HPaned()
93 self
.hpane
.pack1(self
.leftPanelBox
)
94 self
.mainHBox
.add(self
.hpane
)
95 # hierarchy: self.mainHBox / self.hpane / self.graphBox / self.canvas / self.fig / self.ax
97 self
.graphBox
= gtk
.VBox(False, 0)
99 self
.hpane
.pack2(self
.graphBox
)
103 #self.exportButton.set_sensitive(False)
110 """returns the vbox of this thread"""
114 def clearGraphData(self
):
117 self
.graphBox
.remove(self
.canvas
)
123 self
.fig
= Figure(figsize
=(5,4), dpi
=100)
124 if self
.canvas
is not None:
125 self
.canvas
.destroy()
127 self
.canvas
= FigureCanvas(self
.fig
) # a gtk.DrawingArea
129 def generateGraph(self
, widget
, data
):
130 self
.clearGraphData()
135 sites
= self
.filters
.getSites()
136 heroes
= self
.filters
.getHeroes()
137 siteids
= self
.filters
.getSiteIds()
139 # Which sites are selected?
141 if sites
[site
] == True:
142 sitenos
.append(siteids
[site
])
143 _hname
= Charset
.to_utf8(heroes
[site
])
144 result
= self
.db
.get_player_id(self
.conf
, site
, _hname
)
145 if result
is not None:
146 playerids
.append(int(result
))
149 #Should probably pop up here.
150 print _("No sites selected - defaulting to PokerStars")
155 print _("No player ids found")
159 #Set graph properties
160 self
.ax
= self
.fig
.add_subplot(111)
162 #Get graph data from DB
164 green
= self
.getData(playerids
, sitenos
)
165 print _("Graph generated in: %s") %(time() - starttime
)
168 #Set axis labels and grid overlay properites
169 self
.ax
.set_xlabel(_("Tournaments"), fontsize
= 12)
170 self
.ax
.set_ylabel("$", fontsize
= 12)
171 self
.ax
.grid(color
='g', linestyle
=':', linewidth
=0.2)
172 if green
== None or green
== []:
173 self
.ax
.set_title(_("No Data for Player(s) Found"))
174 green
= ([ 0., 0., 0., 0., 500., 1000., 900., 800.,
175 700., 600., 500., 400., 300., 200., 100., 0.,
176 500., 1000., 1000., 1000., 1000., 1000., 1000., 1000.,
177 1000., 1000., 1000., 1000., 1000., 1000., 875., 750.,
178 625., 500., 375., 250., 125., 0., 0., 0.,
179 0., 500., 1000., 900., 800., 700., 600., 500.,
180 400., 300., 200., 100., 0., 500., 1000., 1000.])
181 red
= ([ 0., 0., 0., 0., 500., 1000., 900., 800.,
182 700., 600., 500., 400., 300., 200., 100., 0.,
183 0., 0., 0., 0., 0., 0., 125., 250.,
184 375., 500., 500., 500., 500., 500., 500., 500.,
185 500., 500., 375., 250., 125., 0., 0., 0.,
186 0., 500., 1000., 900., 800., 700., 600., 500.,
187 400., 300., 200., 100., 0., 500., 1000., 1000.])
188 blue
= ([ 0., 0., 0., 0., 500., 1000., 900., 800.,
189 700., 600., 500., 400., 300., 200., 100., 0.,
190 0., 0., 0., 0., 0., 0., 125., 250.,
191 375., 500., 625., 750., 875., 1000., 875., 750.,
192 625., 500., 375., 250., 125., 0., 0., 0.,
193 0., 500., 1000., 900., 800., 700., 600., 500.,
194 400., 300., 200., 100., 0., 500., 1000., 1000.])
196 self
.ax
.plot(green
, color
='green', label
=_('Tournaments') + ': %d\n' % len(green
) + _('Profit') + ': $%.2f' % green
[-1])
197 self
.graphBox
.add(self
.canvas
)
201 #TODO: Do something useful like alert user
203 self
.ax
.set_title(_("Tournament Results"))
206 self
.ax
.plot(green
, color
='green', label
=_('Tournaments') + ': %d\n' % len(green
) + _('Profit') + ': $%.2f' % green
[-1])
207 if sys
.version
[0:3] == '2.5':
208 self
.ax
.legend(loc
='upper left', shadow
=True, prop
=FontProperties(size
='smaller'))
210 self
.ax
.legend(loc
='upper left', fancybox
=True, shadow
=True, prop
=FontProperties(size
='smaller'))
212 self
.graphBox
.add(self
.canvas
)
215 #self.exportButton.set_sensitive(True)
217 #end of def showClicked
219 def getData(self
, names
, sites
):
220 tmp
= self
.sql
.query
['tourneyResults']
221 print "DEBUG: getData"
222 start_date
, end_date
= self
.filters
.getDates()
224 #Buggered if I can find a way to do this 'nicely' take a list of integers and longs
225 # and turn it into a tuple readale by sql.
226 # [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
227 nametest
= str(tuple(names
))
228 sitetest
= str(tuple(sites
))
230 #Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf
231 tmp
= tmp
.replace("<player_test>", nametest
)
232 tmp
= tmp
.replace("<site_test>", sitetest
)
233 tmp
= tmp
.replace("<startdate_test>", start_date
)
234 tmp
= tmp
.replace("<enddate_test>", end_date
)
235 tmp
= tmp
.replace(",)", ")")
237 print "DEBUG: sql query:"
239 self
.db
.cursor
.execute(tmp
)
240 #returns (HandId,Winnings,Costs,Profit)
241 winnings
= self
.db
.cursor
.fetchall()
244 if len(winnings
) == 0:
247 green
= map(lambda x
:float(x
[1]), winnings
)
248 #blue = map(lambda x: float(x[1]) if x[2] == True else 0.0, winnings)
249 #red = map(lambda x: float(x[1]) if x[2] == False else 0.0, winnings)
250 greenline
= cumsum(green
)
251 #blueline = cumsum(blue)
252 #redline = cumsum(red)
253 return (greenline
/100)
255 def exportGraph (self
, widget
, data
):
257 return # Might want to disable export button until something has been generated.
259 dia_chooser
= gtk
.FileChooserDialog(title
=_("Please choose the directory you wish to export to:"),
260 action
=gtk
.FILE_CHOOSER_ACTION_SELECT_FOLDER
,
261 buttons
=(gtk
.STOCK_CANCEL
,gtk
.RESPONSE_CANCEL
,gtk
.STOCK_OK
,gtk
.RESPONSE_OK
))
262 dia_chooser
.set_destroy_with_parent(True)
263 dia_chooser
.set_transient_for(self
.parent
)
265 dia_chooser
.set_filename(self
.exportFile
) # use previously chosen export path as default
269 response
= dia_chooser
.run()
271 if response
<> gtk
.RESPONSE_OK
:
272 print _('Closed, no graph exported')
273 dia_chooser
.destroy()
276 # generate a unique filename for export
278 now_formatted
= now
.strftime("%Y%m%d%H%M%S")
279 self
.exportFile
= dia_chooser
.get_filename() + "/fpdb" + now_formatted
+ ".png"
280 dia_chooser
.destroy()
282 #print "DEBUG: self.exportFile = %s" %(self.exportFile)
283 self
.fig
.savefig(self
.exportFile
, format
="png")
285 #display info box to confirm graph created
286 diainfo
= gtk
.MessageDialog(parent
=self
.parent
,
287 flags
=gtk
.DIALOG_DESTROY_WITH_PARENT
,
288 type=gtk
.MESSAGE_INFO
,
289 buttons
=gtk
.BUTTONS_OK
,
290 message_format
=_("Graph created"))
291 diainfo
.format_secondary_text(self
.exportFile
)
295 #end of def exportGraph