def delete_sequence(name, force, verbose): if not read_sequence(name): click.echo(f"Sequence [{name}] does not exist") return elif not force: click.echo( f"Use --force to confirm action. Caution: This operation is not reversible" ) return sequence = remove_sequence(name) pif(verbose, f"Sequence [{name}] removed:\n{', '.join(sequence)}")
def printable_all(categories, transformations, gap, verbose): """ generate printable files with the transformed images """ os.makedirs(os.path.join(ROOT_DIR, *printable_dir), exist_ok=True) for category in categories: for transformation in transformations: # read available level images pif( verbose, f"Generating printable for {category}, {transformation}..." ) generate_pdf(category, transformation, gap, verbose)
def transform_all( categories, transformations, verbose, override, circle, orientation, margin, border): """ Transform images with available transformations. if category is given, transform only the specified categories if transformation is given, transform with only the specified transformations by default, images will be cropped into a circle, can override this behavior with --no-circle if images are cropped, an orientation mark will by default be added, override this behavior with --no-orientation-mark """ post_processors = [] if circle: post_processors.append(crop_to_circle) if orientation: post_processors.append(add_orientation_marker) if margin: post_processors.append( lambda img: add_margin( img, margin_width=margin)) if border: post_processors.append( lambda img: add_border( img, border_width=border)) for category in categories: pif(verbose, f"Processing category {category}...") # generate the unmodified reference image orig = read_orig(category) out_path = os.path.join( ROOT_DIR, *image_dir, category, "output.jpg") write_image( orig, out_path, post_processors=post_processors, override=override, verbose=verbose) for transformation in transformations: pif(verbose, f"Transforming with {transformation}...") transform_image_by_category( category, transformation, post_processors=post_processors, override=override, verbose=verbose)
def new_sequence(name, count, set_name, force, replacement, truncate, verbose): if not force and read_sequence(name): click.echo( f"{name} already exists in sequence data, choose another one or use --force to override" ) return sequence = generate_random_sequence(count, set_name, replacement, truncate) write_sequence(name, sequence) pif( verbose, f"Successfully added new sequence [{name}]: {', '.join(sequence)}")
def rank(agents, categories, transformations, override, verbose): """ Calculate spearmanrank and p-value for each agent specified """ path = os.path.join(ROOT_DIR, *ranked_data_dir) os.makedirs(path, exist_ok=True) file_path = os.path.join(path, "rank.csv") if os.path.isfile(file_path) and not override: pif(verbose, f"file at {file_path} exists, skipping...") return with open(file_path, "w", newline='') as f: rank_standard(f=f, agents=agents, categories=categories, transformations=transformations, override=override, verbose=verbose) pif(verbose, f"data written into {file_path}")
def rank_standard(f, agents, categories, transformations, override, verbose): """ calculate spearman's rank of each category + transformation with each agent. comparisons are made against the standard order as listed in the header of each csv file (0-10), :f: the file to be written into :agents: the agents to be considered :categories: the categories to be considered :transformations: the transformations to be considered :override: override existing files :verbose: print output regarding writing status :returns: None """ writer = csv.writer(f) # The header line writer.writerow( ['agent', 'category', 'transformation', 'coefficient', 'p-value']) for agent in agents: # set up data file path for the agent csv_file = agent2file(agent) if not is_csv(csv_file): pif( verbose, f"{csv_file} does not exist, use the 'decode' command to generate sorted data." ) continue pif(verbose, f"calculating ranks for {agent}...") # read file # the header row and array of data rows header, *sorted_data = read_csv(csv_file) # TODO: split category_transformation into two separate fields # <2020-11-13, David Deng> # for category_transformation, *order in sorted_data: # get the reference order from the header row reference_order = header[1:] category, transformation = category_transformation.split( csv_subfield_delim) # filter category and transformation if categories and category not in categories: pif( verbose, f"Category {category} not specified, skipping {category}, {transformation}..." ) continue if transformations and transformation not in transformations: pif( verbose, f"Transformation {transformation} not specified, skipping {category}, {transformation}..." ) continue r, p = spearmanr(reference_order, order) # calculate spm-rank writer.writerow([ agent, category, transformation, str(numpy.round(r, decimals=3)), str(numpy.round(p, decimals=3)) ])
def generate_pdf(category, transformation, gap, verbose): """generate pdf file with transformed images :category: the category of image :transformation: the transformation to be used :returns: None """ # read available images image_paths = read_level_image_paths(category, transformation) if len(image_paths) == 0: pif(verbose, f"Skip {category}, {transformation}, no level images found") return None # generate pdf pdf = FPDF(orientation="L", unit="pt", format="letter") pdf.set_auto_page_break(False) pdf.set_margins(30, 30, 30) pdf.set_font('Arial', 'B', 20) pdf.add_page() pdf.cell(pdf.w, 30, f"Category: {category}; Transformation: {transformation}", border=0, ln=1, align="C") pdf.set_font('Arial', '', 10) pdf.cell( pdf.w, 30, f"Images to be sorted first from left to right, then from top to bottom. From level_0 to level_10", border=0, ln=1, align="C") lay_images(pdf, image_paths, width=240, space=gap) output_path = os.path.join(ROOT_DIR, *printable_dir, f"{category}_{transformation}.pdf") pdf.output(output_path) pif(verbose, f"File written to {output_path}")
def decode_command(file_names, verbose): for file_name in file_names: input_path = os.path.join(*raw_sorted_data_dir, file_name) output_path = os.path.join(*human_sorted_data_dir, file_name) header_line, *rows = read_csv(input_path) with open(output_path, "w") as output_file: writer = csv.writer(output_file) pif(verbose, f"Decoding {file_name}...") writer.writerow( [header_line[0], *map(seq_num_formatter, range(1, 11))]) for sequence_name, *sequence in rows: try: writer.writerow([ sequence_name, *decode_sequence(sequence_name, sequence) ]) except SequenceError as e: click.echo( f"Sequence Error in {input_path}: {sequence_name}") click.echo(e) pif(verbose, f"Successfully written decoded sequences into {output_path}")
def transform_image_by_category( category, transformation, levels=range(11), extension='jpg', override=True, verbose=True, post_processors=[]): """ transform the image of a certain category :category: the category to be transformed, assumes that it is a valid category :transformation: the transformation to apply :levels: an iterable of integers :extension: the extension of the output file :returns: None """ orig = read_orig(category) for level in levels: out_dir = os.path.join(ROOT_DIR, *image_dir, category, transformation) os.makedirs(out_dir, exist_ok=True) out_path = os.path.join( out_dir, f"level_{level:02}" + os.extsep + extension) # skip image computation if not overriding existing image if os.path.isfile(out_path) and not override: pif(verbose, f"skip image at {out_path}") continue out = transform_image(orig, transformation, level) write_image( out, out_path, post_processors=post_processors, verbose=verbose)
def sort(categories, transformations, metrics, override, verbose): """sort the generated images by comparing them with output.jpg """ os.makedirs(os.path.join(ROOT_DIR, *metric_sorted_data_dir), exist_ok=True) for metric in metrics: pif(verbose, f"Metric: {metric}") # import the metric module mod = importlib.import_module('.'.join([*analysis_dir, metric])) Analyzer = getattr(mod, 'Analyzer', None) if not Analyzer: raise ModuleError( f"no analyzer class implemented in metric {metric}") analyzer = Analyzer() pif(verbose, f"sorting images with {metric}...") # check if file exists path = os.path.join(ROOT_DIR, *metric_sorted_data_dir, f"{metric}.csv") if os.path.isfile(path) and not override: pif(verbose, f"file at {path} exists, skipping...") continue with open(os.path.join(ROOT_DIR, *metric_sorted_data_dir, f"{metric}.csv"), 'w', newline='') as data_file: writer = csv.writer(data_file) # TODO: remove the subfield delimiter <2020-11-17, David Deng> writer.writerow([ csv_subfield_delim.join(['CATEGORY', 'TRANSFORMATION']), *map(seq_num_formatter, range(11)) ]) # header row for category in categories: try: orig = read_output(category) except ModuleError as e: pif(verbose, e) pif(verbose, f"Skipping category {category}...") continue for transformation in transformations: pif( verbose, f"category, transformation: {category},{transformation}..." ) images = read_level_images(category, transformation) if not images: pif( verbose, f"no level images in {category}_{transformation}, skipping..." ) continue images = analyzer.sort(images, orig) # sorted image order = [ seq_num_formatter(get_level_numeric( image.filename)) for image in images ] writer.writerow([ csv_subfield_delim.join([category, transformation]), *order ]) pif(verbose, f"data written to {path}")