Python Programming for Biology: Bioinformatics and Beyond



Download 7,75 Mb.
Pdf ko'rish
bet433/514
Sana30.12.2021
Hajmi7,75 Mb.
#91066
1   ...   429   430   431   432   433   434   435   436   ...   514
Bog'liq
[Tim J. Stevens, Wayne Boucher] Python Programming

Using Python Qt

The same DNA sequence GUI example will be shown again, but using Qt-based libraries

to compare and contrast with the Tkinter system. There are currently several choices for a

Python-based Qt graphics library,  PyQt4,  PyQt5  and  PySide,  though  PyQt5  only  arrived

after  most  of  this  book  was  written.  For  the  most  part  these  are  almost  identical  and

Python code that works in one will work with the other with only minor adjustments. For

the example we will use PySide because we feel it has a more Pythonic

7

way of dealing



with  GUI  signals  (widget  callbacks  etc.),  and  also  less  restrictive  licence  conditions.

Unfortunately  PyQt5  arrived  too  late  to  be  considered  in  this  book,  though  this  is  the

system the authors would use in the future, given that it has the most active development

and


the

future


of

PySide


is

somewhat

uncertain.

See


http://www.cambridge.org/pythonforbiology

 for  PySide  and  PyQt  download  and  install

instructions, as well as links to full documentation.

Compared to Tk the Qt libraries for Python have a larger variety of widgets, although

we  will  only  use  a  few  in  the  example.  Also,  Qt  naturally  exposes  a  greater  variety  of

signals,  although  Tk  can  be  expanded  somewhat  by  the  use  of  .bind()  calls,  to  connect

events  to  widgets.  For  example,  a  Tkinter.Button  is  generally  only  used  with  a  single

callback  for  when  the  button  is  pressed.  The  nearest  Qt  equivalent,  QtGui.QPushButton,

automatically comes with clicked, pressed, released and toggled signals.

Compared  to  other  libraries  used  in  this  book  the  Python  bindings  to  Qt  feel  a  little

different, because of the way the underlying C++ code is wrapped. For example, most Qt

objects  are  created  with  few  initial  arguments,  and  the  object  is  configured  with  various

calls

after


it

is


created.

Also


nomenclature

like


‘QtCore.Qt.AlignLeft  |

QtCore.Qt.AlignRight’  can  seem  a  bit  unfriendly  at  first.  Here  the  vertical  line  is  the

logical OR operator and is simply a means of combining the two options for left and right

alignment, which are represented as separate bits in a binary number (a typical C++ style

of doing things). This example, albeit using binary, is actually just equivalent to 1 + 2  in

Python.



For the GUI example we make the initial imports. If PyQt4 is used instead the connect()

calls  in  the  class  must  be  adjusted,  as  mentioned  below.  Qt  is  separated  into  discrete

modules  which  relate  to  different  aspects  of  the  system  and  here  we  import  the  required

QtCore and QtGui.

import re

from PySide import QtCore, QtGui # or from PyQt4

from Sequences import proteinTranslation, STANDARD_GENETIC_CODE

The SequenceQtGui definition is a subclass of the basic QtGui.QWidget and when we

initialise  this  class  we  also  initialise  the  superclass  for  self.  Although  QWidget  is  more

directly  comparable  to  Tk  used  earlier,  the  programmer  can  also  consider  using

QMainWindow  because  this  comes  prepared  with  slots  for  a  main  menu,  tool  bar  and

status bar etc.

class SequenceQtGui(QtGui.QWidget):

def __init__(self):

QtGui.QWidget.__init__(self, parent=None)

In Qt it is fairly common to use simple horizontal and vertical layouts to arrange sub-

widgets in a window, but here we will use a grid, as in the previous example. Rather than

the  grid  being  inbuilt  into  the  widget  system  we  need  to  make  a  layout  object,

QGridLayout, and say that this belongs to self, i.e. it is the layout for the main window.

grid = QtGui.QGridLayout(self)

The layout object grid can then be used to configure the size behaviour of the rows and

columns. As before column 5, row 1 and row 4 are set to expand with weight 1.

grid.setColumnStretch(5, 1)

grid.setRowStretch(1, 1)

grid.setRowStretch(4, 1)

As  an  equivalent  to  Tkinter.EW,  to  refer  to  the  left  and  right  edges  of  a  grid  cell,  we

define  leftRight  for  later  use  by  combining  the  binary  Qt.AlignLeft  and  Qt.AlignRight

options.


leftRight = QtCore.Qt.AlignLeft | QtCore.Qt.AlignRight

Next  we  make  the  actual  sub-widgets.  A  QtGui.QLabel  is  constructed,  which  is  the

equivalent  of  Tkinter.Label.  Instead  of  a  simple  label  the  QtGui.QGroupBox  could  be

used, which provides a title and a border to group sub-widgets. Once the widget is made it

is then added to the grid layout at position 0,0; the first row and column.

self.label1 = QtGui.QLabel(text='Enter 1-Letter DNA Sequence:',

parent=self)

grid.addWidget(self.label1, 0, 0)

Next  to  be  constructed  is  the  upper  text  box.  This  will  be  from  the



QtGui.QPlainTextEdit  class  (there  is  also  QTextEdit  which  supports  rich  text  mark-up).

This  goes  in  the  next  row  of  the  grid  (1,0)  and  we  include  the  row  and  column  span

arguments (1,6) to cover one row and six columns. The align argument dictates how the

widget sticks to the grid sides. Note that compared to the Tk equivalent the Qt text box has

more functionality, e.g. there is a context menu (right mouse click) with editing options,

which we do not use here.

self.seqTextBox = QtGui.QPlainTextEdit(parent=self)

grid.addWidget(self.seqTextBox, 1, 0, 1, 6, align=leftRight)

The  QtGui.QPushButton  class  is  used  for  simple  buttons.  Unlike  Tk,  where  we  just

specify the callback for the button with command, for Qt we have to select which kind of

user action we want it to respond to. Here we want the callback to be triggered from the

clicked  action  (technically  a  slot  in  Qt).  The  connecting  of  an  action  slot  to  a  callback

function  is  usually  done  differently  for  PyQt4  and  PySide  libraries.  For  this  PySide

example the self.clearButton.clicked  object  represents  the  button  clicking,  and  this  has  a

connect()  function  to  link  it  to  whichever  callback  function  we  desire.  Thus  the  button

click  calls  self.clearSeq.  A  comment  is  included  below  to  illustrate  the  equivalent  for

PyQt4.  This  involves  actually  creating  a  SIGNAL  object  using  a  text  string  (not  very

Pythonic) and then the connect() call to link the target of the signal to the function comes

from a Qt widget (self in this case).

8

self.clearButton = QtGui.QPushButton(text='Clear', parent=self)



self.clearButton.clicked.connect(self.clearSeq)

grid.addWidget(self.clearButton, 2, 0)

#PyQt4 uses:

#self.connect(self, QtCore.SIGNAL('clicked()'), self.clearSeq)

The other buttons are made in a similar way, and placed in separate grid columns:

self.loadButton = QtGui.QPushButton(text='Load FASTA', parent=self)

self.loadButton.clicked.connect(self.loadFasta)

grid.addWidget(self.loadButton, 2, 1)

self.transButton = QtGui.QPushButton(text='Translate', parent=self)

self.transButton.clicked.connect(self.seqTranslate)

grid.addWidget(self.transButton, 2, 2)

self.compButton = QtGui.QPushButton(text='Composition', parent=self)

self.compButton.clicked.connect(self.seqComposition)

grid.addWidget(self.compButton, 2, 3)

self.findButton = QtGui.QPushButton(text='Find:', parent=self)

self.findButton.clicked.connect(self.seqFind)

grid.addWidget(self.findButton, 2, 4)

The  last  widget  in  row  2  is  the  small  text  box  for  the  user  to  enter  a  query  DNA

sequence. The class used is QtGui.QLineEdit and we will not connect any callback to the

widget,  although  we  could  use  returnPressed  or  editingFinished  action  slots  to  do

something when the user changes the text.



self.findEntry = QtGui.QLineEdit(parent=self)

grid.addWidget(self.findEntry, 2, 5)

Lastly we add the second label, the lower text area for output and the quit button (which

is  connected  to  the  inbuilt  QWidget.destroy()).  Note  that  in  order  to  configure  the  text

widget,  in  this  case  to  say  how  the  text  wraps  around  at  the  end  of  a  line,  the  function

.setLineWrapMode() is used after the object is created.

self.label2 = QtGui.QLabel(text='Text output:', parent=self)

grid.addWidget(self.label2, 3, 0, 1, 6)

self.outTextBox = QtGui.QPlainTextEdit(parent=self)

self.outTextBox.setLineWrapMode(QtGui.QPlainTextEdit.NoWrap)

grid.addWidget(self.outTextBox, 4, 0, 1, 6, align=leftRight)

self.closeButton = QtGui.QPushButton(self, text='Quit')

self.closeButton.clicked.connect(self.destroy)

grid.addWidget(self.closeButton, 5, 5, align=leftRight)

The next functions after the initialisation involve clearing and updating the text areas.

This  is  a  little  simpler  than  with  Tk,  given  that  .clear()  is  inbuilt  in  to

QtGui.QPlainTextEdit.  As  you  might  expect,  the  names  and  the  actions  of  the  functions

differ  between  the  two  systems.  For  example,  setPlainText()  replaces  all  the  text,  so  we

don’t  have  to  clear  first.  Likewise,  using  appendPlainText()does  not  need  newline

characters to be added to text.

def clearSeq(self):

self.seqTextBox.clear()

def setSequence(self, text):

self.seqTextBox.setPlainText(text)

def showText(self, text):

self.outTextBox.appendPlainText(text)

def clearOutput(self):

self.outTextBox.clear()

Fetching  the  DNA  sequence  is  simple  and  employs  .toPlainText()  rather  than  Tk’s

.get(). The tidying of the DNA sequence is done as described earlier.

def getSequence(self):

seq = self.seqTextBox.toPlainText()

seq = re.sub('\s+','',seq)

seq = seq.upper()

return seq

The  loadFasta  function  uses  the  compound  widget  QtGui.QFileDialog  to  get  the  file




name.  This  looks  somewhat  prettier  than  the  Tk  equivalent,  and  will  have  a  style  that

represents the native operating system. Note that getOpenFileName does not give back a

file object. Rather it gives back the location of the file, so we use open() to get the actual

file object that BioPython works with.

def loadFasta(self):

msg = 'Choose a FASTA file'

filePath, filtr = QtGui.QFileDialog.getOpenFileName(self, msg)

if filePath: # Something was selected

fileObj = open(filePath, 'rU')

from Bio import SeqIO

for entry in SeqIO.parse(fileObj, 'fasta'):

self.setSequence(str(entry.seq))

break

fileObj.close()



The two functions seqTranslate()and seqComposition() are unchanged compared to the

Tk equivalent, so we will not repeat them. However, it is worth pointing out that the lack

of  any  difference  shows  that  we  have  separated  the  more  graphical  functions  from  the

scientific functions, which is generally a good plan.

For  finding  a  query  DNA  sub-sequence  the  seqFind  function  is  similar  to  before.  The

differences are that the query entry box uses .text() not .get()  and  that  we  have  naturally

swapped to QtGui.QMessageBox to display warnings to the user. One extra thing that has

been included here is self.seqTextBox.find(query). This highlights successive instances of

the query string in the upper text area. Although Tkinter.Text has a search() function this

merely finds text, but does not highlight it.

def seqFind(self):

self.clearOutput()

query = self.findEntry.text()

query = query.strip()

if not query:

QtGui.QMessageBox.warning(self, "Warning",

"Search sequence was blank")

return


seq = self.getSequence()

self.seqTextBox.find(query)

if query in seq:

text = "Locations of %s" % (query)

self.showText(text)

win = len(query)

for i in range(len(seq)-win):



if seq[i:i+win] == query:

self.showText(' %d' % i)

else:

text = "Sub-sequence %s not found" % (query)



self.showText(text)

To  test  the  SequenceQtGui  class  code  we  have  a  little  work  to  do.  A  Qt  graphical

interface  only  works  if  there  is  a  QApplication  instance  to  control  the  flow  of  the  GUI

program and carry its main settings (this does some of the job that the Tk root does). The

application  object  is  accordingly  made  and  assigned  to  the  app  variable.  The  window

object is made using the SequenceQtGui class described above and will become the top-

level graphical object. The .show() call is required to actually see something; although this

might seem a little tedious it is really handy to be able to control the visibility of widgets

(all  QWidgets  have  .show()).  The  final  line  looks  a  little  odd,  but  is  merely  running  the

QApplication,  and  is  equivalent  to  Tk.mainloop().  The  function  is  called  ‘exec_’  not

‘exec’  because  the  latter  is  an  inbuilt  keyword  of  Python.  This  call  is  wrapped  by

sys.exit(), which is required for the program to exit cleanly when done.

if __name__ == '__main__':

import sys

app = QtGui.QApplication(['Qt Sequence Example'])

window = SequenceQtGui()

window.show()

sys.exit(app.exec_())




Download 7,75 Mb.

Do'stlaringiz bilan baham:
1   ...   429   430   431   432   433   434   435   436   ...   514




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish