source: orange/orange/OrangeCanvas/orngHistory.py @ 6538:a5f65d7f0b2c

Revision 6538:a5f65d7f0b2c, 8.6 KB checked in by Mitar <Mitar@…>, 4 years ago (diff)

Made XPM version of the icon 32x32.

Line 
1# Author: Miha Stajdohar (miha.stajdohar@fri.uni-lj.si)
2# This module
3
4import os, sys, time, smtplib
5import orngEnviron
6from orngSignalManager import OutputSignal
7
8logHistory = 1
9logFile = os.path.join(orngEnviron.directoryNames["canvasSettingsDir"], "history_v002.log")
10
11if not os.path.exists(logFile):
12    file = open(logFile, "w")
13    file.close()
14
15lastSchemaID = None
16openSchemas = {}
17
18def getLastSchemaID():
19    schemaID = None
20    fn = None
21    try:
22        fn = open(logFile, 'r')
23        schemaID = 0
24       
25        for line in fn:
26            values = line.split(';')
27            if values[2].upper() == 'NEWSCHEMA':
28                ID = int(values[1])
29                if ID > schemaID:
30                    schemaID = ID
31    except:
32        print "%s: %s" % sys.exc_info()[:2]
33    finally:
34        if fn != None: fn.close()
35       
36    return schemaID
37
38def logAppend(schemaID, command, params=""):
39    if not logHistory:
40        return
41   
42    if schemaID == None:
43        return
44   
45    fn = None
46    try:
47        fn = open(logFile, 'a')
48        if params == "": fn.write(str(time.localtime()) + ";" + str(schemaID) + ";" + command + ";\n")
49        else: fn.write(str(time.localtime()) + ";" + str(schemaID) + ";" + command + ";" + params + ";\n")
50    except:
51        print "%s: %s" % sys.exc_info()[:2]
52    finally:
53        if fn != None: fn.close()
54
55def logNewSchema():   
56    schemaID = getLastSchemaID()
57   
58    if schemaID == None:
59        return None
60     
61    schemaID += 1
62   
63    logAppend(schemaID, "NEWSCHEMA")   
64    return schemaID
65       
66def logCloseSchema(schemaID):
67    logAppend(schemaID, "CLOSESCHEMA")
68   
69def logAddWidget(schemaID, widgetID, widgetName, x, y):
70    logAppend(schemaID, "ADDWIDGET", str(widgetID) + ";" + str(widgetName) + ";" + str(x) + ";" + str(y))
71   
72def logRemoveWidget(schemaID, widgetID, widgetName):
73    logAppend(schemaID, "REMOVEWIDGET",  str(widgetID) + ";" + str(widgetName))
74
75def logChangeWidgetPosition(schemaID, widgetID, widgetName, x, y):
76    logAppend(schemaID, "MOVEWIDGET", str(widgetID) + ";" + str(widgetName) + ";" + str(x) + ";" + str(y))
77   
78def logAddLink(schemaID, outWidget, inWidget, outSignalName):
79    """Logs new link to history log file."""
80    signalType = ''
81    for o in outWidget.instance.outputs:
82        output = OutputSignal(*o)
83        if output.name == outSignalName:
84            signalType = str(output.type.__name__)
85            break
86   
87    logAppend(schemaID, "ADDLINK", str(id(outWidget)) + ";" + str(id(inWidget)) + ";" + str(signalType))
88
89def sendHistory(username, password, to, host='fri-postar1.fri1.uni-lj.si'):
90    """Sends history file to specified email."""
91    from email.MIMEMultipart import MIMEMultipart
92    from email.MIMEBase import MIMEBase
93    from email.MIMEText import MIMEText
94    from email.Utils import formatdate
95    from email import Encoders
96
97    fro = "Orange user"
98   
99    msg = MIMEMultipart()
100    msg['From'] = fro
101    msg['To'] = to
102    msg['Date'] = formatdate(localtime=True)
103    msg['Subject'] = "history.log"
104       
105    msg.attach(MIMEText("history.log from Orange user"))
106   
107    part = MIMEBase('application', "octet-stream")
108    part.set_payload(open(logFile,"r").read())
109    Encoders.encode_base64(part)
110    part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(logFile))
111    msg.attach(part)
112   
113    smtp = smtplib.SMTP(host)
114    smtp.login(username, password)
115    smtp.sendmail(fro, to, msg.as_string())
116    smtp.close()
117
118def cmpBySecondValue(x,y):
119    """Compares two array by the second value."""
120    if x[1] > y[1]:
121        return -1
122    elif x[1] < y[1]:
123        return 1
124    else:
125        return 0
126
127def historyFileToBasket():
128    """Reads history file to a 'basket'.
129       
130    Each element in a basket list contains a list of widgets in one session.
131       
132    """
133    fin = open(logFile, 'r')
134   
135    session_widgets = {}
136    for line in fin:
137        vals = line.split(";")
138        session = int(vals[1])
139        action = vals[2]
140       
141        if len(vals) > 4 and len(vals[4].split(" - ")) == 2:
142            group, widget = vals[4].split(" - ")
143            group = group.strip() 
144            widget = widget.strip() 
145        elif len(vals) > 4:
146            vals[4] = vals[4][2:-2].split("', '")
147            if len(vals[4]) == 2:
148                group, widget = vals[4]   
149                group = group.strip()
150                widget = widget.strip()
151            else:
152                group, widget = None, None
153       
154        if action == "ADDWIDGET":
155            if session in session_widgets:
156                widgets = session_widgets[session]
157                widgets.append(widget)
158            else:
159                session_widgets[session] = [widget]
160
161    fin.close()
162   
163    basket = []
164    for key in session_widgets:
165        if len(session_widgets[key]) > 0:
166            widgets = session_widgets[key]
167            if len(widgets) > 1:
168                basket.append(widgets)
169   
170    return basket
171
172def buildWidgetProbabilityTree(basket):
173    """Builds a widget probability 'tree'.
174   
175    Levels:
176        0 - probability of inserting a widget in empty canvas
177        1 - probability of inserting a widget after one widget
178        2 - probability of inserting a widget after two widgets
179        3 - probability of inserting a widget after three widgets
180        ...
181     
182    """
183    firstWidget = {}
184    for vals in basket:
185        firstWidget[vals[0]] = firstWidget[vals[0]] + 1 if vals[0] in firstWidget else 1
186   
187    tree = {}
188    tree[0] = [(widgets.split(';'),float(n)/len(firstWidget),n,len(firstWidget)) for widgets, n in firstWidget.items()]
189    #tree[0] = firstWidget
190    for i in range(1,10):
191        tree[i] = estimateWidgetProbability(basket, i)
192       
193    return tree
194   
195def estimateWidgetProbability(basket, depth):
196    """Estimates the probability of inserting the widget after several (depth) widgets.""" 
197    widgetProbs = {}
198    for widgets in basket:
199        if len(widgets) > depth:
200            for i in range(len(widgets) - depth):
201                c = ''
202                for j in range(i, i + depth + 1):
203                    c += widgets[j] + ';'
204                c = c[:-1]   
205                widgetProbs[c] = widgetProbs[c] + 1 if c in widgetProbs else 1
206   
207    widgetProbs = widgetProbs.items()
208    c = 0
209    for l in widgetProbs:
210        c += l[1]
211       
212    widgetProbs = [(widgets.split(';'),float(n)/c,n,c) for widgets, n in widgetProbs]
213    widgetProbs.sort(cmpBySecondValue)
214    return widgetProbs
215
216def nextWidgetProbility(state, tree):
217    """Returns a list of candidate widgets and their probability. The list is sorted descending by probability."""
218    #state = [w.replace(' ','') for w in state]
219    predictions = []
220   
221    if state == []:
222        widgetCounts = tree[0]
223        predictions = [(widgetCounts[j][0][-1], float(widgetCounts[j][2]) / 1) for j in range(len(widgetCounts))]
224    else:
225        # calculate probabilities on levels in a tree up to the number of already inserted widgets
226        for i in range(1, len(state)+1):
227            predictions_tmp = []
228            widgetCounts = tree[i]
229            count = 0
230            for widgets, p, c, n in widgetCounts:
231               
232                if len(widgets) > i:
233                    #print widgets[-2], state[-1]
234                    flag = True
235                    for j in range(i):
236                        if widgets[-j-2] != state[-j-1]:
237                            flag = False
238                           
239                    if flag:
240                        predictions_tmp.append((widgets, p, c, n))
241                        count += n
242           
243            # compute the probability of next widget in current tree level
244            predictions_tmp = [(predictions_tmp[j][0][-1], float(predictions_tmp[j][2]) / count) for j in range(len(predictions_tmp))]
245            predictions.extend(predictions_tmp)
246   
247    predictions.sort(cmpBySecondValue)
248    predictions_set = set()
249    # remove double widget entries; leave the one with highest probability
250    todel = []
251    for i in range(len(predictions)):
252        if predictions[i][0] in predictions_set:
253            todel.append(i)
254        else:
255            predictions_set.add(predictions[i][0])
256
257    todel.sort()
258    for i in range(len(todel)):
259        del predictions[todel[len(todel) - i - 1]]
260   
261    return predictions
262
263def predictWidgets(state, nWidgets=3, tree=None):
264    """Returns the most probable widgets depending on the state and tree."""
265    #state = [w.replace(' ','') for w in state]
266    if not tree:
267        basket = historyFileToBasket()
268        tree = buildWidgetProbabilityTree(basket)
269       
270    widgets = nextWidgetProbility(state, tree)
271    return [widgets[i][0] for i in range(min(nWidgets, len(widgets)))]
Note: See TracBrowser for help on using the repository browser.