Profile


Name
DistMap1.1
ID
101868
Shared with
Public
Parent
DistMap1
Children
None
Created on
February 15, 2016 at 02:37 AM UTC
Updated on
February 15, 2016 at 02:37 AM UTC
Description

DistMap1.1 outputs two hex characters per point in the eps section to get around PostScript issues.

Best for


Code


-- jeff101 began DistMap0 12/3/15 354pm -- adapted DistMap0c.txt 12/4/15 1220pm noon code to make DistMap1 -- last updated 1/24/16 312am -- -- version 1.1 LociOiling 2016/02/14 -- + double sample depth to two hex digits (8 bits) per sample -- -- global variables recipename='DistMap1' function Main() local dist,dd,dcuts,j,j1,j2,minj1,minj2,maxj1,maxj2,ask,runflag,isok local chlist,nshades,hnshades,chway,revflagi,revflag,chways,spflag,lbls local sss,aas,dists,dds,mindist,maxdist,tmpstr,epsway,epsdim,makecsv,maketot local csvspacing,dtot,dtotcalc,davg,drms,drmsd,dmed,dtopq,dbotq,dlist local justansi,ansimax,nlists,didit,skip5num,pflag,sortway local tot=structure.GetCount() local htot=math.floor(tot/2) -- rounds half the total down to nearest integer local nbands=band.GetCount() print(' ') print(recipename..': Puzzle '..puzzle.GetName()) print(' with Puzzle ID '..puzzle.GetPuzzleID()..' on '..ui.GetPlatform()..' at '..os.date()) print(' has score '..trunc3(current.GetScore())..', '..nbands..' bands, and '..tot..' residues.') print(' ') chlist=makechlist() -- chlist should contain many lists chlist[j] containing 5 or 10 elements each nlists=#chlist -- # of character sets available ansimax=nlists-2 -- lists 1 to ansimax are ANSI-only, -- lists ansimax+1 to nlists contain non-ANSI chars -- -- below are some default values -- first few hold for most charts chway=1 -- which set of characters to use for shading the charts revflagi=false -- false=regular order, true=reverse order for shades justansi=true -- true=just use ansi chars, false=allow non-ansi chars spflag=0 -- 0=no spaces, 1=single space, 2=commas lbls=2 -- 0=all labels off, 1=left labels off, top/bottom labels on, 2=all labels on maketot=false -- false=no full-size chart, true=makes full-size chart -- next few are for csv charts makecsv=3 -- 0=none, 1=1 csv chart, 2=2 csv charts, 3=3 csv charts csvspacing=2 -- 1=single space, 2=commas -- next few are for eps plot epsway=4 -- 0=no eps plot, 1=5-shade eps plot, 2-4=10-shade eps plot (4>3>2 for short-distance contrast) epsdim=tot -- size of eps plot to make -- next few are general ones skip5num=0 -- 0=does all 5-number-summaries, 1=skips them for groups >= 500 elements, 2=skips for all groups sortway=2 -- 1=non-table.sort() way, 2=table.sort() way -- showchlist(chlist,nlists,ansimax,1) -- show ANSI-only sets in chlist didit=0 -- -- below shows input menus until the inputs make sense isok=0 -- will be 1 when the inputs make sense while isok==0 do ask=dialog.CreateDialog(recipename) ask.LabelA=dialog.AddLabel('------------- VALUES FOR MOST CHARTS --------------') if justansi then ask.chway=dialog.AddSlider("chway: ",chway,1,ansimax,0) else ask.chway=dialog.AddSlider("chway: ",chway,1,nlists,0) end tmpstr='chway picks characters for distance ranges in charts.\nRecipe Output and scriptlog.default.xml give details.' ask.LabelB=dialog.AddLabel(tmpstr) ask.revflagi=dialog.AddCheckbox('Reverse the order of characters in most charts.',revflagi) ask.justansi=dialog.AddCheckbox('Use only ANSI chars (makes smaller output files).',justansi) ask.spflag=dialog.AddSlider('chart spacing: ',spflag,0,2,0) ask.LabelC=dialog.AddLabel('spacing: 0=no spaces, 1=single space, 2=comma.') ask.lbls=dialog.AddSlider('chart labels: ',lbls,0,2,0) ask.LabelD=dialog.AddLabel('labels: 0=all off, 1=left off, top/bot on, 2=all on.') ask.maketot=dialog.AddCheckbox('Include a full-size chart.',maketot) ask.LabelE=dialog.AddLabel('--------- VALUES FOR EXCEL/CSV CHARTS ---------') ask.makecsv=dialog.AddSlider('makecsv: ',makecsv,0,3,0) ask.LabelF=dialog.AddLabel('makecsv: # of Excel/csv charts to make.\n Each successive chart is larger.') ask.csvspacing=dialog.AddSlider('csv spacing: ',csvspacing,1,2,0) ask.LabelG=dialog.AddLabel('spacing: 1=single space, 2=comma.') ask.LabelH=dialog.AddLabel('----------------- VALUES FOR EPS PLOT -----------------') ask.epsway=dialog.AddSlider('epsway: ',epsway,0,4,0) ask.LabelI=dialog.AddLabel('epsway: 0=no plot, 1=5 shades, 2-4=10 shades.\n epsway 4>3>2 for short-distance contrast.') ask.epsdim=dialog.AddSlider('epsdim: ',epsdim,2,tot,0) ask.LabelJ=dialog.AddLabel('epsdim: # of AA\'s to show in an eps plot.') ask.LabelK=dialog.AddLabel('------------------ GENERAL CONTROLS -------------------') -- ask.skip5num=dialog.AddSlider('skip5num: ',skip5num,0,2,0) -- ask.LabelL=dialog.AddLabel('skip5num: skip 5-#-summaries (median, top & bot 1/4)\n 0=never, 1=for sets>=500 elements, 2=always.') ask.sortway=dialog.AddSlider('sortway: ',sortway,1,2,0) ask.LabelM=dialog.AddLabel('sortway: 1=slow way, 2=table.sort() way.') ask.run=dialog.AddButton('Run',1) ask.quit=dialog.AddButton('Quit',0) runflag=dialog.Show(ask) if runflag==0 then -- quit isok=1 print('Quitting now.') else isok=1 -- values for most charts chway=ask.chway.value+0 revflagi=ask.revflagi.value if revflagi then revflag=1 else revflag=0 end -- if revflagi if justansi~=ask.justansi.value then -- the ANSI setting has changed if justansi then -- new setting allows non-ANSI chars if didit==0 then showchlist(chlist,nlists,ansimax,2) -- show the non-ANSI character sets in chlist didit=1 chway=nlists -- reset the default value to a non-ANSI list end -- if didit isok=0 -- make sure to repeat the input menu end -- if justansi end -- if justansi justansi=ask.justansi.value if justansi then if chway>ansimax then print('ERROR: chway='..chway..' contains non-ANSI characters.') print(' Please pick another character set or allow non-ANSI characters.') print(' ') chway=1 -- reset the default value to an ANSI character set isok=0 end -- if chway end -- if justansi spflag=ask.spflag.value+0 lbls=ask.lbls.value+0 maketot=ask.maketot.value -- csv values makecsv=ask.makecsv.value+0 csvspacing=ask.csvspacing.value+0 -- eps values epsway=ask.epsway.value+0 epsdim=ask.epsdim.value+0 -- general values -- skip5num=ask.skip5num.value+0 sortway=ask.sortway.value+0 end -- if runflag end -- if isok -- if runflag==1 then tmpstr='' nshades=#chlist[chway] for j=1,nshades do tmpstr=(tmpstr..chlist[chway][j]) end -- for j -- -- list the input values print('Got the following inputs by '..os.date()..' for '..tot..' residues:') print(' chway='..chway..'=\''..tmpstr..'\'='..nshades..' shades, reverse order='..tostring(revflagi)..'='..revflag..',') print(' use only ANSI characters='..tostring(justansi)..', spacing='..spflag..',') print(' labels='..lbls..', make full-size chart='..tostring(maketot)..',') print(' makecsv='..makecsv..', csvspacing='..csvspacing..', epsway='..epsway..', epsdim='..epsdim..',') print(' skip5num='..skip5num..', and sortway='..sortway..'.') print(' ') -- -- next part calculates Ca-Ca distance map in dists and dds -- print('Gathering data and doing calculations...') sss={} aas={} dists={} dds={} mindist= -1 -- will be min nonzero Ca-Ca distance found maxdist= -1 -- will be max nonzero Ca-Ca distance found dcuts={2,4,6,8,10,15,20,30,50} -- borders of distance ranges -- want an odd # of elements in dcuts, preferably 9 for j1=1,tot do dists[j1]={} dds[j1]={} sss[j1]=structure.GetSecondaryStructure(j1) aas[j1]=structure.GetAminoAcid(j1) end -- for j1 print('Got list of '..tot..' AA\'s and their secondary structures.') dtot=0 -- will be total # of distances between 2 different Ca's dlist={} for j1=1,tot do -- print('Getting distances from alpha-carbon '..j1..' of '..tot..' ('..os.date()..').') for j2=j1,tot do -- j2>=j1 holds here if j1==j2 then dist=0+0 dd=getdd(dcuts,dist) dists[j1][j2]=dist dds[j1][j2]=dd else -- j1~=j2, which means j2>j1 dtot=dtot+1 dist=getdist(j1,j2,0,0) dlist[dtot]=dist -- dist should now be distance between alpha-carbons j1 and j2 if dist>0 then if maxdist== -1 or dist>maxdist then maxdist=dist maxj1=j1 maxj2=j2 end -- if maxdist if mindist== -1 or dist<mindist then mindist=dist minj1=j1 minj2=j2 end -- if mindist end -- if dist dd=getdd(dcuts,dist) dists[j1][j2]=dist dists[j2][j1]=dist dds[j1][j2]=dd dds[j2][j1]=dd end -- if j1==j2 end -- for j2 end -- for j1 print('Got '..dtot..' distances among '..tot..' alpha-carbons ('..os.date()..').') -- -- below calcs some stats for all the above distances dtotcalc=tot*(tot-1)/2 -- how many pairs of Ca's above give distances to average if dtot~=dtotcalc then print('ERROR: dtot='..dtot..' is not '..dtotcalc..' like it should be.') end -- if dtot -- print(' ') test5num(skip5num,sortway) -- test get5num -- -- below gets 5-number summary as in https://en.wikipedia.org/wiki/Five-number_summary dtopq,dmed,dbotq,davg,drms,drmsd=get5num(dlist,dtot,maxdist,mindist,skip5num,sortway) davgp=davg+drmsd -- avg + rms dev davgm=davg-drmsd -- avg - rms dev -- -- next part makes a few charts -- -- below makes a few charts based on dists for use in Excel if makecsv>0 then csvcharts(sss,aas,dists,tot,htot,csvspacing,makecsv,skip5num,sortway) end -- if makecsv -- -- below makes an eps file if epsway>0 then epsmaker(chlist,epsway,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,davg,drmsd,tot,epsdim) end -- if epsway -- -- next part prints the distance map in dds -- nshades=(#dcuts)+1 -- should be 10 hnshades=nshades/2 -- should be 5 print('Some of the alpha-carbon distance map(s) below use '..nshades..' shades:') print(string.format(' 0 means distance is in range (-Inf,%2d).',dcuts[1])) for j=1,nshades-2 do print(string.format(' %d means distance is in range [%2d,%2d).',j,dcuts[j],dcuts[j+1])) end -- for j print(string.format(' %d means distance is in range [%2d,Inf).',nshades-1,dcuts[nshades-1])) print('Some of the alpha-carbon distance map(s) below use '..hnshades..' shades:') print(string.format(' 0 means distance is in range (-Inf,%2d).',dcuts[2])) for j=1,hnshades-2 do print(string.format(' %d means distance is in range [%2d,%2d).',j,dcuts[2*j],dcuts[2*(j+1)])) end -- for j print(string.format(' %d means distance is in range [%2d,Inf).',hnshades-1,dcuts[2*(hnshades-1)])) print(string.format('All nonzero distances range from %.2f to %.2f',mindist,maxdist)) print(string.format(' for the Ca-Ca pairs %d-%d and %d-%d respectively.',minj1,minj2,maxj1,maxj2)) print(string.format('For these distances, rms value=%.2f, average=%.2f, rms deviation=%.2f,',drms,davg,drmsd)) print(string.format(' so max=%6.2f, avg+rmsdev=%6.2f, avg=%6.2f, avg-rmsdev=%6.2f, min=%6.2f,',maxdist,davgp,davg,davgm,mindist)) print(string.format(' and max=%6.2f, upper 1/4=%6.2f, med=%6.2f, lower 1/4=%6.2f, min=%6.2f.',maxdist,dtopq,dmed,dbotq,mindist)) -- the last line comes from https://en.wikipedia.org/wiki/Five-number_summary print(' ') if maketot then makechart(chlist,chway,revflag,spflag,lbls,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,tot,0) print(' ') end -- if maketot if tot>74 then makechart(chlist,chway,revflag,spflag,lbls,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,74,0) print(' ') end -- if tot if tot>34 then makechart(chlist,chway,revflag,spflag,lbls,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,34,0) print(' ') end -- if tot if tot>18 then makechart(chlist,chway,revflag,spflag,lbls,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,18,0) print(' ') end -- if tot if tot>9 then makechart(chlist,chway,revflag,spflag,lbls,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,9,0) print(' ') end -- if tot if tot>=9 then -- below makes special-format charts for Recipe Output window -- Recipe Output window's slider is hard to line up on these charts. -- It automatically lines up with final chart if there is no blank line at the end. -- Usually I put blank lines after each item I print, but here I put them before. -- pflag is used below to make no blank line after final chart. pflag=0 -- 0 means no printing yet, 1 means something has printed already. -- -- below lists the all-ANSI character sets -- chways={2,3,4,5,6,7,8,11,12,13,14,15,16,17,18,19,20,21,22,1,9,10} chways={1} -- use 1 to give output like in DistMap0 -- chways={1,9,10,24} have fixed-width characters and should look best in Recipe Output window for chway=1,#chways do if pflag==1 then print(' ') end -- if pflag makechart(chlist,chways[chway],0,spflag,lbls,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,9,1) pflag=1 end -- for chway if not justansi then -- non-ANSI char sets are allowed -- below lists all the non-ANSI character sets -- chways={23,24} -- 23 looks odd in Recipe Output window chways={24} -- 24 looks fine in Recipe Output window, so use it here for chway=1,#chways do for revflag=0,1 do -- do it normal order (for white bckgrnd windows), then in reverse order (for black bckgrnd windows) if pflag==1 then print(' ') end -- if pflag makechart(chlist,chways[chway],revflag,spflag,lbls,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,9,1) pflag=1 end -- for revflag end -- for chway end -- if justansi end -- if tot end -- if runflag end -- Main() function makechlist() local chlist={} -- in below, most characters have same width in Courier font, diff widths in Arial. -- all integers have same width on Recipe Output window (Arial not Courier). -- all of the utf8(9608 9619 9618 9617) have same width on Recipe Output window, -- but utf8(9615) (white box) has a slightly different width. chlist[1]={'0','1','2','3','4','5','6','7','8','9'} -- decimal chlist[2]={'0','2','3','5','7','8','A','C','D','F'} -- hexadecimal for eps format chlist[3]={'0','2','4','6','8','A','C','D','E','F'} -- hexadecimal for eps format chlist[4]={'0','3','6','8','A','B','C','D','E','F'} -- hexadecimal for eps format -- chlist[2] is evenly-spaced number-wise, but the low #'d shades are hard to tell apart -- chlist[3-4] space the low #'d shades out more to raise contrast at short distances (4>3>2) -- -- http://www.cs.umd.edu/Outreach/hsContest98/questions/node4.html gives chlist[5]={'$','E','F','L','l','v','!',';',',','.'} -- https://dboikliev.wordpress.com/2013/04/20/image-to-ascii-conversion/ gives chlist[6]={'@','%','#','x','+','=',':','-','.',' '} -- http://paulbourke.net/dataformats/asciiart/ gives chlist[7]={'@','%','#','*','+','=','-',':','.',' '} -- http://members.optusnet.com.au/astroblue/grey_scale.txt gives 12-char list chlist[8]={'#','@','8','O','o','\"',';',',','.',' '} -- I omit 2 of them -- chlist[9]={'0','1','2','3','4'} -- decimal chlist[10]={'0','2','4','6','8'} -- decimal chlist[11]={'0','4','8','B','F'} -- hexadecimal for eps format -- next lines do order darkest to lightest chlist[12]={'@','O','o','.',' '} chlist[13]={'@','0','o','.',' '} chlist[14]={'#','t','+','-',' '} chlist[15]={'#','t','=','-',' '} chlist[16]={'#','\"','~','-',' '} -- \" and utf8(34) are " character chlist[17]={'#','\"','\'','`',' '} -- \' and utf8(39) are ' character chlist[18]={'#','X','/',',',' '} -- utf8(96) is ` character chlist[19]={'%','8','b','o',' '} -- \\ and utf8(92) are \ character chlist[20]={'%','B','b','o',' '} -- utf8(47) is / character chlist[21]={'%','8','b','c',' '} chlist[22]={'%','B','b','c',' '} chlist[23]={utf8(9608),utf8(9619),utf8(9618),utf8(9617),'_'} chlist[24]={utf8(9608),utf8(9619),utf8(9618),utf8(9617),utf8(9472)} -- -- in chlist[23], utf8(9615)=(white block) has odd width vs the rest -- in both Arial and Courier fonts! -- '_' at least has same width as #'s in both fonts -- -- utf8(9472) and utf8(9552) are same width as shaded blocks in Arial & Courier fonts -- utf8(9472) looks like -, utf8(9552) looks like =, and both are fairly white -- they work better than the '_' character -- -- http://www.w3schools.com/charsets/ref_utf_block.asp -- http://www.sorenwinslow.com/AltCodesRun.asp and -- https://en.wikipedia.org/wiki/Box-drawing_character give above codes -- http://www.asciitable.com/ says utf8(176)-utf8(178) are shaded blocks too -- -- typing raw shaded block characters above requires saving this file as unicode not ANSI. -- saving the file as unicode takes about twice the space as ANSI (UTF-8 files = same size as ANSI ones). -- will unicode recipe files put into the cookbook make all.macro much larger? -- will they act strangely in the cookbook? -- unicode outputs in scriptlog.default.xml files will also take twice the usual space. -- return chlist end -- makechlist() -- chflag==1 prints ANSI-only char sets, chflag==2 prints sets w/non-ANSI chars function showchlist(chlist,nlists,ansimax,chflag) local j,k,str,chs,nchs if chflag==1 then print('Use chway to pick which character set (see chlist[chway] below) to use.') print('Each character will represent a different distance range in the charts.') print('Some character sets have 10 distance ranges while others have only 5.') print('Some sets contain non-ANSI characters, which use more bytes than ANSI ones,') print(' making scriptlog.default.xml larger for the same total # of characters.') print(' ') print('The following character sets use only ANSI characters:') else -- if chflag==2 then print('The following character sets include non-ANSI characters:') end -- if chflag -- all chlist[j]'s with j<=ansimax use ANSI characters only for j=1,nlists do if (j<=ansimax and chflag==1) or (j>ansimax and chflag==2) then str='' chs=chlist[j] nchs=#chs for k=1,nchs do str=(str..chs[k]) end -- for k print(string.format(' chlist[%2d][0-%d]=%2d shades=\'%s\'.',j,nchs-1,nchs,str)) -- \' prints a ' character end -- if j end -- for j print(' ') end -- showchlist() -- code below came from -- http://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua function utf8(decimal) if decimal<128 then return string.char(decimal) end local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} } local charbytes = {} local bytes,vals,b for bytes,vals in ipairs(bytemarkers) do if decimal<=vals[1] then for b=bytes+1,2,-1 do local mod = decimal%64 decimal = (decimal-mod)/64 charbytes[b] = string.char(128+mod) end -- for b charbytes[1] = string.char(vals[2]+decimal) break end -- if decimal end -- for bytes return table.concat(charbytes) end -- utf8() -- below finds the distance between residue r1 atom a1 and residue r2 atom a2 function getdist(r1,r2,a1,a2) local tot,nuband local dist= -1+0 -- default value if a1==a2 and a1==0 then dist=structure.GetDistance(r1,r2) -- above finds distance between atom 0's, the alpha-carbons on each residue else -- below finds distance between general atoms on each residue tot=band.GetCount() nuband=band.AddBetweenSegments(r1,r2,a1,a2) if nuband>tot then dist=band.GetLength(nuband) band.Delete(nuband) else -- 4/9/14 below happened for a1==a2 and a1==0 when r1 and r2 differed by 1 -- 5/26/14 below happened for a1==1 and a2==4 when r1 and r2 differed by 1 or less print(string.format("ERROR: getdist(%d,%d,%d,%d) failed so returning -1.",r1,r2,a1,a2)) end -- if nuband end -- if a1==a2 return dist end -- getdist() -- below returns an integer val from 0 to #dcuts -- representing what range the distance dist lies in -- val should be 0 if dist<dcuts[1] or (-Inf,dcuts[1]) -- val should be j if dcuts[j]<=dist<dcuts[j+1] or [dcuts[j],dcuts[j+1]) -- val should be #dcuts if dcuts[#dcuts]<=dist or [dcuts[#dcuts],Inf) -- ideally #dcuts is 9 or less function getdd(dcuts,dist) local val=0+0 local j for j=1,#dcuts do if dist>=dcuts[j] then val=j end -- if dist end -- for j return val end -- getdd() -- below makes charts suitable for use in Excel function csvcharts(sss,aas,dists,tot,htot,spflag,makecsv,skip5num,sortway) local spc,j,k,m,js,jnk,gotit,tmpstr local dist,davg,dmax,dmin,drms,drmsd,dstats,dlist,dtot,dtopq,dmed,dbotq local maxj,maxk -- if makecsv>0 then -- make at least one chart for Excel -- -- usually spflag=0 no space, 1=single space, 2=commas -- but here do 0,1=single space, 2=commas -- if spflag==2 then spc=',' else spc=' ' end -- if spflag -- -- below prepares and prints 1st chart, finding largest distance -- remaining each time, then removes the 2 segments giving it, -- like peeling an onion gotit={} for j=1,tot do gotit[j]=0 -- 0 means not used yet, 1=used already end -- for j print('The next chart is a \'peel-the-onion\' chart. It is made as follows:') print(' (1) Begin with a list of all alpha-carbons in the protein.') print(' (2) Find which pair of alpha-carbons in the list is furthest apart') print(' (find the outermost \'layer\' of the \'onion\').') print(' (3) Report this pair and its members\' distance apart.') print(' (4) Remove this pair from the list of alpha-carbons') print(' (peel off the outermost \'layer\' of the \'onion\').') print(' (5) Repeat steps (2)-(4) until no more alpha-carbon pairs') print(' remain in the list.') print(' (6) If there is one alpha-carbon left in the list,') print(' report it as a pair with zero distance.') print('In this chart, surface residues should have larger distances than core ones.') print(' ') print('********** the \'peel-the-onion\' chart below can be used in Excel ('..os.date()..') **********') print(string.format('SS%sAA#%sAA%sSS%sAA#%sAA%s dist',spc,spc,spc,spc,spc,spc)) for m=1,htot do dmax= -1 maxj=0 maxk=0 for j=1,tot-1 do if gotit[j]==0 then for k=j+1,tot do -- here k>j always holds if gotit[k]==0 then if dists[j][k]>dmax then dmax=dists[j][k] maxj=j maxk=k end -- if dists end -- if gotit end -- for k end -- if gotit end -- for j j=maxj k=maxk gotit[j]=1 gotit[k]=1 print(string.format(' %s%s%3d%s %s%s %s%s%3d%s %s%s%6.2f',sss[j],spc,j,spc,aas[j],spc,sss[k],spc,k,spc,aas[k],spc,dists[j][k])) end -- for m if 2*htot<tot then -- tot is odd, so only 1 segment should remain w/gotit[j]==0 for j=1,tot do if gotit[j]==0 then k=j gotit[j]=1 print(string.format(' %s%s%3d%s %s%s %s%s%3d%s %s%s%6.2f',sss[j],spc,j,spc,aas[j],spc,sss[k],spc,k,spc,aas[k],spc,dists[j][k])) end -- if gotit end -- for j end -- if 2*htot<tot print('********** the \'peel-the-onion\' chart above can be used in Excel ('..os.date()..') **********') print(' ') -- -- below prepares 2nd chart if makecsv>1 then print('Gathering info for the \'AA-stats\' chart below ...') dstats={} -- will hold dmax davg+drmsd davg davg-drmsd dmin drmsd drms dmax dtopq dmed dbotq dmin for each AA for j=1,tot do if j<tot then dist=dists[j][j+1] else dist=dists[j][j-1] end -- if j dmin=dist dmax=dist dlist={} dtot=0 for k=1,tot do if k~=j then dtot=dtot+1 dist=dists[j][k] dlist[dtot]=dist if dist>dmax then dmax=dist elseif dist<dmin then dmin=dist end -- if dist end -- if k end -- for k if dtot~=tot-1 then print('ERROR: for j='..j..', dtot='..dtot..'~='..(tot-1)..'=tot-1.') end -- if dtot -- -- below gets 5-number summary as in https://en.wikipedia.org/wiki/Five-number_summary dtopq,dmed,dbotq,davg,drms,drmsd=get5num(dlist,dtot,dmax,dmin,skip5num,sortway) -- -- gather all the statistics together into dstats dstats[j]={dmax,davg+drmsd,davg,davg-drmsd,dmin,drmsd,drms,dmax,dtopq,dmed,dbotq,dmin} end -- for j -- print(' ') jnk,js=sortmat(dstats,sortway) -- now jnk should hold dstats' elements in descending order -- and js is the sorted order of indices -- -- below prints 2nd chart with dmax listed in descending order print('The \'AA-stats\' chart below has one row for each alpha-carbon in the protein.') print(' Each row lists statistics about the distribution of distances') print(' from the row\'s alpha-carbon to all other alpha-carbons in the protein:') print(' dmax=maximum distance, davg=average distance, dmin=minimum distance,') print(' d=rmsd=rms deviation of all distances from the average distance,') print(' drms=rms (root-mean-squared) distance (it is used to find d=rmsd),') print(' dtopq=upper quartile, dmed=median, dbotq=lower quartile distance.') print(' ') print('********** the \'AA-stats\' chart below can be used in Excel ('..os.date()..') **********') tmpstr=string.format('SS%sAA#%sAA%s dmax%sdavg+d%s davg%sdavg-d%s dmin%sd=rmsd%s drms',spc,spc,spc,spc,spc,spc,spc,spc,spc) print(string.format('%s%s dmax%s dtopq%s dmed%s dbotq%s dmin',tmpstr,spc,spc,spc,spc,spc)) for k=1,tot do j=js[k] tmpstr=string.format(' %s%s%3d%s %s',sss[j],spc,j,spc,aas[j]) for m=1,12 do tmpstr=string.format('%s%s%6.2f',tmpstr,spc,dstats[j][m]) end -- for m print(tmpstr) end -- for k print('********** the \'AA-stats\' chart above can be used in Excel ('..os.date()..') **********') print(' ') -- -- below prints 3rd chart if makecsv>2 then print('The next chart has one row and one column for each alpha-carbon in the protein.') print('Each element in the chart is the distance from the alpha-carbon for the element\'s row') print('to the alpha-carbon for the element\'s column.') print(' ') print('********** the \'all-by-all-distances\' chart below can be used in Excel ('..os.date()..') **********') tmpstr=string.format('SS%sAA#%sAA',spc,spc) for j=1,tot do tmpstr=string.format('%s%s%6s',tmpstr,spc,string.format('%s%d%s',sss[j],j,aas[j])) end -- for j print(tmpstr) for j=1,tot do tmpstr=string.format(' %s%s%3d%s %s',sss[j],spc,j,spc,aas[j]) for k=1,tot do tmpstr=string.format('%s%s%6.2f',tmpstr,spc,dists[j][k]) end -- for k print(tmpstr) end -- for j print('********** the \'all-by-all-distances\' chart above can be used in Excel ('..os.date()..') **********') print(' ') end -- if makecsv>2 end -- if makecsv>1 end -- if makecsv>0 end -- csvcharts() -- below tests get5num() using examples from: -- https://en.wikipedia.org/wiki/Quartile (use method 3 results for 1 & 2 below) -- https://en.wikipedia.org/wiki/Five-number_summary (3) -- http://www.vias.org/tmdatanaleng/cc_quartile.html (4, but I changed dtopq,dbotq to give method 3 results) -- http://mathforum.org/library/drmath/view/60969.html (5-9, M&M=method 1, Tukey=method 2) function test5num(skip5num,sortway) local dlist,dtot,dmax,dmin,dtopq,dmed,dbotq,davg,drms,drmsd local j,k,res,tmpstr,resstrs,diff -- data lists for each example local dlists={ {6,7,15,36,39,40,41,42,43,47,49}, {7,15,36,39,40,41}, {0,0,1,2,63,61,27,13}, {2,4,7,-20,22,-1,0,-1,7,15,8,4,-4,11,11,12,3,12,18,1}, {1,4,9,16,25,36,49,64,81}, {1,2,3,4,5,6,7,8}, {1,2,3,4,5,6,7,8,9}, {1,2,3,4,5,6,7,8,9,10}, {1,2,3,4,5,6,7,8,9,10,11}} -- desired values for dmax,dtopq,dmed,dbotq,dmin,drms for each example -- plus values for dmax,davg+d,davg,davg-d,dmin,d=drmsd for each example local ress={ {49, 42.75, 40, 20.25, 6, 36.4704, 49, 48.3165, 33.1818, 18.0472, 6, 15.1347}, {41, 40, 37.5, 15, 7, 32.5883, 41, 43.1533, 29.6667, 16.1800, 7, 13.4866}, {63, 44, 7.5, 0.5, 0, 32.7738, 63, 46.1408, 20.8750, -4.3908, 0, 25.2658}, {22, 11.5, 5.5, 0.5, -20, 10.4618, 22, 14.4183, 5.550, -3.3183, -20, 8.8683}, {81, 52.75, 25, 7.75, 1, 41.2755, 81, 58.1410, 31.6667, 5.1924, 1, 26.4743}, { 8, 6.5, 4.5, 2.5, 1, 5.0498, 8, 6.7913, 4.5, 2.2087, 1, 2.2913}, { 9, 7.25, 5, 2.75, 1, 5.6273, 9, 7.5820, 5, 2.4180, 1, 2.5820}, {10, 8, 5.5, 3, 1, 6.2048, 10, 8.3723, 5.5, 2.6277, 1, 2.8723}, {11, 8.75, 6, 3.25, 1, 6.7823, 11, 9.1623, 6, 2.8377, 1, 3.1623}} print('Testing 5-number summary code ('..os.date()..'):') for j=1,#dlists do dlist=dlists[j] dtot=#dlist dmin=dlist[1] dmax=dlist[1] for k=2,#dlist do if dlist[k]>dmax then dmax=dlist[k] elseif dlist[k]<dmin then dmin=dlist[k] end -- if dlist end -- for k dtopq,dmed,dbotq,davg,drms,drmsd=get5num(dlist,dtot,dmax,dmin,skip5num,sortway) res={dmax,dtopq,dmed,dbotq,dmin,drms, dmax,davg+drmsd,davg,davg-drmsd,dmin,drmsd} resstrs={'dmax',' dtopq','dmed',' dbotq','dmin',' drms', 'dmax','davg+d','davg','davg-d','dmin','d=drmsd'} for k=1,12 do if k==1 or k==7 then tmpstr='' end -- if k tmpstr=string.format('%s %s=%6.2f',tmpstr,resstrs[k],res[k]) if k==6 or k==12 then print(string.format('Example %d gave%s.',j,tmpstr)) end -- if k end -- for k for k=1,12 do diff=res[k]-ress[j][k] if math.abs(diff)>=0.01 then print(string.format(' ERROR: %s=%.2f above should be %.2f (a difference of %e).', resstrs[k],res[k],ress[j][k],diff)) end -- if math.abs(diff) end -- for k end -- for j print('Done testing at '..os.date()..'.') print(' ') end -- test5num() -- below gets 5-number summary as in https://en.wikipedia.org/wiki/Five-number_summary -- https://en.wikipedia.org/wiki/Median#Easy_explanation_of_the_sample_median -- https://en.wikipedia.org/wiki/Quartile here Method 3 is used function get5num(dlist,dtot,dmax,dmin,skip5num,sortway) local sdlist,hi1,hi2,lo1,lo2,dtopq1,dtopq2,dmed1,dmed2,dbotq1,dbotq2,jnk1,jnk2 local j,dist,davg,drms,drmsd -- if dtot~=#dlist then print('ERROR: dtot='..dtot..'~='..(#dlist)..'=#dlist.') end -- if dtot -- davg=0 drms=0 for j=1,dtot do dist=dlist[j] davg=davg+dist drms=drms+dist^2 end -- for j -- -- in the comments below, x is the list of distances in dlist -- <x> is the average of these distances, or davg -- N is the # of distances, or dtot -- <x^2> is the average of the squares of the distances -- the sums below are over all N values of x -- davg=davg/dtot -- now davg = average of dlist's elements -- average distance: davg=<x>=(sum of x)/N -- drms=math.sqrt(drms/dtot) -- now drms = root-mean-squared of dlist's elements -- rms distance: drms=sqrt[<x^2>]=sqrt[(sum of x^2)/N] -- drmsd=math.sqrt(drms^2-davg^2) -- now drmsd = rms deviation of dlist's elements from davg -- drmsd is like standard deviation but with dtot not dtot-1 in denominator of sqrt -- -- rms deviation of distances: -- drmsd=sqrt[(sum of (x-<x>)^2)/N]=root-mean-squared deviation between x and its average, <x> -- =sqrt[(sum of (x^2-2x<x>+<x>^2))/N] -- =sqrt[(sum of x^2)/N - 2<x>(sum of x)/N + <x>^2(sum of 1)/N] -- =sqrt[<x^2> - 2<x><x> + <x>^2 N/N] -- =sqrt[<x^2> - 2<x>^2 + <x>^2] -- =sqrt[<x^2>-<x>^2]=sqrt(drms^2-davg^2) -- standard deviation would use (N-1) in place of N in sqrt[(sum of (x-<x>)^2)/N] -- if skip5num==2 or (skipit==1 and dtot>=500) then print('skip5num='..skip5num..' and dtot='..dtot..', so skipping get5num.') return -1,-1,-1,davg,drms,drmsd -- return crazy values for the quartiles and median of positive #'s else -- next line is very rate-limiting if dtot is large like 11476 (puzzle 973 1/17/16) sdlist,jnk1=sortit(dlist,sortway) -- sdlist is dlist in descending order if sdlist[1]~=dmax then print('ERROR: dmax='..dmax..'~='..sdlist[1]..'=sdlist[1].') end -- if sdlist if sdlist[dtot]~=dmin then print('ERROR: dmin='..dmin..'~='..sdlist[dtot]..'=sdlist['..dtot..'].') end -- if sdlist hi1,dmed1,lo1=getmedian(sdlist,1) hi2,dmed2,lo2=getmedian(sdlist,2) -- methods 1 & 2 above should give dmed1==dmed2 -- but can give different lists for hi1,hi2 -- and different lists for lo1,lo2 jnk1,dtopq1,jnk2=getmedian(hi1,1) jnk1,dtopq2,jnk2=getmedian(hi2,1) jnk1,dbotq1,jnk2=getmedian(lo1,1) jnk1,dbotq2,jnk2=getmedian(lo2,1) -- method 3 uses the average of methods 1 & 2 return (dtopq1+dtopq2)/2,(dmed1+dmed2)/2,(dbotq1+dbotq2)/2,davg,drms,drmsd end -- if skip5num end -- get5num() -- https://en.wikipedia.org/wiki/Median#Easy_explanation_of_the_sample_median -- https://en.wikipedia.org/wiki/Quartile here Methods 1 and 2 are used -- below assumes vals is sorted from hi to lo function getmedian(vals,method) local lovals,hivals,med,n,hn,j,midn n=#vals hn=n/2 lovals={} hivals={} if hn==math.floor(hn) then -- if n is even, hn=n/2=integer med=(vals[hn]+vals[hn+1])/2 for j=1,hn do hivals[j]=vals[j] lovals[j]=vals[j+hn] -- j+hn rises to 2*hn=2*n/2=n=ok end -- for j -- above does not include median in vals, hivals, or lovals -- and methods 1 & 2 behave the same else -- n is odd, so midn=(n+1)/2=integer midn=(n+1)/2 med=vals[midn] -- the median is a datum from the original list in vals if method==1 then -- do not include median in hivals or lovals (Moore & McCabe, TI-83) for j=1,midn-1 do hivals[j]=vals[j] lovals[j]=vals[j+midn] -- j+midn rises to (2*midn)-1=(2*(n+1)/2)-1=(n+1)-1=n=ok end -- for j elseif method==2 then -- include median in both hivals & lovals (Tukey) for j=1,midn do hivals[j]=vals[j] lovals[j]=vals[j+midn-1] -- j+midn-1 rises to (2*midn)-1=(2*(n+1)/2)-1=(n+1)-1=n=ok end -- for j else print('ERROR: Method '..method..' is not allowed here.') end -- if method end -- if hn return hivals,med,lovals end -- getmedian() -- sortit() w/sortway==1 below was adapted from -- gary_Minima_Finder_v0.1 code 4/1/14 -- to do like Matlab's sort for a vector x. -- It should end with x[indx[i]]=s[i] and s[1]>=s[2]>=s[3] etc. -- so s ends with x's elements in descending order. -- -- sortway==1 was extremely slow for sorting all 11476 of the -- distances among 152 alpha-carbons for puzzle 973 on 1/17/16. -- It looks like it scales slightly below dim^2. function sortit(x,sortway) -- sortway==1 does non-table.sort() way -- sortway==2 does table.sort() way local s={} local sx={} local indx={} local i,j,k,dim,pflag dim=#x pflag=0 -- 0 means no printing so far, 1 means it printed something if sortway==2 then -- use table.sort way for i=1,dim do sx[i]={} sx[i][1]=x[i] -- copy x into sx sx[i][2]=i -- store original indices end -- for i table.sort(sx,comp) -- Above sorts rows of matrix sx in place from max to min -- using all cols of sx if needed. Having orig index in the -- last col of sx above makes equal items appear in reverse -- their original order. for i=1,dim do s[i]=sx[i][1] -- retrieve sorted values indx[i]=sx[i][2] -- retrieve sorted indices end -- for i elseif sortway==1 then -- use non-table.sort way for i=1,dim do s[i]=x[i] -- copy x into s indx[i]=i -- store original indices end -- for i k=0 for i=1,dim-1 do k=k+1 if k==500 then pflag=1 print(string.format('sortit(%d) is comparing item %5d of %5d with %5d other items (%s).', sortway,i,dim-1,dim-i,os.date())) k=0 end -- if k for j=dim,i+1,-1 do -- i<j always holds here if s[i]<s[j] then -- use < so get largest element first s[j],s[i]=s[i],s[j] -- swaps elements i,j indx[j],indx[i]=indx[i],indx[j] end -- if s end -- for j end -- for i end -- if sortway if pflag==1 then print(' ') end -- if pflag return s,indx end -- sortit() -- sortmat() below uses the same methods as sortit() above. -- Its goal is to sort the rows of the matrix x -- using col 1 1st, then col 2, then col 3, etc, if necessary. -- It should end with x[indx[i]][j]=s[i][j] and s[1][1]>=s[2][1]>=s[3][1] etc. -- so s ends with x's rows in descending order. function sortmat(x,sortway) -- sortway==1 does non-table.sort() way -- sortway==2 does table.sort() way local s={} local sx={} local indx={} local i,j,k,n,nrows,ncols,qflag,swapem,istr,jstr,pflag nrows=#x ncols=#(x[nrows]) pflag=0 -- 0 means no printing so far, 1 means it printed something print(string.format('sortmat(%d) is sorting a matrix with %d rows and %d cols (%s).',sortway,nrows,ncols,os.date())) pflag=1 if sortway==2 then -- use table.sort way for i=1,nrows do sx[i]={} for k=1,ncols do sx[i][k]=x[i][k] -- copy x into sx end -- for k sx[i][ncols+1]=i -- store original indices end -- for i table.sort(sx,comp) -- Above sorts rows of matrix sx in place from max to min -- using all cols of sx if needed. Having orig index in the -- last col of sx above makes equal items appear in reverse -- their original order. for i=1,nrows do s[i]={} for k=1,ncols do s[i][k]=sx[i][k] -- retrieve sorted values end -- for k indx[i]=sx[i][ncols+1] -- retrieve sorted indices end -- for i elseif sortway==1 then -- use non-table.sort way for i=1,nrows do s[i]={} for k=1,ncols do s[i][k]=x[i][k] -- copy x into s end -- for k indx[i]=i -- store original indices end -- for i n=0 for i=1,nrows-1 do -- i rises from 1 n=n+1 if n==50 then pflag=1 print(string.format('sortmat(%d) is comparing item %5d of %5d with %5d other items (%s).', sortway,i,nrows-1,nrows-i,os.date())) n=0 end -- if n for j=nrows,i+1,-1 do -- j falls from nrows -- i<j always holds here istr=string.format('s[i]=s[%3d]=(',i) jstr=string.format('s[j]=s[%3d]=(',j) for k=1,ncols do istr=string.format('%s %6.2f',istr,s[i][k]) jstr=string.format('%s %6.2f',jstr,s[j][k]) end -- for k qflag=0 swapem=false -- won't swap i,j below k=1 -- 1st try to sort using col 1 while qflag==0 do if s[i][k]<s[j][k] then -- use < so get largest element (here j) first swapem=true -- will swap i,j below qflag=1 -- will quit while loop elseif s[i][k]==s[j][k] then -- if can't sort w/col k, try w/col k+1 k=k+1 if k>ncols then -- have tried all cols, so i,j are same, let em be qflag=1 -- will quit while loop end -- if k else -- s[i][k]>s[j][k] already holds, so no need to swap i,j qflag=1 -- will quit while loop end -- if s end -- while qflag if k>1 then pflag=1 print(string.format('sortmat(%d) got to k=%2d of %d sorting s[i]=s[%3d] and s[j]=s[%3d] below (%s):', sortway,k,ncols,i,j,os.date())) print(string.format(' %s ).\n %s ).',istr,jstr)) if swapem then print(' sortmat() will swap the above s[i] and s[j] since s[j] is larger.') end -- if swapem end -- if k if swapem then -- below swaps i,j indx[j],indx[i]=indx[i],indx[j] -- swaps elements for i,j for k=1,ncols do s[j][k],s[i][k]=s[i][k],s[j][k] -- swaps elements for i,j end -- for k end -- if swapem end -- for j end -- for i end -- if sortway if pflag==1 then print(' ') end -- if pflag return s,indx end -- sortmat() -- comp() below is used with table.sort() for sortway==2 -- to sort things from highest to lowest. -- Using comp(si,sj) below put things lowest to highest 1/24/16. function comp(sj,si) local qflag,swapem,k,ncols -- here si=s[i] & sj=s[j], else code is very like in sortmat() for sortway==1 ncols=#si qflag=0 swapem=false -- won't swap i,j below k=1 -- 1st try to sort using col 1 while qflag==0 do if si[k]<sj[k] then -- use < so get largest element (here j) first swapem=true -- will swap i,j below qflag=1 -- will quit while loop elseif si[k]==sj[k] then -- if can't sort w/col k, try w/col k+1 k=k+1 if k>ncols then -- have tried all cols, so i,j are same, let em be qflag=1 -- will quit while loop end -- if k else -- si[k]>sj[k] already holds, so no need to swap i,j qflag=1 -- will quit while loop end -- if s end -- while qflag return swapem end -- comp() -- below eps template is based on 973a19h.eps -- adapted from eps file made using Matlab function makeeps1() print('%!PS-Adobe-2.0 EPSF-1.2') print('%%Creator: MATLAB, The Mathworks, Inc.') print('%%BoundingBox: 96 180 501 616') print('/MathWorks 160 dict begin') print('/bdef {bind def} bind def') print('/ldef {load def} bind def') print('/xstore {exch store} bdef') print('/c /clip ldef') print('/cc /concat ldef') print('/gr /grestore ldef') print('/gs /gsave ldef') print('/mt /moveto ldef') print('/np /newpath ldef') print('/s {show newpath} bdef') print('/sg /setgray ldef') print('/w /setlinewidth ldef') print('/pgsv () def') print('/bpage {/pgsv save def} bdef') print('/epage {pgsv restore} bdef') print('/bplot /gsave ldef') print('/eplot {stroke grestore} bdef') print('/portraitMode 0 def /landscapeMode 1 def /rotateMode 2 def') print('/dpi2point 0 def') print('/FontSize 0 def') print('/FMS {/FontSize xstore findfont [FontSize 0 0 FontSize neg 0 0]') print(' makefont setfont} bdef') print('/ISOLatin1Encoding where {pop /WindowsLatin1Encoding 256 array bdef') print('ISOLatin1Encoding WindowsLatin1Encoding copy pop') print('/.notdef/.notdef/quotesinglbase/florin/quotedblbase/ellipsis/dagger') print('/daggerdbl/circumflex/perthousand/Scaron/guilsinglleft/OE/.notdef/.notdef') print('/.notdef/.notdef/quoteleft/quoteright/quotedblleft/quotedblright/bullet') print('/endash/emdash/tilde/trademark/scaron/guilsinglright/oe/.notdef/.notdef') print('/Ydieresis WindowsLatin1Encoding 128 32 getinterval astore pop}') print('{/WindowsLatin1Encoding StandardEncoding bdef} ifelse') print('/reencode {exch dup where {pop load} {pop StandardEncoding} ifelse') print(' exch dup 3 1 roll findfont dup length dict begin') print(' { 1 index /FID ne {def}{pop pop} ifelse } forall') print(' /Encoding exch def currentdict end definefont pop} bdef') print('/isroman {findfont /CharStrings get /Agrave known} bdef') print('/FMSR {3 1 roll 1 index dup isroman {reencode} {pop pop} ifelse') print(' exch FMS} bdef') print('/csm {1 dpi2point div -1 dpi2point div scale neg translate') print(' dup landscapeMode eq {pop -90 rotate}') print(' {rotateMode eq {90 rotate} if} ifelse} bdef') print('/L {lineto stroke} bdef') print('/MR {4 -2 roll moveto dup 0 exch rlineto exch 0 rlineto') print(' neg 0 exch rlineto closepath} bdef') print('/L1i {{currentfile picstr readhexstring pop} image} bdef') print('currentdict end def') print('MathWorks begin') print('bpage') print('bplot') print('/dpi2point 12 def') print('portraitMode 0204 7344 csm') print('gs 5368 908 133 3406 MR c np') print('[131 0 0 3404 5369 909] cc') print('/picstr 1 string def') end -- makeeps1() -- below eps template is based on 973a19h.eps -- adapted from eps file made using Matlab function makeeps2() print('5368 908 mt 5368 4313 L') print('5500 908 mt 5500 4313 L') print('1874 908 mt 1874 4313 L') print('1874 908 mt 5279 908 L') print('1874 4313 mt 5279 4313 L') print('5279 908 mt 5279 4313 L') print('eplot') print('epage') print('end') print('showpage') print('%%EOF') end -- makeeps2() function epsmaker(chlist,epsway,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,davg,drmsd,tot,jdim) local chway,tops,bots,lefts,topys,botys,leftxs,toplo,bothi,leftlo,j10s,j1s,nlines local j,lnum,tmpstr,tmpstrs,ssstr,aastr,nshades,barys,bary,dcut if epsway>0 then -- do this routine print('********** copy lines below to make an eps file ('..os.date()..') **********') makeeps1() -- set up start of eps file -- -- below makes middle of eps file -- if epsway==1 then -- use 5 shades chway=11 else -- use 10 shades chway=epsway end -- if epsway nshades=#chlist[chway] -- nshades should be 5 or 10 -- -- below shades in the colorbar. -- oddly 2-digit hex works while 1-digit hex fails here. -- nevertheless, since hex 0-9A-F give 0-15 in decimal and 255/15=17, -- the single-hex digits can just be listed twice -- to get the equivalent 2-digit hex shade. print(string.format('1 %d 8 [1 0 0 %d 0 0] L1i',nshades,nshades)) -- the 8 in the above line means 8 bits=2^8=256=0-255=00-FF=2-hex digits per shaded box tmpstr='' for j=nshades,1,-1 do tmpstr=string.format('%s%s%s',tmpstr,chlist[chway][j],chlist[chway][j]) end -- for j print(tmpstr) print('gr') -- -- below preps to shade the main part of the plot the 1-digit hex way. -- would 1-digit hex fail if there were <=10 AA's to be plotted (if jdim<=10) ? print('gs 1874 908 3406 3406 MR c np') print('[3404 0 0 3404 1875 909] cc') print(string.format('/picstr %d string def',jdim)) print(string.format('%d %d 8 [%d 0 0 %d 0 0] L1i',jdim,jdim,jdim,jdim)) -- version 1.1: the 8 in the above line means 8 bits per shaded box -- (was: the 4 in the above line means 4 bits=2^4=16=0-15=0-F=1-hex digit per shaded box) -- -- below fills in the graph part with single hexadecimal digits for each value in dds makechart(chlist,chway,0,0,0,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,jdim,0,true) print('gr') -- -- below prepares the text parts for the eps file tops={} -- up to 7 lines of 60 characters each for above the graph, 1st line is highest bots={} -- up to 7 lines of 60 characters each for below the graph, 1st line is highest lefts={} -- up to 7 lines of 48 characters each to left of the graph, 1st line is left-most tmpstrs={} -- up to 7 lines of 48 characters each, sometimes on top, sometimes on left tmpstrs[1]=string.format('%s: %s of %s',recipename,user.GetPlayerName(),user.GetGroupName()) tmpstrs[2]=string.format('%s',puzzle.GetName()) tmpstrs[3]=string.format('score=%.3f on %d at %s',trunc3(current.GetScore()),puzzle.GetPuzzleID(),os.date()) tmpstrs[4]=string.format('dist=%.2f (Ca%d-Ca%d) to %.2f (Ca%d-Ca%d)',mindist,minj1,minj2,maxdist,maxj1,maxj2) tmpstrs[5]=string.format('avg+-rmsdev=%.2f+-%.2f=%.2f to %.2f',davg,drmsd,davg-drmsd,davg+drmsd) tmpstrs[6]=string.format('epsway=%d w/%d dist ranges for %d of %d AA\'s',epsway,nshades,jdim,tot) j10s='000000000111111111122222222223333333333444444444455555555556' -- 60 chars wide j1s='123456789012345678901234567890123456789012345678901234567890' -- 60 chars wide nlines=math.ceil(tot/60) -- tot=300 will give 5 lines for AAs and 5 lines for SSs if nlines>5 then -- chop off AAs and SSs beyond 5 lines or with segment #'s > 300 nlines=5 end -- if nlines if nlines<=2 then -- place all the SS and AA info at the bottom, other info at top bothi=2*nlines+2 bots[1]=j10s bots[2]=j1s toplo=2 for j=1,6 do tops[toplo+j-1]=tmpstrs[j] end -- for j leftlo=8 -- set it above 7 so it won't use the left positions else -- put the SS info at the top, the AA info at the bottom, and other info to left bothi=nlines+2 toplo=6-nlines tops[toplo]=j10s tops[toplo+1]=j1s bots[1]=j10s bots[2]=j1s leftlo=2 for j=1,6 do lefts[leftlo+j-1]=tmpstrs[j] end -- for j end -- if nlines for lnum=1,nlines do j0=(lnum-1)*60 aastr='' ssstr='' for j=(j0+1),(j0+60) do if j<=tot then aastr=(aastr..aas[j]) ssstr=(ssstr..sss[j]) else aastr=(aastr..' ') ssstr=(ssstr..' ') end -- if j end -- for j if nlines<=2 then -- SS and AA info go at bottom bots[2+lnum]=ssstr bots[2+lnum+nlines]=aastr else -- SS info at top, AA info at bottom tops[toplo+1+lnum]=ssstr bots[2+lnum]=aastr end -- if nlines end -- for lnum -- -- below are coordinates for different lines of text on the plot topys={96,216,336,456,576,696,816} -- #'s rise from top to bottom on plot botys={4476,4596,4716,4836,4956,5076,5196} -- #'s rise from top to bottom leftxs={1062,1182,1302,1422,1542,1662,1782} -- #'s rise from left to right barys={4349,4009,3668,3328,2987,2647,2306,1966,1625,1285,944} -- #'s fall bot to top -- barys are listed in reverse order to correspond better with dcuts & dds -- -- below adds text to the eps file print('0 sg') print('/Courier-Bold /WindowsLatin1Encoding 120 FMSR') print('6 w') -- next few lines are to left of plot for j=leftlo,7 do print(leftxs[j]..' 4339 mt -90 rotate ('..chopchars(lefts[j],48)..') s 90 rotate') end -- for j -- next few lines are above the plot for j=toplo,7 do print(string.format('1416 %4d mt (%s) s',topys[j],chopchars(tops[j],60))) end -- for j -- next few lines are below the plot for j=1,bothi do print('1416 '..botys[j]..' mt ('..chopchars(bots[j],60)..') s') end -- for j -- below adds labels and horizontal lines to colorbar for j=nshades,0,-1 do if j==0 then dcut='0 ' elseif j==nshades then dcut='Inf' else if nshades==5 then -- j=1 to 4, so 2*j=2 to 8 dcut=string.format('%d ',dcuts[2*j]) else -- j=1 to 9, dcuts only has 9 elements dcut=string.format('%d ',dcuts[j]) end -- if nshades end -- if j -- in the above, it is ok to pad the right with extra blanks. -- we will want just 1st 3 characters in dcut below, -- and we want the numbers in dcut to be left-justified. if nshades==5 then -- here j=0 to 5 step 1 bary=barys[2*j+1] -- here 2*j+1=1 to 11 step 2 else -- nshades==10 -- here j=0 to 10 step 1 bary=barys[j+1] -- here j+1=1 to 11 step 1 end -- if nshades print(string.format('5368 %4d mt 5500 %4d L',bary-36,bary-36)) print(string.format('5520 %4d mt (%3s) s',bary,string.sub(dcut,1,3))) end -- for j -- -- above makes middle of eps file -- makeeps2() -- set up end of eps file print('********** copy lines above to make an eps file ('..os.date()..') **********') print(' ') end -- if epsway end -- epsmaker() -- below forces the string str to be dim characters long function chopchars(str,dim) local len,res,j,isodd len=string.len(str) -- len is # of characters in str if len<dim then -- pad both sides with blank spaces res=str isodd=1 for j=1,(dim-len) do if isodd==0 then -- j is even res=(' '..res) else -- j is odd res=(res..' ') end -- if j isodd=1-isodd end -- for j elseif len>dim then -- just keep the 1st dim characters of str res=string.sub(str,1,dim) else -- just copy str into res res=str end -- if len return res end -- chopchars() function makechart(chlist,chway,revflag,spflagi,lbls,sss,aas,dds,dcuts,mindist,maxdist,minj1,minj2,maxj1,maxj2,tot,jdimi,roflag, doubled ) -- -- version 1.1 -- double up output for eps chart -- (requires a bit of wrenching) -- -- add new "doubled" parm, make it optional -- if doubled == nil then doubled = false end local tmpstr,j100s,j10s,j1s,alleq,ssstr,aastr local js,j,j1,j2,j100,j10,jrem,jdim,ch,chs,nchs,spflag,spcs,spc if roflag==1 then -- roflag==1 means use special format for Recipe Output window jdim=9 spflag=0 -- means no spaces else jdim=jdimi spflag=spflagi -- 0=no spaces, 1=spaces, 2=commas end -- if roflag chs={} nchs = #chlist [ chway ] -- should be 5 or 10 for jj = 1, nchs do if revflag == 1 then -- do them in reverse order ch = chlist [ chway ] [ nchs - jj + 1 ] else -- do them in normal order ch = chlist [ chway ] [ jj ] end -- if revflag -- next part makes sure jj in chs[jj] is 0-9 if nchs == 10 then chs [ jj - 1 ] = ch else -- nchs==5 chs [ 2 * jj - 2 ] = ch chs [ 2 * jj - 1 ] = ch end -- if nchs end -- for jj -- -- lbls==0 all labels off, =1 left labels off, top/bot labels on, =2 all labels on if lbls==2 then -- left labels are on j1s=' ' else -- left labels are off j1s='' end -- if lbls if lbls>=1 then -- top/bottom labels are on j10s=j1s j100s=j1s alleq=j1s ssstr=j1s aastr=j1s spcs={'',' ',','} spc=spcs[spflag+1] end -- if lbls js={} for j=1,jdim do js[j]=1+round0((j-1)*(tot-1)/(jdim-1)) -- want j=1 to jdim to give js=1 to tot if lbls>=1 then -- top/bottom labels are on if j==jdim then spc='' end -- if j j100=trunc0(js[j]/100) jrem=js[j]-j100*100 j10=trunc0(jrem/10) j1=jrem-j10*10 j100s=(j100s..j100..spc) j10s=(j10s..j10..spc) j1s=(j1s..j1..spc) alleq=(alleq..'|'..spc) ssstr=(ssstr..sss[js[j]]..spc) aastr=(aastr..aas[js[j]]..spc) end -- if lbls end -- for j for j1=jdim,1,-1 do spcs={'-',' ',','} spc=spcs[spflag+1] if roflag==1 then -- do special format for Recipe Output window tmpstr=string.format('%03d%s',js[j1],spc) else -- do more general formats if lbls==2 then -- left labels are on tmpstr=string.format('%s%03d%s%s',sss[js[j1]],js[j1],aas[js[j1]],spc) else -- left labels are off tmpstr='' end -- if lbls end -- if roflag spcs={'',' ',','} spc=spcs[spflag+1] for j2=1,jdim do if j2==jdim then spc='' end -- if j2 if doubled then tmpstr=string.format('%s%s%s%s',tmpstr,chs[dds[js[j1]][js[j2]]],chs[dds[js[j1]][js[j2]]],spc) else tmpstr=string.format('%s%s%s',tmpstr,chs[dds[js[j1]][js[j2]]],spc) end end -- for j2 if roflag==1 then -- do special format for Recipe Output window if j1==9 then tmpstr=string.format('%s %s: for all %d amino acids',tmpstr,recipename,tot) elseif j1==8 then tmpstr=string.format('%s min Ca-Ca dist=%6.2f for %3d-%d',tmpstr,mindist,minj1,minj2) elseif j1==7 then tmpstr=string.format('%s max Ca-Ca dist=%6.2f for %3d-%d',tmpstr,maxdist,maxj1,maxj2) elseif j1==6 then tmpstr=string.format('%s Ca-Ca dist ranges (chway=%d rev=%d):',tmpstr,chway,revflag) elseif nchs==10 then if j1==5 then tmpstr=string.format('%s %s=0 for 0-%-3s %s=1 for %2d-%d', tmpstr,chs[0],string.format('%d,',dcuts[1]),chs[1],dcuts[1],dcuts[2]) elseif j1==1 then tmpstr=string.format('%s %s=8 for %2d-%-3s %s=9 for %2d-Inf', tmpstr,chs[8],dcuts[8],string.format('%d,',dcuts[9]),chs[9],dcuts[9]) else j=2*(5-j1) -- j1==4 -> j=2, j1==3 -> j=4, j1==2 -> j=6 tmpstr=string.format('%s %s=%d for %2d-%-3s %s=%d for %2d-%d', tmpstr,chs[j],j,dcuts[j],string.format('%d,',dcuts[j+1]),chs[j+1],j+1,dcuts[j+1],dcuts[j+2]) end -- if j1 else -- nchs==5 should hold if j1==5 then tmpstr=string.format('%s %s=0 for 0-%d',tmpstr,chs[0],dcuts[2]) elseif j1==1 then tmpstr=string.format('%s %s=4 for %2d-Inf',tmpstr,chs[8],dcuts[8]) else j=(5-j1) -- j1==4 -> j=1, j1==3 -> j=2, j1==2 -> j=3 tmpstr=string.format('%s %s=%d for %2d-%d',tmpstr,chs[2*j],j,dcuts[2*j],dcuts[2*j+2]) end -- if j1 end -- if nchs end -- if roflag print ( tmpstr ) end -- for j1 if roflag~=1 then -- do more general formats if lbls>=1 then -- top/bottom labels are on print(alleq) print(ssstr) print(j100s) print(j10s) print(j1s) print(aastr) end -- if lbls end -- if roflag end -- makechart() -- below rounds down to 3 decimal places (nearest 0.001) function trunc3(numi) local numo=trunc0(numi*1000)/1000 return numo end -- trunc3() -- below rounds to 2 decimal places (nearest 0.01) function round2(numi) local numo=round0(numi*100)/100 return numo end -- round2() -- below rounds to 1 decimal place (nearest 0.1) function round1(numi) local numo=round0(numi*10)/10 return numo end -- round1() -- below rounds val to the nearest integer to get res function round0(val) local res=math.floor(val) if val-res>=0.5 then res=res+1 end -- if val return res end -- round0() -- below rounds val down to the nearest integer to get res function trunc0(val) local res=math.floor(val) return res end -- trunc0() Main()

Comments


LociOiling Lv 1

This version of DistMap increases the output to 8 bits, putting out two hex characters per point in the EPS section. This doubles the length of each line, while the number of lines remain the same.

This change seems to get around issues with the previous scheme, which used 4 bits or one hex digit per point.

LociOiling Lv 1

The fix simply repeats the previous single digit. So "0" is now "00", "1" is now "11", "2" is "22", and so on. Perhaps we could do something more create with the extra bits, but good enough for now.