Skip to content

Commit 7a08d41

Browse files
committed
tcltk macosfix and new binaries
1 parent 3da1cbd commit 7a08d41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+3624
-130
lines changed

README.md

+10-3
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,21 @@ Description
99

1010
iqtreeGUI is a graphical front-end for [IQ-TREE](http://www.iqtree.org). The goal is to implement all features of IQ-TREE 1.6.*. It is under active development and therefore several features are still missing (eg. a GUI for likelihood mapping, topology tests). iqtreeGUI is written in Python3 and executables are available for Windows, Linux and MacOS.
1111

12-
**Note:** In the MacOS version on MacOS 10.14 of iqtreeGUI at start some buttons and menus will not display text correctly. This is due to a bug in Tcl/Tk framework. Till the bug in Tcl/Tk gets removed, simply resize the window slightly and everythingh should look fine.
1312

1413
![Screenshot of iqtreeGUI](screenshot.png)
1514
*Figure: iqtreeGUi running on MacOS High Sierra*
1615

1716
A work in progress
1817
==============
19-
One of the great things about IQ-TREE is that is has lots of possibilities to combine different parameters and analyses. While iqtreeGUI aims to provide a graphical way to access all these features, it is almost impossible to test every possible combination of parameters IQ-TREE allows. At the moment iqtreeGUI is still under active developement. Therefore there may still be a large number of bugs. I am greatful for every bug report I receive. Reporting bugs will help to improve iqtreeGUI.
18+
One of the great things about IQ-TREE is that is has lots of possibilities to combine different parameters and analyses. While iqtreeGUI aims to provide a graphical way to access all these features, it is almost impossible to test every possible combination of parameters IQ-TREE allows. At the moment iqtreeGUI is still under active development. Therefore there may still be a large number of bugs. I am greatful for every bug report I receive. Reporting bugs will help to improve iqtreeGUI.
19+
20+
Changelog:
21+
========
22+
23+
Nov.13 2019 v(13112019): New version with many bug fixes:
24+
- The pyinstaller executable for MacOS should now work properly again.
25+
- The code is now better organized which removed occasional strange behavior in older versions
26+
- A problem with tkinter on newer versions of MacOS caused different rendering problems. This should now be fixed as well (tested on MacOS 10.14)
2027

2128
Features
2229
===========
@@ -39,7 +46,7 @@ Currently implemented features:
3946

4047
Obtaining and configuring iqtreeGUI
4148
================
42-
Executables are available for Linux, MacOS and Windows. The Windows and Linux versions were built using a combination of Docker and pyinstaller.
49+
Executables are available for Linux, MacOS and Windows. The Windows and Linux versions were built using a combination of Docker and [pyinstaller] (https://pyinstaller.readthedocs.io).
4350

4451
For iqtreeGUI to work you will also need to download and install [IQ-TREE](http://www.iqtree.org). Once you have started iqtreeGUI you will have to set the correct path to the IQ-TREE executable. Click on iqtreeGUI -> GUI settings and select the iqtree executable.
4552

build_all.sh

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
#!/bin/bash
2-
# This script builds the Linux and Windows Versions of iqtreeGUI using Docker
1+
#!/bin/zsh
2+
# This script builds Linux, Windows and MacOS Versions of iqtreeGUI using cdrx/pyinstallers Docker containers.
33

44

55
#Windows build: requires Docker
6-
docker run -v "$(pwd):/src/" cdrx/pyinstaller-windows:python3
6+
docker run -t --rm -v "$(pwd):/src/" cdrx/pyinstaller-windows:python3 "apt-get update -y && apt-get install -y python3-tk && pyinstaller --clean -y --dist ./dist/windows --workpath /tmp *.spec"
77

88
#Linux Build: requires Docker with custom command
9-
docker run -v "$(pwd):/src/" cdrx/pyinstaller-linux:python3 "apt-get update -y && apt-get install -y python3-tk && pyinstaller --clean -y --dist ./dist/linux --workpath /tmp *.spec"
9+
docker run --rm -v "$(pwd):/src/" cdrx/pyinstaller-linux:python3 "apt-get update -y && apt-get install -y python3-tk && pyinstaller --clean -y --dist ./dist/linux --workpath /tmp *.spec"
1010

11+
pyinstaller iqtreegui_mac.spec
12+
cp -r tcltk_lib/lib dist/iqtreeGUI.app/Contents/

config.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[Settings]
2+
iqtree = iqtree111
3+
version = 12112019
4+

dist/iqtrGUI_v13112019.zip

28.7 MB
Binary file not shown.

iqtgui_modules/ScrollableFrame.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#! /usr/bin/env python
2+
# add credits...
3+
import sys
4+
from tkinter import *
5+
from tkinter.ttk import *
6+
7+
class ScrollableFrame(Frame):
8+
"""
9+
Consider me a regular frame with a vertical scrollbar
10+
on the right, after adding/removing widgets to/from me
11+
call my method update() to refresh the scrollable area.
12+
Don't pack() me, nor place() nor grid().
13+
I work best when I am alone in the parent frame.
14+
"""
15+
def __init__(self, parent, *args, **kw):
16+
17+
# scrollbar on right in parent
18+
yscrollbar = Scrollbar(parent)#, width=15)
19+
yscrollbar.pack(side=RIGHT, fill=Y, expand=False)
20+
21+
# canvas on left in parent
22+
#plain_can_style = Style()
23+
#plain_can_style.configure("plain_canvas.TCanvas", foreground="green", background="red")
24+
self.canvas = Canvas(parent, yscrollcommand=yscrollbar.set, bd=0, highlightthickness=0, relief='ridge', background="#ECECEC")
25+
#self.canvas.config(bg="gray85")
26+
self.canvas.pack(side=LEFT, fill=BOTH, expand=True)
27+
28+
def fill_canvas(event):
29+
"enlarge the windows item to the canvas width"
30+
canvas_width = event.width
31+
self.canvas.itemconfig(self.windows_item, width = canvas_width)
32+
33+
self.canvas.bind('<Configure>', fill_canvas)
34+
35+
yscrollbar.config(command=self.canvas.yview)
36+
37+
#plain_style = Style()
38+
#plain_style.configure("plain_st.TFrame", foreground="black", background="#F0F0F0")
39+
40+
#self.configure(style="plain_style")
41+
42+
# create the scrollable frame and assign it to the windows item of the canvas
43+
Frame.__init__(self, parent, *args, **kw)
44+
self.windows_item = self.canvas.create_window(-1,-1, window=self, anchor=NW)
45+
46+
def update(self):
47+
"""
48+
Update changes to the canvas before the program gets
49+
back the mainloop, then update the scrollregion
50+
"""
51+
self.update_idletasks()
52+
self.canvas.config(scrollregion=self.canvas.bbox(self.windows_item))

iqtgui_modules/__init__.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from . import model_select
2+
from . import partition
3+
from . import ScrollableFrame
4+
from . import iqtree_out
5+
from . import settings
6+
from . import bootstrap_settings
7+
from . import data_types_settings
8+
from . import iqtree_settings
9+
from . import treesearch_settings
10+
from . import modelselect_settings
11+
#from iqtgui_modules.special import consensustree
12+
#from iqtgui_modules.special import robinsonfoulds
13+
#from iqtgui_modules.special import randomtree
14+
from iqtgui_modules import special
15+
from . import alignment
Binary file not shown.
613 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

iqtgui_modules/alignment.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#! /usr/bin/env python
2+
# tkinter Frame for importing multiple alignments
3+
# written by Philipp Resl
4+
from iqtgui_modules import alignment_view
5+
from tkinter import *
6+
from tkinter.ttk import *
7+
8+
class Alignment(Frame):
9+
alignment_id = ""
10+
alignment_path = ""
11+
window = ""
12+
def show_alignment(self):
13+
self.window = Toplevel()
14+
self.al_window = alignment_view.AlignmentView(self.window, alignment=self.alignment_id, filename=self.alignment_path)
15+
self.master.wait_window(self.al_window)
16+
17+
18+
def remove_alignment(self):
19+
#print("Length of alignment list before: %s" % len(self.al_list))
20+
for no in range(0,len(self.al_list)):
21+
self.al_list[no].grid_forget()
22+
23+
del self.al_list[self.alignment_no-1]
24+
#print("Length of alignment list after: %s" % len(self.al_list))
25+
for no in range(0,len(self.al_list)):
26+
#self.al_list[no].grid_forget()
27+
#print("Alignment %s is now %s" % (str(self.al_list[no].alignment_no), str(no+1)))
28+
self.al_list[no].alignment_no = no + 1
29+
self.al_list[no].alignment_label.configure(text="Alignment "+str(no+1)+": ")
30+
self.al_list[no].alignment_label.configure(font=("TkTextFont", 12, "bold"))
31+
self.al_list[no].grid(sticky=W)
32+
self.al_list[no].update()
33+
#kill the alignment window if present, need to find a better way of doing this
34+
if isinstance(self.window,str) == False and Toplevel.winfo_exists(self.window)==1:
35+
self.window.destroy()
36+
self.info_lab.config(text="Alignments: %s Alignment(s) loaded" % str(len(self.al_list)))
37+
38+
self.destroy()
39+
40+
def create_widgets(self):
41+
self.alignment_label = Label(self, text=self.alignment_id)
42+
self.alignment_label.grid(row=0,column=3)
43+
self.alignment_label.configure(font=("TkTextFont", 12, "bold"))
44+
45+
self.alignment_path_label = Label(self, text=self.alignment_path)
46+
self.alignment_path_label.grid(row=0,column=4, sticky=E)
47+
48+
49+
self.view_button = Button(self, text="View", command=self.show_alignment)
50+
self.view_button.grid(row=0,column=1)
51+
52+
self.remove_button = Button(self, text="Remove", command=self.remove_alignment)
53+
self.remove_button.grid(row=0,column=2)
54+
print("Alignment created: %s" % self.alignment_no)
55+
56+
def __init__(self, master, align_id, path, number, alignment_list, info_label):
57+
Frame.__init__(self, master)
58+
self.info_lab = info_label
59+
self.al_list = alignment_list
60+
self.master = master
61+
self.alignment_id = align_id
62+
self.alignment_path = path
63+
self.alignment_no = number
64+
self.create_widgets()

iqtgui_modules/alignment_view.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#! /usr/bin/env python
2+
# tkinter window for settings
3+
# written by Philipp Resl
4+
import os
5+
from tkinter import *
6+
from tkinter.scrolledtext import ScrolledText
7+
from tkinter.ttk import *
8+
9+
10+
#import ttk
11+
#import tkFileDialog, tkMessageBox
12+
13+
class AlignmentView():
14+
def __init__(self, master, alignment, filename):
15+
self.master = master
16+
self.master.title(alignment)
17+
self.master.grid_columnconfigure(0,weight=1)
18+
self.master.grid_rowconfigure(0,weight=1)
19+
#self.master.geometry("500x400")
20+
self.alignment_text = ScrolledText(self.master)
21+
self.alignment_text.grid(row=0,column=0,sticky=N+S+W+E)
22+
file = open(filename, "U")
23+
sequence = ""
24+
for line in file.readlines():
25+
sequence += line
26+
file.close()
27+
self.alignment_text.insert(END, sequence)
28+
29+

iqtgui_modules/bootstrap_settings.py

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#! /usr/bin/env python
2+
# tkinter window for settings
3+
# written by Philipp Resl
4+
import os
5+
from tkinter import *
6+
from tkinter.ttk import *
7+
import tkinter.filedialog, tkinter.messagebox
8+
9+
class AdvancedBSWindow():
10+
wbtvar = 0
11+
wbtlvar = 0
12+
def __init__(self, master, data):
13+
self.master = master
14+
self.master.title("Advanced Bootstrap settings")
15+
self.settings_frame = Frame(self.master)
16+
#create an empty margin so that the widgets wont stick to the very edges
17+
self.settings_frame.rowconfigure(0, minsize=30)
18+
self.settings_frame.rowconfigure(20, minsize=30)
19+
self.settings_frame.columnconfigure(0, minsize=30)
20+
self.settings_frame.columnconfigure(20, minsize=30)
21+
22+
self.description = Label(self.settings_frame,text="Here you can configure advanced options of the\nbootstraping functionality of iqtree", justify=LEFT)
23+
self.description.configure(font="Helvetica 14 bold")
24+
self.description.grid(row=1,column=1, sticky=W, columnspan=5)
25+
26+
self.settings_frame.rowconfigure(2, minsize=20)
27+
28+
self.bcor_label= Label(self.settings_frame,text="Minimum correlation coefficient for UFBoot: ")
29+
self.bcor_label.grid(row=3, column=1, sticky=W)
30+
self.bcor_entry = Entry(self.settings_frame)
31+
self.bcor_entry.insert(END,data.bcor)
32+
self.bcor_entry.grid(row=3, column=2, sticky=W)
33+
34+
self.beps_label= Label(self.settings_frame,text="Epsilon to break tie in RELL: ")
35+
self.beps_label.grid(row=4, column=1, sticky=W)
36+
self.beps_entry = Entry(self.settings_frame)
37+
self.beps_entry.insert(END,data.beps)
38+
self.beps_entry.grid(row=4, column=2, sticky=W)
39+
40+
self.nm_label= Label(self.settings_frame,text="Maximum number of iterations to stop: ")
41+
self.nm_label.grid(row=5, column=1, sticky=W)
42+
self.nm_entry = Entry(self.settings_frame)
43+
self.nm_entry.insert(END,data.nm)
44+
self.nm_entry.grid(row=5, column=2, sticky=W)
45+
46+
self.nstep_label= Label(self.settings_frame,text="Iteration interval to check for\nUFBoot convergence: ")
47+
self.nstep_label.grid(row=6, column=1, sticky=W)
48+
self.nstep_entry = Entry(self.settings_frame)
49+
self.nstep_entry.insert(END,data.nstep)
50+
self.nstep_entry.grid(row=6, column=2, sticky=W)
51+
52+
self.settings_frame.rowconfigure(8, minsize=20)
53+
54+
self.bbnivar = IntVar()
55+
self.bbnivar.set(data.bnni)
56+
57+
def bbni():
58+
self.bbnivar.set(1)
59+
60+
61+
self.bbni = Checkbutton(self.settings_frame, text="reduce model violation (-bnni)", command=bbni, variable=self.bbnivar)
62+
self.bbni.grid(row=9, column=1, sticky=W)
63+
64+
65+
self.wbtvar = IntVar()
66+
self.wbtlvar = IntVar()
67+
68+
self.wbtvar.set(data.wbt)
69+
self.wbtlvar.set(data.wbtl)
70+
71+
def wbt():
72+
if self.wbtlvar.get() == 1:
73+
self.wbtlvar.set(0)
74+
print() #change!!
75+
76+
self.wbt = Checkbutton(self.settings_frame, text="Write bootstrap trees to .ufboot file. (-wbt)", command=wbt, variable=self.wbtvar)
77+
self.wbt.grid(row=10, column=1, sticky=W)
78+
79+
80+
def wbtl():
81+
if self.wbtvar.get() == 1:
82+
self.wbtvar.set(0)
83+
print() #change!!
84+
85+
86+
self.wbtl = Checkbutton(self.settings_frame, text="Write bootstrap trees to .ufboot file\nincluding branch lengths. (-wbtl)", command=wbtl, variable=self.wbtlvar)
87+
self.wbtl.grid(row=11, column=1, sticky=W)
88+
89+
def apply():
90+
try:
91+
data.bnni = self.bbnivar.get()
92+
data.beps = float(self.beps_entry.get())
93+
data.bcor = float(self.bcor_entry.get())
94+
data.nm = int(self.nm_entry.get())
95+
data.nstep = int(self.nstep_entry.get())
96+
data.wbt = self.wbtvar.get()
97+
data.wbtl = self.wbtlvar.get()
98+
self.master.destroy()
99+
100+
except ValueError:
101+
tkinter.messagebox.showinfo("Error", "Some of the entered values are incorrect")
102+
103+
self.apply_button = Button(self.settings_frame, text="Apply & Close", command=apply)
104+
self.apply_button.grid(row=11, column=12, sticky=W)
105+
self.cancel_button = Button(self.settings_frame, text="Cancel", command=self.master.destroy)
106+
self.cancel_button.grid(row=11, column=11, sticky=W)
107+
self.settings_frame.grid()
108+
109+

0 commit comments

Comments
 (0)