#!/usr/bin/env python # # ver : 1.3 || date: Oct 17, 2018 || auth: PA Taylor # + new container/div for centering text box (while left-ifying text) # # ver : 1.4 || date: Oct 19, 2018 # + parse inp opts # # ver : 1.5 || date: Nov 1, 2018 # + check for "subtext" files-- things to be put beneath IMG/TXT/WARN for # extra info. # # ver : 1.5 || date: Nov 20, 2018 # + put in container2 to have gray subtext (differentiate from titles) # + make all subtxt be BOLD # + fixed making the whole image line *not* being a link, while also # having it be centered # #ver = '1.7' ; date = 'Nov 23, 2018' ; auth = 'PA Taylor' # + for each image/section, will now have json files that describe # the contents of the title/text/subtext, etc. # this will allow for easier button definition # + pages get jumped to correctly now # + hyperrefs have abbrevs and links to top of page, where a navigator # menu sits (permanently) # #ver = '1.7' ; date = 'May 17, 2019' # + [PT] simplifying pbar behavior # #ver = '1.8' ; date = 'May 22, 2019' # + [PT] help updates # + [PT] warning level stuff # #ver = '2.3' ; date = 'July 3, 2019' # + [PT] Colorbars standard widths # + [PT] QC block ID now in QC block titles # + [PT] added more help descriptions # #ver = '2.31' ; date = 'July 17, 2019' # + [PT] tiny tweak in departurating message: guard against dreaded # double slash # #ver = '2.4' ; date = 'March 27, 2020' # [PT] remove dependency on lib_apqc_html_helps.py # + dir_img now from lah # #ver = '2.41' ; date = 'Oct 22, 2021' # [PT] better path reporting for the "done" message, hopefully # ver = '2.5' ; date = 'Jan 18, 2022' # [PT] add link buttons # + particular case: mecho QC block, m_tedana link buttons # ######################################################################### import os import sys import glob import json from afnipy import lib_apqc_html as lah from afnipy import lib_apqc_html_css as lahc from afnipy import lib_apqc_tcsh as lat from afnipy import lib_apqc_io as laio # ------------------------------------------------------------------------ ohtml = lat.ohtml # output file, HTML page ocss = lat.dir_info + '/styles.css' # CSS of formats/attributes/etc. ohelp = 'help.html' # output help file, also html oids = lat.dir_info + '/list_ids.txt' # list of jump_to-able IDs tobetable = "IHAVEACUNNINGPLAN!" # string to be replaced later ftypes = [ 'jpg', 'dat', 'txt' ] # types of data to populate HTML page allblocks = lah.qc_blocks.keys() # SHOULD be ordered list of QC blocks MAX_WLEVEL = '' MAX_WLEVEL_RANK = lahc.wlevel_ranks[MAX_WLEVEL] # ========================================================================= if __name__ == "__main__": # parse inputs, and get current dir (to return to at end) iopts = laio.parse_html_args(sys.argv[1:]) my_cwd = os.getcwd() list_links = [] # will hold list of links # move to subj qc dir os.chdir(iopts.qcdir) # get dictionary form of json, title page info to get subj ID fname = lah.dir_img + '/' + lat.page_title_json + '.json' with open( fname, 'r' ) as fff: titlepg_dict = json.load(fff) # output JSON file, for rating/comments. Now includes SUBJ ID in # it, for easier identification oapqcjson = 'apqc_{}.json'.format( titlepg_dict['subj'] ) # make a list of lists: each sublist is either 'blockid' or # 'itemid', and then the id. E.g.: ['blockid', 'regr'], # ['itemid', 'tsnr_vreg'] list_ids = [] # ========================= HTML: start =========================== # ht = """""" # ========================= HTML: style =========================== # # [PT: Jan 14, 2019] Have finally moved CSS attributes to their # own, external CSS file. They grow up soooo fast... ht+= ''' {subj} '''.format( subj=titlepg_dict['subj'], ocss=ocss ) # javascript functions ht+= lah.make_javascript_btn_func( titlepg_dict['subj'] ) # ========================= HTML: title =========================== # # Offset when jumping to div IDs with #id. Value comes from: # navbar height = 70px # border bottom = 3px # padding top = 2px # [other] = 5px PADMARG_VAL = 80 page_title = lah.dir_img + '/' + lat.page_title_json + '.json' # 'AATI' = all APQC title info. AATI = lah.read_title_json(page_title) ht+= ''' {} '''.format( tobetable ) # NB: someday, xstudy can be the task_name, likely from a uvar and # field in page_title_json ht+= lah.wrap_page_title( AATI.title, AATI.subj, xstudy='task_name', vpad=1, blockid=AATI.blockid, padmarg=PADMARG_VAL ) list_links.append( [AATI.blockid, AATI.blockid_hov] ) ht+= ''' ''' # ========================= HTML: body =========================== # ht += ''' ''' # --------------------------------------------------------------------- # ---------------- get images with any associated text ---------------- # --------------------------------------------------------------------- # First, find ALL images and jsons, and then we'll exclude some # because they are supplementary sub-images and not independent # ones (like the *.cor.*, *.sag.* and *pbar* ones) DID_START_QC_BLOCKS = False list_allglob = [] for ff in ftypes: list_allglob += glob.glob(lah.dir_img + '/*.' + ff) list_jsonglob = glob.glob(lah.dir_img + '/*.json') #print(list_allglob) #print(list_jsonglob) # we don't want the 'cor' ones, for space considerations; # and now, we don't want the colorbars *here*, either-- will # read those in based on the names of *axi.jpg. list_use = [] for x in list_allglob: if not(x.__contains__('.cor.jpg') or x.__contains__('.pbar.jpg')) : list_use.append(x) list_use.sort() #print(list_use) # for each QC block for qcb in allblocks: # find the QC items that belong to it, by parsing names list_qci = [] for img in list_use: if img.__contains__('_' + qcb + '_') : list_qci.append(img) Nqui = len(list_qci) # loop through any for ii in range(Nqui): img = list_qci[ii] # get extension of file, must be one of ftypes (how # could it not be??) img_ext = img.split('.')[-1] img_json = img.replace(img_ext, 'json') # 'AAII' = 'all APQC item info' # initialize empty, may not need/use AAII = lah.apqc_item_info() if list_jsonglob.__contains__(img_json) : AAII = lah.read_descrip_json(img_json) # 1) Try to get title+text+blockid, only for first one in # list if AAII.title and not(ii): if DID_START_QC_BLOCKS : dcpd = True else: dcpd = False ht+= lah.wrap_block_title( AAII.title, vpad=1, addclass=" class='padtop' ", blockid=AAII.blockid, padmarg=PADMARG_VAL, do_close_prev_div=dcpd ) list_links.append( [AAII.blockid, AAII.blockid_hov] ) DID_START_QC_BLOCKS = True list_ids.append( ['blockid', AAII.blockid] ) list_ids.append( ['itemid', AAII.itemid] ) # 2) Try to add text above it if AAII.text : ht+= lah.wrap_block_text( AAII.text, addclass="class='container' ", itemid=AAII.itemid, padmarg=PADMARG_VAL, vpad=1 ) if AAII.itemid != list_ids[-1][1] : list_ids.append( ['itemid', AAII.itemid] ) # 3) Try to add image or dat if AAII.itemtype == '1D': # put a border around this type ht+=lah.wrap_img( img, vpad=True, addclass=" class='bordered' " ) elif AAII.itemtype == 'VOL': # decide when to put AV/NV buttons (or not) if AAII.text and AAII.itemid != 'olap' : add_nvbtn = True else: add_nvbtn = False ht+=lah.wrap_img( img, itemid=AAII.itemid, vpad=True, add_nvbtn=add_nvbtn, av_file=AAII.av_file, ic_file=AAII.ic_file, ic_args=AAII.ic_args, gv_file=AAII.gv_file, gv_args=AAII.gv_args ) if AAII.nv_html : fname = lah.dir_img + '/' + AAII.nv_html ht+= lah.wrap_nv_html(fname) if AAII.itemid != list_ids[-1][1] : list_ids.append( ['itemid', AAII.itemid] ) elif AAII.itemtype == 'WARN': ht+=lah.wrap_dat( lah.read_dat(img), addclass=" class='warnbord' ", warn_level = AAII.warn_level, remove_top_empty = True) if lahc.wlevel_ranks[AAII.warn_level] > MAX_WLEVEL_RANK : MAX_WLEVEL = AAII.warn_level MAX_WLEVEL_RANK = lahc.wlevel_ranks[MAX_WLEVEL] if AAII.itemid != list_ids[-1][1] : list_ids.append( ['itemid', AAII.itemid] ) elif AAII.itemtype == 'DAT': ht+=lah.wrap_dat( lah.read_dat(img), addclass=" class='datbord' ") if AAII.itemid != list_ids[-1][1] : list_ids.append( ['itemid', AAII.itemid] ) elif AAII.itemtype == 'BUTTON': ht+=lah.wrap_button( lah.read_dat(img), button_type=AAII.itemid ) # 4) Add in any 'subtext' if AAII.subtext : ht+= lah.wrap_block_text( AAII.subtext, addclass=" class='container2' ", dobold=True, vpad=2 ) # --------------------------------------------------------------------- # -------------- put the nav link table in ------------------ # --------------------------------------------------------------------- # close final section div ht+= ''' ''' list_links.append( lah.qc_link_final ) txt_for_navtable = lah.make_nav_table(list_links, subj=AATI.subj, max_wlevel = MAX_WLEVEL) ht = ht.replace(tobetable, txt_for_navtable) # -------------- done: wrap up and close body text ------------------ ht+=''' ''' # ------------- write to file ---------------- # main index.html output file fff = open(ohtml, 'w') fff.write(ht) fff.close() # write the external style file for the HTML files lahc.write_css_file( ocss ) # at least here, the JSON has indentation lah.write_json_file(list_links, oapqcjson) # output help html file; reuse same external CSS file lah.write_help_html_file( ohelp, ocss ) # output list of IDs to a text file, to display lah.write_list_ids_file( oids, list_ids ) # silly check, so no doubling of slash in path (not harmful, but # annoyingly unaesthetic) path_qcdir = iopts.qcdir if path_qcdir[-1] == '/' : path_qcdir = iopts.qcdir[:-1] # [PT: Oct 22, 2021] update the 'done' message path, because the # originally-reported relative path is often not useful. here, # get abs path to current dir, which should be QC_*/, because of # os.chdir(..) above pwd_res = os.getcwd() qcfile_abs = pwd_res + '/' + ohtml bye_msg = """ ++ Done! Wrote QC HTML. To view, run either this (without server): afni_open -b {qcfile_abs} ... or this (with server): open_apqc.py -infiles {qcfile_abs} """.format(qcfile_abs=qcfile_abs) print(bye_msg) os.chdir(my_cwd) # exit, pursued by a bear sys.exit(0)