sábado, 25 de abril de 2015

wxPython double slider widget to enter a range.

I had this problem to enter a range of times in a wxPython application. After some research I could not found a widget that does what I need. The closest I could get was a Slider with SL_SELRANGE
style. Unfortunatelly this option is only available in Windows.

So I decide to create a small widget with two sliders to select the maximum and minimum time. If the minimum goes over the maximum the maximum is updated and viceversa. The selected values are updated as labels.





This is the code:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import wx

class RangeSlider (wx.Panel):
    MAX_VALUE = 1000

    def __init__ (self, parent, minTime, maxTime):
        super(RangeSlider, self).__init__(parent, wx.ID_ANY)

        self.minTime = minTime
        self.maxTime = maxTime

        sizer = wx.FlexGridSizer (rows=2, cols = 3, vgap = 5, hgap = 5)
        self.sldMax = wx.Slider(self, value=RangeSlider.MAX_VALUE, minValue=0,
                maxValue=self.MAX_VALUE,
                style=wx.SL_HORIZONTAL )
        self.sldMin = wx.Slider (self, value=0, minValue=0,
                maxValue=self.MAX_VALUE,
                style =wx.SL_HORIZONTAL )

        self.sldMax.Bind(wx.EVT_SCROLL, self.OnSliderScroll)
        self.sldMin.Bind (wx.EVT_SCROLL, self.OnSliderScroll2)

        self.txtMax = wx.StaticText(self, label= self.formatTime (self.maxTime))
        self.txtMin = wx.StaticText(self, label=self.formatTime (self.minTime))

        lab1 = wx.StaticText (self, label="Min " + self.formatTime (self.minTime))
        lab2 = wx.StaticText (self, label="Max " + self.formatTime (self.maxTime))

        sizer.Add (lab1, 0, wx.LEFT, 10)
        sizer.Add (self.sldMax, 1, wx.EXPAND)
        sizer.Add (lab2, 0, wx.RIGHT, 10)
        sizer.Add (self.txtMin, 1, wx.ALIGN_CENTER)
        sizer.Add (self.sldMin, 1, wx.EXPAND)
        sizer.Add (self.txtMax, 1, wx.ALIGN_CENTER)
        sizer.AddGrowableCol (1, 1)

        self.SetSizer (sizer)

    def formatTime (self, t):
        return "%02d:%02d:%02d" % (t / 3600, (t%3600)/60, t%60)

    def formatValue (self, v):
        t = v * (self.maxTime - self.minTime) / 1000
        return self.formatTime (t)


    def OnSliderScroll(self, e):

        val = self.sldMax.GetValue()

        valMin = self.sldMin.GetValue ()
        if valMin > val:
            self.sldMin.SetValue (val)
            self.txtMin.SetLabel (self.formatValue(val))

        self.txtMax.SetLabel(self.formatValue(val))

    def OnSliderScroll2 (self, e):
        val = self.sldMin.GetValue()

        valMax = self.sldMax.GetValue ()
        if valMax < val:
            self.sldMax.SetValue (val)
            self.txtMax.SetLabel (self.formatValue(val))

        self.txtMin.SetLabel(self.formatValue(val))


class Example(wx.Frame):

    def __init__(self, parent, minTime, maxTime):
        """ The time is seconds """
        super(Example, self).__init__(parent, wx.ID_ANY)


        self.InitUI(minTime, maxTime)


    def InitUI(self, minTime, maxTime):

        rangeSlider = RangeSlider (self,minTime, maxTime)

        self.SetTitle('RangeSlider')
        self.Centre()
        self.Show(True)

def main():

    ex = wx.App()
    Example(None, 0, 7200)
    ex.MainLoop()

if __name__ == '__main__':
    main()



jueves, 9 de abril de 2015

Timedoctor Visualizer. An application to analyze timedoctor files.

Recently I needed to analyze some linux execution tasks and interrupt traces and I could not find a tool to do what I wanted so I created my own.

The timedoctor files show the begining and end time of each task executed by a CPU. This is a quite usefull tool to analyze errors in embedded systems, like deadlock, priority inversions...

The tool has two main windows the first one shows the existing tasks in one file and allows to sort, select and deselect each of them. More than one file can be analyzed at the same time.

The other windows allows to visualize the time of execution of the selected tasks in the time. The window allows to pan, zoom and save an image with the graph.

The application was implemented in python and it uses wxPython for the user interface and matplotlib for the plots. I've made it run on Linux, Windows and Mac. The tool can be downloaded from here:

http://github.com/rgonzalez72/tdv

lunes, 6 de abril de 2015

Managing id tags in mp3 files with eyed3.

This is a problem I solved some time ago but after updating to the lastest library I discovered the interface has changed. Setting the tags is quite straightforward following the instructions in here: http://eyed3.nicfit.net/. It wasn't so easy for me to figure out how to attach and image to an mp3 file.
This is the solution I found:

import eyed3

audiofile = eyed3.load (fileName)
if audiofile.tag == None:
    audiofile.tag = eyed3.id3.Tag ()
    audiofile.file_info = eyed3.id3.FileInfo (fileName)


audiofile.tag.artist = artist
audiofile.tag.title = unicode (title)
audiofile.tag.genre = unicode (genre)
img_fp = open (file_path, "rb")

# The type of image, the content of the jpg file, mime type, description
audiofile.tag.images.set(eyed3.id3.frames.ImageFrame.FRONT_COVER,
                img_fp.read(), "image/jpeg", u" ")
audiofile.tag.save (filename=fileName, version=eyed3.id3.ID3_V2_3)

domingo, 15 de marzo de 2015

Heads up Omaha. An artificial inteligence example.

This entry describes the implementation of the Bot I entered to the "Heads up Omaha" competition (http://theaigames.com/competitions/heads-up-omaha). This is basically a competion between IA robots playing poker (Omaha). I was a bit surprised to make to the semifinals considering the little efford I put on it so I decided to explain the simple solution I found.

 I put the code in here:
 https://github.com/rgonzalez72/omaha

This is how I did it step by step. I wrote the bot using object oriented python.

Basic classes 

I created a number of classes to deal with the poker card. They are Suit, Height, Card, Hand and Maze. These classes are simple enough and they don't require further explanation.

Hand evaluation

The class Evaluate performs the evaluation of the hands. I copied the evaluation functions from the "getting started" code of the competion. The trick here is representing every hand and the rank as a 32 bit map in a way they can be compared. This is done in the eval5 function.

There is another function called eval9 that calculates the best score considering the four card in the hand and the five on the table  according to the Omaha rules. That is why we need the getCouples and getTrios functions in the Hand class.

Probabilities calculation 

This section describes how the probabilities of my hand is calculated. We'll I don't, I just estimate them after running a number of random games and counting the winning and losing hands. This is done in the calProbabilies function.

Fuzzy logic implementation

We have all the basic poker functionallity implemented so far. What we need now is to define the strategy. I decided to use fuzzy logic for the simple reason that I had never used it before and wanted to become familiar with it. First I was considering using some library but I could not be sure the library would be available in the competition servers so I implemented my basic fuzzy logic module.
The module defines fuzzy variables and operators. The variables can be triangles or trapezoids. The inputSet and outputSet classes are arrays of variables.

Fuzzy logic rules

Finally, with all the elements described, we can't define the rules that make our program "intelligent".

Type of game 

The first set of input rules we define is the number of chips in the pot that can be FEW, AVERAGE, LOTS. Depending on the number of chips we change the way we play that can be SUICIDAL, AGGRESIVE, CAUTIOUS and CONSERVATIVE. The rules are defined in GameTypeCalculator.

This strategy proved to be not too good and was later dropped the Bot is always AGGRESIVE.

ActionCalculator

The action calculator uses two inputSet: the game type and the hand probability. The hand probability can be VERY GOOD, GOOD, REGULAR and BAD. The goodness of the hand based on the probability is different in the phases of the game, that is why we have defined different ranges for pre-flop, flop, turn and river. The output set is the action: FOLD, CALL, RAISE MIN, RAISE MED, RAISE MAX. Please see ActionCalculator class and its children for details.

And that is, the rest of code is used to deal with the Bot interface. We've implemented a reasonable poker player in 1200 lines of code.

sábado, 28 de febrero de 2015

Report the duration using html

Another problem about creating automatic reports in html. In this case, we need to show the duration of cetain events graphically. It is expressed in a percentange of a total. The first idea is to use a progress bar as defined by html5:

def printProgress2 (percent):
    progStr = str(percent) + " "
    progStr += '<progress value="' + \
               str(percent) + '" max="100"></progress>'
    return progStr
And the result is something like:

33 <progress value="33" max="100"></progress>
This is not to bad but I don't totally like the animations that show some navigators. So my next approach is to use a html5 rectangle. This is the function:

def printProgress1 (percent):
    progStr = " "
    v = percent * 150 / 100
    progStr += '<svg width="160" height="25">'
    progStr += '<rect x="5" y="3" width="' + \
               str(v) + '" height="19" style="fill:rgb(148, 148, 210)"/>'
    progStr += '<text x="6" y="20">' + str (percent) + "%</text>"
    progStr += '<,/svg>'
    return progStr
And the result is something like:

<svg width="160" height="25"><rect x="5" y="3" width="4" height="19" 
   style="fill:rgb(148, 148, 210)"/><text x="6" y="20">3%</text></svg>
This is not bad but now the problem is that not all the navigators like html5 and outlook does not like it either. So the idea I came out with is to use the width of the table cells and change their background color to show the duration:

def getDurationHtml (self, percent):
        """ This function returns the contents of the duration cell based in the percentage. """
        durationStr = '<td><table><tr><td width="45">' + str (percent) + '%</td>'
        first = percent
        second = 100 - first
        durationStr += '<td width="' + str (first) + '" bgcolor="#7070C0"></td>'
        if second > 0:
            durationStr += '<td width="' + str (second) + '"></td>'
        durationStr += '</tr></table>'
        return durationStr
And this is the result:

<table><tr><td width="45">33%</td><td width="33" bgcolor="#7070C0"></td>
  <td width="67"> </td></tr></table>

viernes, 9 de enero de 2015

Color gradation for reports (from red to green)

A little piece of code I wrote to represent a color gradation: red means very bad, green very good and everything in between. The trick here is to use HSV system instead of RGB. You keep the S and V to your favourite value and change the H from 0 to 120 degrees. Here is the function:


import colorsys

def get_color (percentage):

    V=1.0
    S=0.6
    H= (float(percentage) * 120.0) / 36000.0 

    R, G, B = colorsys.hsv_to_rgb (H, S, V)

    R = int (R * 255.0)
    G = int (G * 255.0)
    B = int (B * 255.0)

    octets = [R, G, B]

    color = "#{0:02X}{1:02X}{2:02X}".format (*octets)  

    return  color