''' This plugin takes a csv as input that defines the structure of the classification GUI The CSV should contain one column per dropdowns choice menu The first line of the CSV contains the label of the category and the following lines the possible choice example Tail, Morphology Straight, Gross Bent, Slim Broken, , ''' #@ File (label="CSV file for category and choice", style="extension:csv") csvpath #@ String (label="Browsing mode", choices={"stack", "directory"}) browse_mode from java.awt import Panel, Choice, Label, GridLayout from fiji.util.gui import GenericDialogPlus from QualiAnnotations import CustomDialog import os, csv, codecs class MainDialog(CustomDialog): """ Main annotation dialog for this plugin In this case the panel contains dropdowns """ def __init__(self, title, message, panel, browseMode): """Custom constructor instead of the CustomDialog constructor: does not have the "Add" button""" GenericDialogPlus.__init__(self, title) self.setModalityType(None) # like non-blocking generic dialog self.addMessage(message) self.addPanel(panel) #self.addButton("Add new category", self) # no add new category button for dropdown self.addStringField("Comments", "") self.addButton(CustomDialog.LABEL_ADD, self) self.browseMode = browseMode # important to define it before addDefaultOptions self.addDefaultOptions() #self.addCitation() def fillTable(self, table): '''Read dropdown states and update table''' for dropdown in ( self.getPanel().getComponents()[n:] ): # n first elements are the labels table.addValue( dropdown.getName(), dropdown.getSelectedItem() ) def keyPressed(self, keyEvent): """Define shortcut: pressing any of the + key also adds to the table like the Add button""" code = keyEvent.getKeyCode() if code == keyEvent.VK_ADD or code==keyEvent.VK_PLUS: self.defaultActionSequence() def makeCategoryComponent(self, category): """ Could return a new dropdown, but not implemented """ return None ### Read CSV to get categories and choices csvPath = csvpath.getPath() with open(csvPath, "r") as csvFile: # Check extension (script parameter extension filtering above not functionnal) if csvPath.endswith("csv"): # Guess , or ; separator s = csv.Sniffer() dialect = s.sniff(csvFile.readline()) csvFile.seek(0) # come back to the beginning of the file # Open and parse file csvIterator = csv.reader( codecs.EncodedFile(csvFile, "utf8", "utf_8_sig"), dialect ) # Prevent weird character with utf_8 + BOM, generated by excel mostly when exporting as csv + utf8 elif csvPath.endswith("tsv"): csvIterator = csv.reader( codecs.EncodedFile(csvFile, "utf8", "utf_8_sig"), delimiter="\t" ) else: raise TypeError("Expected a ,-separated or ;-separated (csv) or tab-separated (tsv) file") headers = csvIterator.next() # read first header line n = len(headers) dropdowns = [ [] for i in range(n)] # [[], [], [], [], []] such that dropdowns[i] contains the list of choices for dropdowns i for row in csvIterator: for i, entry in enumerate(row): # row is a list if entry: dropdowns[i].append(entry) # dropdown[i] is the list of choices # if necessary since all columns might not have the same length # Create horizontal panel for dropdowns panel = Panel( GridLayout(0, n) ) # as many columns (n) as menus, as many rows as necessary (0) # First panel row -> dropdown labels for header in headers: panel.add( Label(header) ) # Second panel row -> dropdown choices for i in range(n): label = headers[i] chooser = Choice() chooser.setName(label) # not display but easier to recover infos dropdown = dropdowns[i] for option in dropdown: chooser.add(option) chooser.setFocusable(False) panel.add(chooser) # Initialize classification GUI title = "Qualitative Annotations - multi-classes (dropdown)" message = """Select the descriptors corresponding to the current image, then click 'Add' or press one of the '+' key. To annotate ROI, draw a new ROI or select some ROI(s) from the RoiManager before clicking 'Add'/pressing '+'.""" win = MainDialog(title, message, panel, browse_mode) win.showDialog()