multisplit
[iramuteq] / tabchi2mcnemar.py
1 # -*- coding: utf-8 -*-
2 #Author: Pierre Ratinaud
3 #Copyright (c) 2008-2020 Pierre Ratinaud
4 #modification pour python 3 : Laurent Mérat, 6x7 - mai 2020
5 #License: GNU/GPL
6
7 #------------------------------------
8 # import des modules python
9 #------------------------------------
10 import os
11 import string
12 import sys
13 import tempfile
14 from time import sleep
15
16 #------------------------------------
17 # import des modules wx
18 #------------------------------------
19 import wx
20 import wx.lib.sized_controls as sc
21
22 #------------------------------------
23 # import des fichiers du projet
24 #------------------------------------
25 import HTML
26 from chemins import ffr,FFF
27 from functions import exec_rcode, check_Rresult
28 from dialog import ChiDialog, PrefChi
29 from analysematrix import AnalyseMatrix
30
31
32 chioption = { 'valobs' : True,
33     'valtheo' : True,
34     'resi' : False,
35     'contrib' : True,
36     'pourcent' : False,
37     'pourcentl' : True,
38     'pourcentc' : True,
39     'graph' : True,
40     'bw' : False,
41 }
42
43
44 def make_res(line) :
45     if float(line[5]) <= 0.05 and line[6] != 'warning':
46         line.append('green')
47     elif float(line[5]) <= 0.05 and line[6] == 'warning':
48         line.append('blue')
49     else :
50         line.append('red')
51     return line
52
53 def clean_line(result) :
54     return [[val for val in line if val != '**'] for line in result]
55
56 def make_table(tabs, tab_title, res) :
57     return ['<br>'.join(['<font color=%s>%s</font>' % (res[i][-1], tab_title), HTML.table(tab)]) for i,tab in enumerate(tabs)]
58
59 def make_restab(res) :
60     return ['<br>'.join(['<font color=%s>%s</font>'% (line[-1], 'Résultats'),HTML.table([['chi', line[3]],['p', line[5]]])]) for i,line in enumerate(res)]
61
62 def make_htmlgraphs(graphs) :
63     return ['<img src=%s>' % os.path.basename(val) for val in graphs]
64
65 def make_link_list(res, text) :
66     return ['<a name=back_%i></a><a href=#%i><font color=%s>%s</font></a>' % (i, i, chi[-1], text[i]) for i, chi in enumerate(res)]
67
68 def make_title(res, text) :
69     return ['<a name=%i></a><br><font color=%s>%s</font><br><a href=#back_%i>retour</a><br>' % (i, val[-1], text[i], i) for i, val in enumerate(res)] 
70
71
72 class McNemar(AnalyseMatrix):
73
74     def doparametres(self, dlg = None):
75         if dlg is None :
76             return
77         dial = ChiDialog(self.parent, -1, "Chi2 McNemar", chioption, self.tableau, size=(400, 350),
78                      style = wx.DEFAULT_DIALOG_STYLE
79                      )
80         dial.CenterOnParent()
81         val = dial.ShowModal()
82         if val==wx.ID_OK :     
83             self.colsel1 = dial.list_box_1.GetSelections()
84             self.colsel2 = dial.list_box_2.GetSelections()
85             if dial.chiopt :
86                 chioption['valobs'] = dial.dial.check1.GetValue()
87                 chioption['valtheo'] = dial.dial.check2.GetValue()
88                 chioption['resi'] = dial.dial.check3.GetValue()
89                 chioption['contrib'] = dial.dial.check4.GetValue()
90                 chioption['pourcent'] = dial.dial.check5.GetValue()
91                 chioption['pourcentl'] = dial.dial.check6.GetValue()
92                 chioption['pourcentc'] = dial.dial.check7.GetValue()
93                 chioption['graph'] = dial.dial.check8.GetValue()
94                 chioption['bw'] = dial.dial.checkbw.GetValue()
95                 dial.dial.Destroy()
96             dial.Destroy()
97             self.parametres.update(chioption)
98             self.chioption = chioption
99         else :
100             if dial.chiopt :
101                 dial.dial.Destroy()
102             dial.Destroy()
103             self.parametres = None
104
105     def doanalyse(self):
106         self.count = 1
107         keepGoing = self.dlg.Update(self.count,"Analyse dans R...")
108         self.OutFrame=tempfile.mktemp(dir=self.parent.TEMPDIR)
109         self.encode=self.parent.encode
110         self.TEMPDIR=self.parent.TEMPDIR
111         self.RPath=self.parent.PathPath.get('PATHS','rpath')
112         self.TextCroise=[]
113         for i in self.colsel1 :
114             for j in self.colsel2 :
115                 self.TextCroise.append(self.tableau.colnames[i] + ' / ' + self.tableau.colnames[j])
116         rchioption = {}
117         for val in self.chioption :
118             if self.chioption[val]:
119                 rchioption[val] = 'TRUE'
120             else :
121                 rchioption[val] = 'FALSE'
122         txt="""
123         source("%s")
124         """%ffr(self.parent.RscriptsPath['Rfunct'])
125         txt += """
126         source("%s")
127         """ % ffr(self.parent.RscriptsPath['Rgraph'])
128         txt += """
129         doobs <- %s
130         doexp <- %s
131         docontrib <- %s
132         doresi <- %s
133         dopr <- %s
134         doprl <- %s
135         doprc <- %s
136         dograph <- %s
137         bw <- %s
138         """ % (rchioption['valobs'], rchioption['valtheo'], rchioption['contrib'], rchioption['resi'], rchioption['pourcent'], rchioption['pourcentl'], rchioption['pourcentc'], rchioption['graph'], rchioption['bw'])
139         txt+="""
140         datadm <- read.csv2("%s", encoding="%s", header = TRUE, row.names = 1, sep='\\t', quote = '"', na.string = '')
141         listres<-list()
142         listcol<-list()
143         cont<-1
144         """%(ffr(self.tableau.parametres['csvfile']), self.tableau.parametres['syscoding'])
145         if len(self.colsel1)==1:
146             strsel1=str(tuple(self.colsel1)).replace(',','')
147         else:
148             strsel1=str(tuple(self.colsel1))
149         if len(self.colsel2)==1:
150             strsel2=str(tuple(self.colsel2)).replace(',','')
151         else:
152             strsel2=str(tuple(self.colsel2))
153         txt+="""
154         for (i in c%s) {""" % strsel1
155         txt+="""
156             for (j in c%s) {""" % strsel2
157         txt+="""
158                 tab<-table(datadm[,i+1],datadm[,j+1])
159                 if (min(dim(tab)) != 1) {
160                     chi <- mcnemar.test(tab)
161                     #chi<-chisq.test(tab)
162                     CS<-colSums(tab)
163                     RS<-rowSums(tab)
164                     GT<-sum(tab)
165                     chi$observed <- tab
166                     chi$expected <- tab
167                     chi$contrib <- tab
168                     chi$residuals <- tab
169                     #chi$contrib<-(tab-chi$expected)/sqrt(chi$expected * ((1 - RS/GT) %%*%% t(1 - CS/GT)))
170                     listres[[cont]]<-chi
171                     listcol[[cont]]<-ncol(tab)
172                     cont<-cont+1
173                 } else {
174                     chi <- list(observed = tab, residuals = tab, contrib = tab, statistic = 0, p.value = 1, expected = tab, message = 'pas de calcul')
175                     listres[[cont]] <- chi
176                     listcol[[cont]]<-ncol(tab)
177                     cont <- cont + 1
178                 }
179             }
180         }
181         maxcol<-max(unlist(listcol))+1
182         if (maxcol<7) {maxcol<-7}
183         frameout<-matrix('*',1,maxcol)
184         count<-0
185         for (chi in listres) {
186             if (min(chi$expected)<5) {
187                 att<-"warning"
188             } else {
189                 att<-""
190             }
191             if ('message' %%in%% attributes(chi)$names) {
192                 att <- "Ce chi2 n\'a pas été calculé"
193                 nom_colresi<-colnames(chi$observed)
194                 chi$prl <- chi$expected
195                 chi$prc <- chi$expected
196                 st <- sum(chi$observed)
197             } else {
198                 nom_colresi<-colnames(chi$observed)
199                 st <- sum(chi$observed)
200                 sc <- colSums(chi$observed)
201                 sr <- rowSums(chi$observed)
202                 chi$prl <- round((chi$observed/sr)*100,2)
203                 chi$prc <- t(round((t(chi$observed)/sc)*100,2))
204             }
205             fileout<-paste('histo_',count,sep='')
206             fileout<-paste(fileout,'.png',sep='')
207             count<-count+1
208             fileout<-file.path("%s",fileout)
209             if (max(nchar(colnames(chi$observed)))>15) {
210                 leg <- 1:length(colnames(chi$observed))
211             } else {
212                 leg <- colnames(chi$observed)
213             }
214             if (dograph) {
215                 width<-ncol(chi$observed)*100
216                 if (width < 350) {width <- 350}
217                 open_file_graph(fileout,width = width, height = 300)
218                 par(mar=c(0,0,0,0))
219                 layout(matrix(c(1,2),1,2, byrow=TRUE),widths=c(3,1))
220                 par(mar=c(2,2,1,0))
221                 par(cex=0.8)
222                 if (!bw) colors <- rainbow(length(rownames(chi$observed)))
223                 else colors <- gray.colors(length(rownames(chi$observed)))
224                 barplot(chi$prl,names.arg = leg, beside=TRUE,border=NA, col=colors)
225                 par(mar=c(0,0,0,0))
226                 par(cex=0.8)
227                 plot(0, axes = FALSE, pch = '')
228                 legend(x = 'center' , rownames(chi$observed), fill = colors)
229                 dev.off()
230             }
231             chi$prl <- cbind(chi$prl, total = rowSums(chi$prl))
232             chi$prc <- rbind(chi$prc, total = colSums(chi$prc))
233             chi$observed<-rbind(chi$observed,total=colSums(chi$observed))
234             chi$observed<-cbind(chi$observed,total=rowSums(chi$observed))
235             chi$pr <- round((chi$observed/st)*100,2)
236             chi$expected<-rbind(chi$expected,total=colSums(chi$expected))
237             chi$expected<-cbind(chi$expected,total=rowSums(chi$expected))
238             chi$expected<-round(chi$expected,digits=2)
239             chi$residuals<-round(chi$residuals,digits=2)
240             chi$contrib<-round(chi$contrib, digits=2)
241             nom_col<-colnames(chi$observed)
242            
243             if (ncol(chi$observed)<maxcol) {
244                 for (i in 1:(maxcol-ncol(chi$observed))) {
245                     chi$observed<-cbind(chi$observed,'**')
246                     chi$pr<-cbind(chi$pr,'**')
247                     chi$prl<-cbind(chi$prl,'**')
248                     chi$prc<-cbind(chi$prc,'**')
249                     chi$expected<-cbind(chi$expected,'**')
250                     chi$residuals<-cbind(chi$residuals,'**')
251                     chi$contrib<-cbind(chi$contrib,'**')
252                     nom_col<-append(nom_col,'**')
253                     nom_colresi<-append(nom_colresi,'**')
254                 }
255                 chi$residuals<-cbind(chi$residuals,'**')
256                 chi$contrib<-cbind(chi$contrib,'**')
257                 nom_colresi<-append(nom_colresi,'**')
258                 chi$prc<-cbind(chi$prc,'**')
259             } else if (ncol(chi$observed)==maxcol) {
260                 chi$residuals<-cbind(chi$residuals,'**')
261                 chi$contrib<-cbind(chi$contrib,'**')
262                 nom_colresi<-append(nom_colresi,'**')
263                 chi$prc<-cbind(chi$prc,'**')
264             }
265             if (doobs) {
266                 li<-matrix('*obs*',1,maxcol)
267                 frameout<-rbind(frameout,li)
268                 frameout<-rbind(frameout,nom_col)
269                 frameout<-rbind(frameout,chi$observed)
270             }
271             if (doexp) {
272                 li<-matrix('*exp*',1,maxcol)
273                 frameout<-rbind(frameout,li)
274                 frameout<-rbind(frameout,nom_col)
275                 frameout<-rbind(frameout,chi$expected)
276             }
277             if (doresi) {
278                 li<-matrix('*resi*',1,maxcol)
279                 frameout<-rbind(frameout,li)
280                 frameout<-rbind(frameout,nom_colresi)
281                 frameout<-rbind(frameout,chi$residuals)
282             }
283             if (docontrib) {
284                 li<-matrix('*contrib*',1,maxcol)
285                 frameout<-rbind(frameout,li)
286                 frameout<-rbind(frameout,nom_colresi)
287                 frameout<-rbind(frameout,chi$contrib)
288             }
289             if (dopr) {
290                 li<-matrix('*pr*', 1, maxcol)
291                 frameout<-rbind(frameout,li)
292                 frameout<-rbind(frameout,nom_col)
293                 frameout<-rbind(frameout,chi$pr)
294             }
295             if (doprl) {
296                 li<-matrix('*prl*', 1, maxcol)
297                 frameout<-rbind(frameout,li)
298                 frameout<-rbind(frameout,nom_col)
299                 frameout<-rbind(frameout,chi$prl)
300             }
301             if (doprc) {
302                 li<-matrix('*prc*', 1, maxcol)
303                 frameout<-rbind(frameout,li)
304                 frameout<-rbind(frameout,nom_colresi)
305                 frameout<-rbind(frameout,chi$prc)
306             }
307             res<-c('****','chi',chi$statistic,'p',chi$p.value,att,fileout)
308             frameout<-rbind(frameout,res)
309         }
310         li<-matrix('fin_analyse',1,maxcol)
311         frameout<-rbind(frameout,li)
312         write.csv2(frameout,file="%s")
313         """ % (ffr(self.parametres['pathout']),ffr(self.OutFrame))
314         tmpfile=tempfile.mktemp(dir=self.TEMPDIR)
315         print(tmpfile)
316         tmpscript=open(tmpfile,'w')
317         tmpscript.write(txt)
318         tmpscript.close()
319         pid = exec_rcode(self.RPath, tmpfile, wait = False)
320         while pid.poll() == None :
321             sleep(0.2)
322         check_Rresult(self.parent, pid)            
323         self.count += 1
324         keepGoing = self.dlg.Update(self.count,"Ecriture des résultats")
325          
326         listfileout = self.dolayout(self.chioption)
327             #listfileout=dlg.ShowChi2(ColSel1,ColSel2)
328             #parent.FreqNum += 1
329             #parent.DictTab[u"Chi2_%s*"%parent.FreqNum]=listfileout
330             #parent.newtab = wx.html.HtmlWindow(parent.nb, -1)
331             #if "gtk2" in wx.PlatformInfo:
332                 #parent.newtab.SetStandardFonts()
333                 #parent.newtab.LoadPage(listfileout[len(listfileout)-1])
334                 #parent.nb.AddPage(parent.newtab,u"Chi2_%s*"%parent.FreqNum)
335                 #parent.nb.SetSelection(parent.nb.GetPageCount()-1)
336                 #parent.ShowTab(wx.EVT_BUTTON)
337                 #parent.DisEnSaveTabAs(True)
338             #self.count += 1
339             #keepGoing = self.dlg.Update(self.count,u"Fini")
340
341     def dolayout(self, option):
342         ListFile=[False]
343         file=open(self.OutFrame,'r')
344         content=file.readlines()
345         file.close()
346         lcont = [line.replace('"','').replace('\n','').split(';') for line in content]
347         lcont.pop(0)
348         lcont.pop(0)
349         allcoord = []
350         names = []
351         res = [chi for chi in lcont if chi[0]=='res']
352         res = [make_res(line) for line in res]
353         coord_res = [i for i,chi in enumerate(lcont) if chi[0]=='res']
354         if option['valobs']:
355             allcoord.append([i for i,chi in enumerate(lcont) if chi[1]=='*obs*'])
356             names.append('Valeurs observées')
357         if option['valtheo'] :
358             allcoord.append([i for i,chi in enumerate(lcont) if chi[1]=='*exp*'])
359             names.append('Valeurs théoriques')
360         if option['resi'] :
361             allcoord.append([i for i,chi in enumerate(lcont) if chi[1]=='*resi*'])
362             names.append('Residuals')
363         if option['contrib'] :
364             allcoord.append([i for i,chi in enumerate(lcont) if chi[1]=='*contrib*'])
365             names.append('Contributions a posteriori')
366         if option['pourcent'] : 
367             allcoord.append([i for i,chi in enumerate(lcont) if chi[1]=='*pr*'])
368             names.append('Pourcentages')
369         if option['pourcentl'] :
370             allcoord.append([i for i,chi in enumerate(lcont) if chi[1]=='*prl*'])
371             names.append('Pourcentages en ligne')
372         if option['pourcentc'] :
373             allcoord.append([i for i,chi in enumerate(lcont) if chi[1]=='*prc*'])
374             names.append('Pourcentages en colonne')
375         allcoord.append(coord_res)
376         allhtml = [[clean_line(lcont[allcoord[i][j]+1:allcoord[i+1][j]]) for j, line in enumerate(allcoord[i])] for i, tab in enumerate(allcoord) if i!=len(allcoord)-1]
377         allhtml = [make_table(val,names[i],res) for i,val in enumerate(allhtml)]
378         links = make_link_list(res, self.TextCroise)
379         html_res = make_restab(res)
380         allhtml.insert(0,html_res)
381         titles = make_title(res, self.TextCroise)
382         allhtml.insert(0,titles)
383         if option['graph'] :
384             graphs = [line[7] for line in res]
385             ListFile += graphs
386             html_graphs = make_htmlgraphs(graphs)
387             allhtml.append(html_graphs)
388         header="""
389         <html>\n
390         <meta http-equiv="content-Type" content="text/html; charset=%s" />\n
391         <body>\n
392         <h1>Test du Chi2</h1>\n
393         <br>
394         <table border=1><tr><td>
395         Légende : <br>
396         <font color=green>p &lt;= 0.05</font><br>
397         <font color=blue>p &lt;= 0.05 mais il y a des valeurs théoriques &lt; 5</font><br>
398         <font color=red>p &gt; 0.05</font>
399         </td></tr></table><br><br>
400         """%self.parent.SysEncoding
401         pretxt = '<br>\n'.join(links)+'<br><hr><br>\n'
402         txt = '<br><hr><br>\n'.join(['<br><br>'.join([tab[i] for tab in allhtml]) for i,val in enumerate(res)])
403         txt = header + pretxt + txt + '\n</body></html>'
404         fileout=os.path.join(self.parametres['pathout'],'resultats-chi2.html')
405         with open(fileout, 'w') as f :
406             f.write(txt)
407         ListFile.append(fileout)         
408         return ListFile