Skip to content

Commit

Permalink
Added functions to save and load selections + explanation in help menu
Browse files Browse the repository at this point in the history
  • Loading branch information
calebweinreb committed Apr 22, 2024
1 parent 651b406 commit 939fec8
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 9 deletions.
2 changes: 1 addition & 1 deletion snub/gui/help/loading_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ To open a SNUB project, go to File > Open Project, navigate to the project direc

## Reload a project

If a project is already open and its files have been modified outside of SNUB, the project can be reloaded in the SNUB GUI by going to File > Reload Project.
If a project is already open and its files have been modified outside of SNUB, the project can be reloaded in the SNUB GUI by going to File > Reload Project.
4 changes: 4 additions & 0 deletions snub/gui/help/selections.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Selections can be used to show relationships between data-views (such intervals
* Use command/control+drag to deselect points and intervals.
* Use Edit > Deselect All to deselect everything

### Saving and loading selections

The start/end times of all currently selected intervals can be saved to an external file using File > Save Selections. The file is in csv format with two columns containing the start and end times respectively. Selections can also be loaded using File > Load Selections. Note that when you load selections from a file, all current selections are cleared.

## Rank variables by enrichment

### Scatter plot
Expand Down
87 changes: 79 additions & 8 deletions snub/gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import sys, os, json
import numpy as np
from functools import partial
from snub.gui.utils import IntervalIndex, CheckBox
from snub.gui.stacks import PanelStack, TrackStack
Expand Down Expand Up @@ -339,12 +340,15 @@ def __init__(self, args):
reload_data.setShortcut("Ctrl+R")
reload_data.triggered.connect(self.reload_data)

save_selection = QAction("Save Selection", self)
save_selection.triggered.connect(self.save_selection)

load_selection = QAction("Load Selection", self)
load_selection.triggered.connect(self.load_selection)

deselect_all = QAction("&Deselect All", self)
deselect_all.triggered.connect(self.deselect_all)

save_layout = QAction("&Layout", self)
save_layout.triggered.connect(self.save_layout)

self.set_layout_to_rows = QAction("&Rows", self)
self.set_layout_to_cols = QAction("&Columns", self)
self.set_layout_to_rows.setCheckable(True)
Expand All @@ -362,6 +366,8 @@ def __init__(self, args):
fileMenu = mainMenu.addMenu("&File")
fileMenu.addAction(open_project)
fileMenu.addAction(reload_data)
fileMenu.addAction(save_selection)
fileMenu.addAction(load_selection)

editMenu = mainMenu.addMenu("&Edit")
editMenu.addAction(deselect_all)
Expand Down Expand Up @@ -401,8 +407,6 @@ def open(self, *args, project_directories=None):
error_directories = []
for project_dir in project_directories:
if len(project_dir) > 0:
# if project_dir.endswith('config.json'):
# project_dir = os.path.dirname(project_dir)
if os.path.exists(os.path.join(project_dir, "config.json")):
self.load_project(project_dir)
else:
Expand All @@ -426,9 +430,6 @@ def reload_data(self):
self.close_tab(current_index)
self.load_project(project_dir)

def save_layout(self):
print("save")

def load_project(self, project_directory):
name = project_directory.strip(os.path.sep).split(os.path.sep)[-1]
project_tab = ProjectTab(project_directory)
Expand Down Expand Up @@ -458,6 +459,76 @@ def getExistingDirectories(self):
str(),
]

def load_selection(self):
current_index = self.tabs.currentIndex()
if current_index == -1:
QMessageBox.warning(self, "Error: No project is open")
return # no tab

# get path of file to load
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
file_name, _ = QFileDialog.getOpenFileName(
self,
"Load Selection",
"",
"All Files (*);;CSV Files (*.csv)",
options=options,
)

print(file_name)

if file_name:
try:
intervals = np.loadtxt(file_name, delimiter=",", skiprows=1)
if len(intervals) > 0:
is_selected = np.ones(len(intervals)) > 0
self.tabs.currentWidget().update_selected_intervals(
intervals, is_selected
)
except Exception as e:
QMessageBox.warning(
self, "Error", f"Failed to load selection: {str(e)}"
)

def save_selection(self):
current_index = self.tabs.currentIndex()
if current_index == -1:
QMessageBox.warning(self, "Error: No project is open")
return # no tab

selected_intervals = self.tabs.currentWidget().selected_intervals.intervals
if len(selected_intervals) == 0:
QMessageBox.warning(self, "Error: Nothing is selected")
return # no tab

# get path of file to save
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
file_name, _ = QFileDialog.getSaveFileName(
self, "Save Selection", "", "CSV Files (*.csv)", options=options
)

if file_name:

if not file_name.lower().endswith(".csv"):
file_name += ".csv"

try:
# generate csv text
text = ["start,end"]
for s, e in selected_intervals:
text.append(f"{s},{e}")
text = "\n".join(text) + "\n"

# write to file
with open(file_name, "w") as file:
file.write(text)
except Exception as e:
QMessageBox.warning(
self, "Error", f"Failed to save selection: {str(e)}"
)


def run():
app = QApplication(sys.argv)
Expand Down

0 comments on commit 939fec8

Please sign in to comment.