diff --git a/beamtime/electrochemistry/plot.py b/beamtime/electrochemistry/plot.py index ef1efc8..64b7115 100644 --- a/beamtime/electrochemistry/plot.py +++ b/beamtime/electrochemistry/plot.py @@ -275,8 +275,8 @@ def prettify_gc_plot(fig, ax, options=None): # Otherwise apply user input else: - major_xtick = options['yticks'][0] - minor_xtick = options['yticks'][1] + major_ytick = options['yticks'][0] + minor_ytick = options['yticks'][1] # Apply values diff --git a/beamtime/xrd/io.py b/beamtime/xrd/io.py index c5e5966..2afe41c 100644 --- a/beamtime/xrd/io.py +++ b/beamtime/xrd/io.py @@ -90,25 +90,7 @@ def integrate_1d(calibrant, bins, path=None, image=None, options=None): return open_1d_data(filename) -def open_1d_data(path, options=None): - with open(path, 'r') as f: - position = 0 - - current_line = f.readline() - - while current_line[0] == '#': - position = f.tell() - current_line = f.readline() - - f.seek(position) - - df = pd.read_csv(f, header=None, delim_whitespace=True) - - df.columns = ['2th', 'I'] - - - return df @@ -165,7 +147,7 @@ def view_integrator(calibrant): def read_brml(path, options=None): - required_options = ['extract_folder'] + required_options = ['extract_folder', 'save_folder'] default_options = { 'extract_folder': 'temp', 'save_folder': None @@ -240,9 +222,43 @@ def read_brml(path, options=None): return diffractogram +def read_diffractogram(path, options=None): + + with open(path, 'r') as f: + position = 0 + + current_line = f.readline() + + while current_line[0] == '#': + position = f.tell() + current_line = f.readline() + f.seek(position) + + diffractogram = pd.read_csv(f, header=None, delim_whitespace=True) + + diffractogram.columns = ['2th', 'I'] + + + return diffractogram + + +def read_data(path, kind, options=None): + + if kind == 'beamline': + diffractogram = read_diffractogram(path, options=options) + + elif kind == 'recx': + diffractogram = read_brml(path, options=options) + + elif kind == 'image': + diffractogram = get_image_array(path) + + + return diffractogram + diff --git a/beamtime/xrd/plot.py b/beamtime/xrd/plot.py index e37c7b8..79feffa 100644 --- a/beamtime/xrd/plot.py +++ b/beamtime/xrd/plot.py @@ -1,2 +1,327 @@ import matplotlib.pyplot as plt -import numpy +from matplotlib.ticker import (MultipleLocator, FormatStrFormatter,AutoMinorLocator) + +import pandas as pd +import numpy as np +import math + +import beamtime.xrd as xrd + + + + +def plot_diffractogram(path, kind, options=None): + + # Prepare plot, and read and process data + fig, ax = prepare_diffractogram_plot(options=options) + diffractogram = xrd.io.read_data(path=path, kind=kind, options=options) + + + # Update options + required_options = ['x_vals', 'y_vals', 'scatter'] + + + + default_options = { + 'x_vals': '2th', + 'y_vals': 'I', + 'scatter': False + } + + options = update_options(options=options, required_options=required_options, default_options=default_options) + + if options['scatter']: + diffractogram.plot(x=options['x_vals'], y=options['y_vals'], ax=ax, kind='scatter') + + else: + diffractogram.plot(x=options['x_vals'], y=options['y_vals'], ax=ax) + + + + fig, ax = prettify_diffractogram_plot(fig=fig, ax=ax, options=options) + + + return diffractogram, fig, ax + + + +def prepare_diffractogram_plot(options=None): + # First take care of the options for plotting - set any values not specified to the default values + required_options = ['columns', 'width', 'height', 'format', 'dpi', 'facecolor'] + default_options = {'columns': 1, 'width': 14, 'format': 'golden_ratio', 'dpi': None, 'facecolor': 'w'} + + + # Define the required sizes + required_sizes = ['lines', 'axes'] + + + + + # If none are set at all, just pass the default_options + if not options: + options = default_options + options['height'] = options['width'] * (math.sqrt(5) - 1) / 2 + options['figsize'] = (options['width'], options['height']) + + + # Define default sizes + default_sizes = { + 'lines': 3*options['columns'], + 'axes': 3*options['columns'] + } + + # Initialise dictionary if it doesn't exist + if not 'sizes' in options.keys(): + options['sizes'] = {} + + + # Update dictionary with default values where none is supplied + for size in required_sizes: + if size not in options['sizes']: + options['sizes'][size] = default_sizes[size] + + + # If options is passed, go through to fill out the rest. + else: + # Start by setting the width: + if 'width' not in options.keys(): + options['width'] = default_options['width'] + + # Then set height - check options for format. If not given, set the height to the width scaled by the golden ratio - if the format is square, set the same. This should possibly allow for the tweaking of custom ratios later. + if 'height' not in options.keys(): + if 'format' not in options.keys(): + options['height'] = options['width'] * (math.sqrt(5) - 1) / 2 + elif options['format'] == 'square': + options['height'] = options['width'] + + options['figsize'] = (options['width'], options['height']) + + # After height and width are set, go through the rest of the options to make sure that all the required options are filled + for option in required_options: + if option not in options.keys(): + options[option] = default_options[option] + + fig, ax = plt.subplots(figsize=(options['figsize']), dpi=options['dpi'], facecolor=options['facecolor']) + + + plt.rc('lines', linewidth=options['sizes']['lines']) + plt.rc('axes', linewidth=options['sizes']['axes']) + + return fig, ax + +def prettify_diffractogram_plot(fig, ax, options=None): + + ################################################################## + ######################### UPDATE OPTIONS ######################### + ################################################################## + + # Define the required options + required_options = [ + 'columns', + 'xticks', 'yticks', + 'units', + 'show_major_ticks', 'show_minor_ticks', 'show_tick_labels', + 'xlim', 'ylim', + 'hide_x_axis', 'hide_y_axis', + 'positions', + 'xlabel', 'ylabel', + 'sizes', + 'title' + ] + + + # Define the default options + default_options = { + 'columns': 1, + 'xticks': [10, 5], 'yticks': [10000, 5000], + 'units': {'2th': '$^o$', 'I': 'arb. u.'}, + 'show_major_ticks': [True, False, True, False], 'show_minor_ticks': [True, False, True, False], 'show_tick_labels': [True, False, False, False], + 'xlim': None,'ylim': None, + 'hide_x_axis': False, 'hide_y_axis': False, + 'positions': {'xaxis': 'bottom', 'yaxis': 'left'}, + 'xlabel': None, 'ylabel': None, + 'sizes': None, + 'title': None + } + + options = update_options(options, required_options, default_options) + + + + ################################################################## + ########################## DEFINE SIZES ########################## + ################################################################## + + # Define the required sizes + required_sizes = [ + 'labels', + 'legend', + 'title', + 'line', 'axes', + 'tick_labels', + 'major_ticks', 'minor_ticks'] + + + + # Define default sizes + default_sizes = { + 'labels': 30*options['columns'], + 'legend': 30*options['columns'], + 'title': 30*options['columns'], + 'line': 3*options['columns'], + 'axes': 3*options['columns'], + 'tick_labels': 30*options['columns'], + 'major_ticks': 20*options['columns'], + 'minor_ticks': 10*options['columns'] + } + + # Initialise dictionary if it doesn't exist + if not options['sizes']: + options['sizes'] = {} + + + # Update dictionary with default values where none is supplied + for size in required_sizes: + if size not in options['sizes']: + options['sizes'][size] = default_sizes[size] + + + ################################################################## + ########################## AXIS LABELS ########################### + ################################################################## + + + if not options['xlabel']: + options['xlabel'] = prettify_labels(options['x_vals']) + ' [{}]'.format(options['units'][options['x_vals']]) + + else: + options['xlabel'] = options['xlabel'] + ' [{}]'.format(options['units'][options['x_vals']]) + + + if not options['ylabel']: + options['ylabel'] = prettify_labels(options['y_vals']) + ' [{}]'.format(options['units'][options['y_vals']]) + + else: + options['ylabel'] = options['ylabel'] + ' [{}]'.format(options['units'][options['y_vals']]) + + ax.set_xlabel(options['xlabel'], size=options['sizes']['labels']) + ax.set_ylabel(options['ylabel'], size=options['sizes']['labels']) + + ################################################################## + ###################### TICK MARKS & LABELS ####################### + ################################################################## + + ax.tick_params( + direction='in', + which='major', + bottom=options['show_major_ticks'][0], labelbottom=options['show_tick_labels'][0], + left=options['show_major_ticks'][1], labelleft=options['show_tick_labels'][1], + top=options['show_major_ticks'][2], labeltop=options['show_tick_labels'][2], + right=options['show_major_ticks'][3], labelright=options['show_tick_labels'][3], + length=options['sizes']['major_ticks'], + width=options['sizes']['axes']) + + + ax.tick_params(direction='in', which='minor', bottom=options['show_minor_ticks'][0], left=options['show_minor_ticks'][1], top=options['show_minor_ticks'][2], right=options['show_minor_ticks'][3], length=options['sizes']['minor_ticks'], width=options['sizes']['axes']) + + + + if options['positions']['yaxis'] == 'right': + ax.yaxis.set_label_position("right") + ax.yaxis.tick_right() + + + if options['hide_x_axis']: + ax.axes.xaxis.set_visible(False) + + if options['hide_y_axis']: + ax.axes.yaxis.set_visible(False) + + + + # Otherwise apply user input + if options['xticks']: + major_xtick = options['xticks'][0] + minor_xtick = options['xticks'][1] + + + if options['yticks']: + + major_ytick = options['yticks'][0] + minor_ytick = options['yticks'][1] + + + # Apply values + ax.xaxis.set_major_locator(MultipleLocator(major_xtick)) + ax.xaxis.set_minor_locator(MultipleLocator(minor_xtick)) + + ax.yaxis.set_major_locator(MultipleLocator(major_ytick)) + ax.yaxis.set_minor_locator(MultipleLocator(minor_ytick)) + + + + + # SET FONTSIZE OF TICK LABELS + + plt.xticks(fontsize=options['sizes']['tick_labels']) + plt.yticks(fontsize=options['sizes']['tick_labels']) + + ################################################################## + ########################## AXES LIMITS ########################### + ################################################################## + + if options['xlim']: + plt.xlim(options['xlim']) + + if options['ylim']: + plt.ylim(options['ylim']) + + ################################################################## + ############################# TITLE ############################## + ################################################################## + + if options['title']: + ax.set_title(options['title'], size=options['sizes']['title']) + + ################################################################## + ############################# LEGEND ############################# + ################################################################## + + if ax.get_legend(): + ax.get_legend().remove() + + return fig, ax + + + +def prettify_labels(label): + + labels_dict = { + '2th': '2$\\theta$', + 'I': 'Intensity' + } + + return labels_dict[label] + +#def plot_diffractograms(): + + + + +#def plot_heatmap(): + + + + + +def update_options(options, required_options, default_options): + + if not options: + options = default_options + + else: + for option in required_options: + if option not in options.keys(): + options[option] = default_options[option] + + return options \ No newline at end of file