<jupyter_start><jupyter_text>Data Support<jupyter_code>fan_smoothing_window = 60  # time width of smoothing wndow

def load_df(df_name):
    df = pd.read_csv(
        df_name,
        usecols=[0, 1, 2, 3, 4, 5, 6]
    )
    df.rename(index=str, columns={  # remove units for easier indexing
        'Time (s)': 'Time',
        'Temperature': 'Thermistor',
        'Error (deg C)': 'Error',
        'Setpoint Reached': 'Reached'
    }, inplace=True)
    df.dropna(how='all', inplace=True)
    df.index = pd.to_timedelta(df['Time'], unit='s')  # set index to units of seconds
    df.Time = df.Time / 60  # set Time to units of minutes
    return df

def smooth_fan(df):
    df['FanSmooth'] = df.Fan.rolling(fan_smoothing_window, win_type='hamming').mean()<jupyter_output><empty_output><jupyter_text>Plotting Support<jupyter_code>figure_width = 17.5
figure_temps_height = 4
figure_complete_height = 7.5
figure_complete_height_ratio = (3, 2)
box_width_shrink_factor = 0.875  # to fit the figure legend on the right
ylabel_position = -0.08

min_temp = 20
max_temp = 100

legend_location = 'center right'

reached_color = 'gainsboro'  # light gray
setpoint_color = 'tab:green'
thermistor_color = 'tab:orange'
fan_color = 'tab:blue'
heater_color = 'tab:red'
def fig_temps(title):
    (fig, ax_temp) = plt.subplots(
        figsize=(figure_width, figure_temps_height)
    )
    ax_temp.set_title(title)
    return (fig, ax_temp)

def fig_complete(title):
    (fig, (ax_temp, ax_duties)) = plt.subplots(
        nrows=2, sharex=True,
        gridspec_kw={
            'height_ratios': figure_complete_height_ratio
        },
        figsize=(figure_width, figure_complete_height)
    )
    ax_temp.set_title(title)
    return (fig, (ax_temp, ax_duties))

def plot_setpoint_reached(df, ax, label=True):
    legend_label = 'Reached\nSetpoint'
    if not label:
        legend_label = '_' + legend_label  # hide the label from the legend
    
    (groups, _) = ndi.label(df.Reached.values.tolist())
    df = pd.DataFrame({
        'Time': df.Time,
        'ReachedGroup': groups
    })
    result = (
        df
        .loc[df.ReachedGroup != 0]
        .groupby('ReachedGroup')['Time']
        .agg(['first', 'last'])
    )
    for (i, (group_start, group_end)) in enumerate(result.values.tolist()):
        ax.axvspan(group_start, group_end, facecolor=reached_color, label=legend_label)
        if i == 0:
            legend_label = '_' + legend_label  # hide subsequent labels from the legend
    

def plot_temps(df, ax, label_x=True):
    ax.plot(df.Time, df.Setpoint, color=setpoint_color, label='Setpoint')
    ax.plot(df.Time, df.Thermistor, color=thermistor_color, label='Thermistor')
    
    ax.set_xlim([df.Time[0], df.Time[-1]])
    ax.set_ylim([min_temp, max_temp])
    
    if label_x:
        ax.set_xlabel('Time (min)')
    ax.set_ylabel('Temperature\n(°C)')
    
def plot_efforts(df, ax):
    ax.plot(df.Time, df.FanSmooth, color=fan_color, label='Fan')
    ax.plot(df.Time, df.Heater, color=heater_color, label='Heater')
    
    ax.set_xlabel('Time (min)')
    ax.set_ylabel('Duty\nCycle')

def shrink_ax_width(ax, shrink_factor):
    box = ax.get_position()
    ax.set_position([box.x0, box.y0, box.width * shrink_factor, box.height])

def fig_plot_complete(df, title):
    (fig, (ax_temp, ax_duties)) = fig_complete(title)
    
    plot_setpoint_reached(df, ax_temp)
    plot_temps(df, ax_temp, label_x=False)
    ax_temp.yaxis.set_label_coords(ylabel_position, 0.5)
    shrink_ax_width(ax_temp, box_width_shrink_factor)
    
    plot_setpoint_reached(df, ax_duties, label=False)
    plot_efforts(df, ax_duties)
    ax_duties.yaxis.set_label_coords(ylabel_position, 0.5)
    shrink_ax_width(ax_duties, box_width_shrink_factor)
    
    fig.legend(loc=legend_location)

def fig_plot_temps(df, title):
    (fig, ax_temp) = fig_temps(title)
    
    plot_setpoint_reached(df, ax_temp)
    plot_temps(df, ax_temp)
    ax_temp.yaxis.set_label_coords(ylabel_position, 0.5)
    shrink_ax_width(ax_temp, box_width_shrink_factor)
    
    fig.legend(loc=legend_location)<jupyter_output><empty_output><jupyter_text>Stepwise Sequence<jupyter_code>df_stepwise = load_df('20190117 Thermal Subsystem Testing Data - Fifth Test.csv')
smooth_fan(df_stepwise)
df_stepwise
fig_plot_temps(df_stepwise, 'Stepwise Adjustment Control Sequence')
plt.savefig('stepwise_control.pdf', format='pdf')
plt.savefig('stepwise_control.png', format='png')
fig_plot_complete(df_stepwise, 'Stepwise Control Sequence')<jupyter_output><empty_output><jupyter_text>Lysis Sequence<jupyter_code>df_lysis = load_df('20190117 Thermal Subsystem Testing Data - Fourth Test.csv')
smooth_fan(df_lysis)
df_lysis
fig_plot_temps(df_lysis, 'Thermal Lysis Control Sequence')
fig_plot_complete(df_lysis, 'Thermal Lysis Control Sequence')
plt.savefig('thermal_lysis.pdf', format='pdf')
plt.savefig('thermal_lysis.png', format='png')<jupyter_output>'HelveticaNeueLTStd_Md.otf' can not be subsetted into a Type 3 font. The entire font will be embedded in the output.
'HelveticaNeueLTStd_Roman.otf' can not be subsetted into a Type 3 font. The entire font will be embedded in the output.
'HelveticaNeueLTStd_Md.otf' can not be subsetted into a Type 3 font. The entire font will be embedded in the output.
'HelveticaNeueLTStd_Roman.otf' can not be subsetted into a Type 3 font. The entire font will be embedded in the output.
{'fraction_non_alphanumeric': 0.11846754695927098, 'fraction_numerical': 0.011902547889157523, 'mean_word_length': 4.211240310077519, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '668339', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2084, 'n_tokens_neox': 1976, 'n_words': 397, 'path': 'results/Temperature Control Plots.ipynb', 'repo_name': 'ethanjli/punchcard-microfluidics', 'size': '5377'}