PageRenderTime 41ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Scripts/xbbtools/xbb_search.py

http://github.com/biopython/biopython
Python | 196 lines | 176 code | 8 blank | 12 comment | 0 complexity | a107a3d22b77294c8101269eee6d879a MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #!/usr/bin/env python
  2. # Copyright 2000 by Thomas Sicheritz-Ponten.
  3. # Copyrigth 2016 by Markus Piotrowski.
  4. # All rights reserved.
  5. # This code is part of the Biopython distribution and governed by its
  6. # license. Please see the LICENSE file that should have been included
  7. # as part of this package.
  8. # Created: Sun Dec 3 13:38:52 2000
  9. # thomas@cbs.dtu.dk, http://www.cbs.dtu.dk/thomas
  10. """Search code for graphical Xbbtools tool."""
  11. import re
  12. import tkinter as tk
  13. import tkinter.ttk as ttk
  14. from tkinter import colorchooser
  15. from Bio.Data.IUPACData import ambiguous_dna_values
  16. from Bio.Seq import reverse_complement
  17. import xbb_widget
  18. class DNAsearch:
  19. """Class to search a DNA sequence."""
  20. def __init__(self):
  21. """Set up the alphabet."""
  22. self.init_alphabet()
  23. self.sequence = ""
  24. def init_alphabet(self):
  25. """Expand alphabet values for ambiguous codes."""
  26. self.alphabet = ambiguous_dna_values
  27. other = "".join(self.alphabet)
  28. self.alphabet["N"] = self.alphabet["N"] + other
  29. for key in self.alphabet:
  30. if key == "N":
  31. continue
  32. if key in self.alphabet[key]:
  33. continue
  34. self.alphabet[key] = self.alphabet[key] + key
  35. def SetSeq(self, seq):
  36. """Set sequence."""
  37. self.sequence = seq
  38. def SetPattern(self, pattern):
  39. """Convert search pattern to regular expression."""
  40. self.pattern = pattern
  41. self.rx_pattern = self.IUPAC2regex(pattern)
  42. self.rx = re.compile(self.rx_pattern)
  43. def IUPAC2regex(self, s):
  44. """Translate search text into pattern."""
  45. rx = ""
  46. for i in s:
  47. r = self.alphabet.get(i, i)
  48. if len(r) > 1:
  49. rx = f"{rx}[{r}]"
  50. else:
  51. rx += r
  52. return rx
  53. def _Search(self, start=0):
  54. """Search and return MatchObject (PRIVAT)."""
  55. # Only called from SearchAll. Is it used?
  56. pos = self.rx.search(self.sequence, start)
  57. return pos
  58. def Search(self, start=0):
  59. """Search for query sequence and return position."""
  60. pos = self.rx.search(self.sequence, start)
  61. if pos:
  62. return pos.start()
  63. else:
  64. return -1
  65. def SearchAll(self):
  66. """Search the whole sequence."""
  67. # Doesn't seem to be used...
  68. pos = -1
  69. positions = []
  70. while True:
  71. m = self._Search(pos + 1)
  72. if not m:
  73. break
  74. pos = m.start()
  75. if pos == -1:
  76. break
  77. positions.append(pos)
  78. return positions
  79. class XDNAsearch(tk.Toplevel, DNAsearch):
  80. """Graphical tools to perform the DNA search."""
  81. def __init__(self, seq="", master=None, highlight=0):
  82. """Initialize the search GUI."""
  83. DNAsearch.__init__(self)
  84. self.master = master
  85. self.highlight = highlight
  86. self.colors = []
  87. self.init_graphics()
  88. self.sequence = seq
  89. self.cur_pos = 0
  90. def init_graphics(self):
  91. """Build the search window."""
  92. tk.Toplevel.__init__(self, self.master)
  93. self.frame = ttk.Frame(self)
  94. self.frame.pack(fill=tk.BOTH, expand=1)
  95. self.search_entry = ttk.Entry(self.frame)
  96. self.search_entry.pack(fill=tk.BOTH, expand=1)
  97. f2 = ttk.Frame(self.frame)
  98. f2.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
  99. f = f2
  100. self.forward = ttk.Button(f, text="Search +", command=self.do_search)
  101. self.forward.pack(side=tk.LEFT)
  102. self.forward = ttk.Button(
  103. f, text="Search -", command=lambda x=self.do_search: x(other_strand=1)
  104. )
  105. self.forward.pack(side=tk.LEFT)
  106. self.cancel = ttk.Button(f, text="Cancel", command=self.exit)
  107. self.cancel.pack(side=tk.LEFT)
  108. self.current_color = "cyan"
  109. self.colorb = ttk.Button(f, text="Color", command=self.change_color)
  110. self.colorb.pack(side=tk.LEFT)
  111. self.config_color(self.current_color)
  112. def config_color(self, color=None):
  113. """Set color for found sequence tag."""
  114. if not self.highlight:
  115. return
  116. if not color:
  117. color = colorchooser.askcolor()[1]
  118. if not color:
  119. color = "cyan"
  120. self.current_color = color
  121. self.current_tag = f"searched_{self.current_color}"
  122. self.master.tag_config(self.current_tag, background=self.current_color)
  123. self.master.tag_config(
  124. self.current_tag + "R", background=self.current_color, underline=1
  125. )
  126. self.colors.append(color)
  127. def change_color(self):
  128. """Call back for color button."""
  129. self.config_color()
  130. def get_pattern(self):
  131. """Retrieve query sequence."""
  132. pattern = self.search_entry.get()
  133. return pattern
  134. def do_search(self, other_strand=0):
  135. """Start the search."""
  136. pattern = self.get_pattern()
  137. if other_strand:
  138. pattern = reverse_complement(pattern)
  139. self.SetPattern(pattern)
  140. pos = self.Search(self.cur_pos)
  141. self.cur_pos = pos + 1
  142. w = self.master
  143. if pos != -1:
  144. if self.highlight:
  145. start, stop = pos, pos + len(self.pattern)
  146. if other_strand:
  147. w.tag_add(self.current_tag + "R", f"1.{start:d}", f"1.{stop}")
  148. else:
  149. w.tag_add(self.current_tag, f"1.{start:d}", f"1.{stop}")
  150. w.see(f"1.{start:d}")
  151. def exit(self):
  152. """Clean up on exit."""
  153. for c in self.colors:
  154. self.master.tag_remove(f"searched_{c}", 1.0, tk.END)
  155. self.master.tag_remove(f"searched_{c}R", 1.0, tk.END)
  156. self.destroy()
  157. del self
  158. if __name__ == "__main__":
  159. win = tk.Tk()
  160. xbbtools = xbb_widget.xbb_widget()
  161. seq = "ATGGTGTGTGTGTACGATCGCCCCCCCCAGTCGATCGATGCATCGTA"
  162. xbbtools.insert_sequence(("Test_seq", seq))
  163. xbbtools.search()
  164. win.mainloop()