<jupyter_start><jupyter_text>Born to slide: mobile origin licensing factors confer resistance to transcription conflicts Jupyter notebooks  Figures:+ 5I+ 5J+ 5L+ S5K+ S5L+ S5M+ S5N Archives:+ Transcription_ORC-DNA_ATP.yama+ Transcription_ORC-DNA_ATP_stuck-ORC.yama+ Transcription_ORC-DNA_T7T_ATP.yama+ Transcription_ORC-DNA_T7T_ATP_stuck-ORC.yama+ Transcription_naked-DNA_ATP_LD555.yama+ Transcription_naked-DNA_ATP_LD655.yama+ Transcription_naked-DNA_ATP_AF488.yama+ Transcription_naked-DNA_T7T_ATP.yama Additional data:+ none  Initialize ImageJ<jupyter_code>import imagej
ij = imagej.init('/Applications/Fiji.app')
ij.getVersion()<jupyter_output><empty_output><jupyter_text>Imports<jupyter_code>import sys
sys.path.insert(0, '..')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import re
import awesome_data
from marspy.convert.archive import DnaMoleculeArchive, SingleMoleculeArchive, instantiate_archive, describe_archives
from scipy.stats import norm
from tqdm.notebook import tqdm
from functools import reduce
from collections import Counter<jupyter_output>marspy initialized.<jupyter_text>Select archives<jupyter_code>selected_archives = ['Transcription_ORC-DNA_ATP.yama',
                     'Transcription_ORC-DNA_ATP_stuck-ORC.yama',
                     'Transcription_ORC-DNA_T7T_ATP.yama',
                     'Transcription_ORC-DNA_T7T_ATP_stuck-ORC.yama',
                     'Transcription_naked-DNA_ATP_LD555.yama',
                     'Transcription_naked-DNA_ATP_LD655.yama',
                     'Transcription_naked-DNA_ATP_AF488.yama',
                     'Transcription_naked-DNA_T7T_ATP.yama']<jupyter_output><empty_output><jupyter_text>Figure style and output directory<jupyter_code>from figure_style import *
set_style_paper()
dir_out = '/Volumes/pool-duderstadt/Matthias/Manuscript/Figures/SVGs/Figure5/'
dir_out<jupyter_output><empty_output><jupyter_text>Instantiate selected archives<jupyter_code>for archive in tqdm(selected_archives):
    instantiate_archive(archive, awesome_data.datasets)<jupyter_output><empty_output><jupyter_text>Archives Overview<jupyter_code>describe_archives(DnaMoleculeArchive.instances)<jupyter_output><empty_output><jupyter_text>Load segment tables, apply filter & detect pauses<jupyter_code>for index,archive in enumerate(tqdm(DnaMoleculeArchive.instances)):
    
    archive.add_segments_tables()
    archive.filter_segments(b_min=-10, sigma_b_max=10)
    archive.detect_pauses()<jupyter_output><empty_output><jupyter_text>Generate main df<jupyter_code>def setup_pandas_df(archive_instances):
    '''
    Sets up a multilevel df with all relevant information
    '''
    
    # indices will be UIDs
    prefixes = set()
    for archive in archive_instances:
        prefixes.update(archive.prefixes)
    col_1 = sorted(list(prefixes))
    #inside
    col_2 = ['initial_intensity', 'lifetime', 'start_site', 'stop_site', 'number_pauses']
    col_3 = ['']
    hier_index = pd.MultiIndex.from_product([col_1,col_2,col_3],names=['molecule','properties','properties_details'])

    return pd.DataFrame(columns=hier_index)
    
df = setup_pandas_df(DnaMoleculeArchive.instances)

# sort MultiIndexCols for performance
df.sort_index(axis=1, inplace=True)
df.head()

# fill dataframe
for archive in tqdm(DnaMoleculeArchive.instances):

    for molecule in archive.molecules:
        #print('handling molecule '+molecule.uid)
        # general columns first
        df.loc[molecule.uid,'dna_length'] = molecule.calc_length_dna()
        df.loc[molecule.uid,'dna_count_valid'] = archive.dna_count_valid
        df.loc[molecule.uid,'hs_wash'] = archive.highsalt_wash
        df.loc[molecule.uid,'nucleotide'] = archive.nucleotide
        df.loc[molecule.uid,'t7_terminator'] = archive.t7_terminator
        df.loc[molecule.uid,'tags'] = reduce(lambda tag1,tag2: tag1+','+tag2, molecule.tags)

        # general proteins
        for protein in molecule.proteins:
            #store protein number
            df.loc[molecule.uid,'number_'+protein] = molecule.params['Number_'+protein]
            #assign label for each protein
            df.loc[molecule.uid,'label_'+protein] = archive.labels[protein]
            
            # burst velocity (weighted average, exclude pauses, all regions)
            # always calculate weighted average for all seg_dfs of a protein
            # check if protein has a SegmentsTable, otherwise skip
            if len(list(filter(lambda seg_df: protein in seg_df.prefix, molecule.seg_dfs))) > 0:
                df.loc[molecule.uid,('velocity_'+protein)] = \
                np.average([seg_df.calc_rate()[0] for seg_df in list(filter(lambda seg_df: protein in seg_df.prefix, molecule.seg_dfs))],
                           weights=[seg_df.calc_rate()[1] for seg_df in list(filter(lambda seg_df: protein in seg_df.prefix, molecule.seg_dfs))])
        
        # every specific protein
        for prefix in molecule.prefixes:

            #take mean intensity from first 5 frames (maybe need try block later if shorter traces)
            df.loc[molecule.uid,(prefix,'initial_intensity')] = molecule.df.iloc[:5][prefix+'Intensity'].mean()

            #lifetime (in frames) defined on tracking length
            df.loc[molecule.uid,(prefix,'lifetime')] = len(molecule.df[prefix+'y'].dropna())
            
            #start & stop site
            if re.match('T7',prefix):
                df.loc[molecule.uid,(prefix,'start_site')] = molecule.df[prefix+'Position_on_DNA'].min()
                df.loc[molecule.uid,(prefix,'stop_site')] = molecule.df[prefix+'Position_on_DNA'].max()
            else:
                df.loc[molecule.uid,(prefix,'start_site')] = molecule.df.iloc[:5][prefix+'Position_on_DNA'].mean()
                df.loc[molecule.uid,(prefix,'stop_site')] = molecule.df[prefix+'Position_on_DNA'].max()
            
            #pauses:
            #number of pauses
            #- do not consider first segment (transcription stalling before UTP arrival)
            #- do not consider pauses above 19 kb on DNA (exclude diffraction limit towards end of DNA = 1.5-2kb)
            #- do not consider pauses with less than 20 seconds (x2-x1)
            
            #note: following is split up in multiple lines to avoid long arguments and reusage
            #save as temporal variable (already exclude exclude first segment of each segment table (index 0 stays in concatenated))
            # check if protein prefix has a SegmentsTable, otherwise skip
            if len(list(filter(lambda seg_df: prefix == seg_df.prefix, molecule.seg_dfs))) > 0:
                _seg_df = pd.concat([seg_df.df for seg_df in list(filter(lambda seg_df: prefix == seg_df.prefix, molecule.seg_dfs))]).drop(0,axis=0)
                # reset index for proper loops by index later
                _seg_df.reset_index(drop=True, inplace=True)
                # filter df based on pause definition (keep all segments which are not a pause for recovery)
                _seg_df = _seg_df[(_seg_df['x2'] - _seg_df['x1'] >= 20) & 
                                  (_seg_df['y2'] < 19000) & (_seg_df['y1'] < 19000) | 
                                  (_seg_df['pause_B'] == False)]
                             
            
                df.loc[molecule.uid,(prefix,'number_pauses')] = _seg_df['pause_B'].sum()
            
                #loop through filtered _seg_df to get pause details:
                pause_counter = 0
                for row in _seg_df.index:
                    #do we have a pause segment?
                    if _seg_df.loc[row,'pause_B']:
                        pause_counter+=1

                        # pause duration (endtime - starttime: x2-x1)
                        df.loc[molecule.uid,(prefix,'pause_'+str(pause_counter),'duration')] = \
                        _seg_df.loc[row,'x2'] - _seg_df.loc[row,'x1']

                        # pause position on dna (mean of start and end: y2-y1)
                        df.loc[molecule.uid,(prefix,'pause_'+str(pause_counter),'position_on_dna')] = \
                        (_seg_df.loc[row,'y2'] + _seg_df.loc[row,'y1']) / 2

                        # does it recover from pause (=> is it the last segment)
                        # note: concatenated df is perfect because subsequent region can show pause recovery
                        df.loc[molecule.uid,(prefix,'pause_'+str(pause_counter),'recovery')] = \
                        row != _seg_df.index.max()

                # sanity check between pause_counter and earlier detected pauses
                # [0] necessary because of multi-index. use .xs() alternatively
                if pause_counter != df.loc[molecule.uid,(prefix,'number_pauses')][0]:
                    print(f"Attention! Problem with pause detection in molecule {molecule.uid}.")           

# fill all NaN values in number_protein with 0
proteins = set()
for archive in DnaMoleculeArchive.instances:
    proteins.update(archive.proteins)

for protein in proteins:
    df['number_'+protein] = df['number_'+protein].apply(lambda value: 0 if np.isnan(value) else value)
                    
# convert tags back to list
df['tags'] = df['tags'].apply(lambda tags: tags.split(','))

# again sort MultiIndexCols for performance
df.sort_index(axis=1, inplace=True)

# fix data types
df = df.infer_objects()

df.head()<jupyter_output><empty_output><jupyter_text>Figures   Figure 5I: Collision outcomes RNAP-ORC*Note*: only consider archives with valid DNA count<jupyter_code>colls = list()

for archive in filter(lambda archive: archive.dna_count_valid, DnaMoleculeArchive.instances):
    for molecule in archive.molecules:
        for tag in filter(lambda tag: 'coll_T7_1_ORC_' in tag, molecule.tags):
            colls.append(tag.split('_')[-1])

df_coll = pd.DataFrame(index=['outcome'],data=([Counter(colls)])).T
#df_coll.columns.names = ['hs_challenge']
df_coll
df_coll = df_coll.reindex(['push', 'bypass','pause', 'stall', 'T7eject','ORCeject','T7eject-ORCeject'])
df_coll
#plot a stacked barplot
fig,axes = plt.subplots(figsize=(4,0.5))

(df_coll/df_coll.sum()).T.plot(kind='barh',stacked=True,ax=axes,rot=0,edgecolor='.15',
                               color=[palettes['qualitative'][0],palettes['qualitative'][4],
                                      palettes['qualitative'][5],palettes['qualitative'][1],
                                      palettes['qualitative'][2],palettes['qualitative'][3],
                                      palettes['qualitative'][6]])

axes.set_xlabel("Probability")

#axes.set_title("Fate upon T7RNAP-MCM collision")
axes.set_xlim([0,1.05])
axes.set_yticks([])

labels = [int(df_coll.sum()[col]) for col in df_coll.columns]

#calculate y offset to label bars on top

rects = axes.patches
counter = 0
for rect, label in zip(rects, labels):
    axes.text(1.05, rect.get_y() + rect.get_height()/2, s=f'n = {label}', ha='left', va='center')
    counter+=1
axes.legend(ncol=len(df.index),bbox_to_anchor=[-0.3, 1], loc='center left',frameon=False)

#tidy up
#fig.tight_layout()
sns.despine(trim=True,left=True)

#save
plt.savefig(dir_out+'5I_ORC_collision_fate.svg',transparent=True)<jupyter_output><empty_output><jupyter_text>Figure 5J: Transcription rate +/- ORC<jupyter_code>df_push = pd.DataFrame(columns=['initial_intensity','velocity'])

# loop through all archives with nucleotide ATPgS (just sanity check, only "ATPgS archives selected")
for archive in filter(lambda archive: archive.nucleotide == 'ATP',DnaMoleculeArchive.instances):

    # loop through all molecules
    for molecule in archive.molecules:
        #print('processing molecule:', molecule.uid)
        valid = True
        
        for protein, number in molecule.proteins.items():
            # make sure molecule only contains MCM & T7 
            if (number > 0 and protein not in {'T7', 'ORC'}):
                valid = False
                continue
            # more than 1 T7 or ORC (just a sanity check, shouldn't happen)
            elif number > 1:
                valid = False
                continue
                
        # loop through all seg_dfs with T7 in prefix
        if valid:
            for seg_df in filter(lambda seg_df: 'T7' in seg_df.prefix, molecule.seg_dfs):
                # get the rate
                velocity = seg_df.calc_rate()[0]

                # get intensity_MCM
                intensity = 0
                # add intensities for all pushed MCMs
                for i in range(1,seg_df.pushed_proteins['ORC']+1):
                    intensity += molecule.df.iloc[:5]['ORC_'+str(i)+'_Intensity'].mean()

                _temp_df = pd.DataFrame(data=[[intensity,velocity]],
                                        columns=['initial_intensity','velocity'])
                df_push = pd.concat([df_push,_temp_df])
                
                
df_push = df_push.convert_dtypes()
df_push = df_push.dropna()
df_push
# 1 ORC has around 35000 intensity
def estimate_bleaching(intensity):
    if intensity == 0:
        return 0
    else:
        return 1
df_push['number_ORC'] = df_push['initial_intensity'].apply(estimate_bleaching)
df_push
# Observed rates +/- ORC
protein = 'ORC'
fig,axes = plt.subplots(figsize=(1.2, 2))

sns.boxplot(x='number_ORC',y='velocity',data=df_push,order=sorted(df_push['number_ORC'].unique()),
            palette=palettes[protein][::2],fliersize=0)


#calculate number of observations
nobs = df_push['number_ORC'].value_counts().sort_index()
nobs = [str(x) for x in nobs.tolist()]
nobs = ["n = " + i for i in nobs]

#put nobs into plot

pos = range(len(nobs))

for tick,label in zip(pos,axes.get_xticklabels()):
    axes.text(pos[tick], 95, nobs[tick],
    horizontalalignment='center',verticalalignment='bottom')

rates = []
# fit data to normal distribution and print on plot
for num_orc in sorted(df_push['number_ORC'].unique()):
    mu, std = norm.fit(df_push[df_push['number_ORC']==num_orc]['velocity'])
    rates.append(f'{round(mu,1)}\n+ {round(std,1)}')
    
for tick,label in zip(pos,axes.get_xticklabels()):
    axes.text(pos[tick], 75, rates[tick],
    horizontalalignment='center',verticalalignment='bottom')

axes.set_xticklabels(['No','Yes'])
axes.set_ylim(0,100)
axes.set_xlabel('ORC pushed?')
axes.set_ylabel('Transcription rate (nt/s)')

# axes.set_title('T7 RNAP can push trains of MCM DHs')

sns.despine()
# plt.tight_layout()

plt.savefig(dir_out+'5J_Transcription_rates_ORC.svg',transparent=True)<jupyter_output><empty_output><jupyter_text>Figure 5L: ORC variance analysis*Note*: only consider collisions in presence of ORC and archives with valid DNA count<jupyter_code># collect values
# pushed ORCs
var_push_x = list()
var_push_y = list()
# bypassed ORCs
var_bypass_x = list()
var_bypass_y = list()
# stuck ORCs
var_stuck_x = list()
var_stuck_y = list()

# pushed & bypassed
for archive in DnaMoleculeArchive.instances:

    var_push_x.extend([molecule.params['ORC_1_x_Variance'] 
                       for molecule in filter(lambda molecule:('coll_T7_1_ORC_1_push' in molecule.tags 
                                                               or 'coloc_T7_1_ORC_1_push' in molecule.tags) 
                                              and molecule.params['ORC_1_x_Variance'] < 0.6,archive.molecules)])
    var_push_y.extend([molecule.params['ORC_1_y_Variance'] 
                       for molecule in filter(lambda molecule:('coll_T7_1_ORC_1_push' in molecule.tags 
                                                               or 'coloc_T7_1_ORC_1_push' in molecule.tags) 
                                              and molecule.params['ORC_1_x_Variance'] < 0.6,archive.molecules)])

    var_bypass_x.extend([molecule.params['ORC_1_x_Variance'] 
                         for molecule in filter(lambda molecule:('coll_T7_1_ORC_1_bypass' in molecule.tags 
                                                               or 'coloc_T7_1_ORC_1_bypass' in molecule.tags) 
                                              ,archive.molecules)])
    var_bypass_y.extend([molecule.params['ORC_1_y_Variance'] 
                         for molecule in filter(lambda molecule:('coll_T7_1_ORC_1_bypass' in molecule.tags 
                                                               or 'coloc_T7_1_ORC_1_bypass' in molecule.tags) 
                                              ,archive.molecules)])
    
# stuck
for archive in SingleMoleculeArchive.instances:
    
    var_stuck_x.extend([molecule.params['x_Variance'] 
                        for molecule in filter(lambda molecule: 'accept' in molecule.tags,archive.molecules)])
    var_stuck_y.extend([molecule.params['y_Variance'] 
                        for molecule in filter(lambda molecule: 'accept' in molecule.tags,archive.molecules)])
from scipy import stats
# actual values (mean +/- SEM)
print(f"pushed ORC: {round(np.mean(var_push_x),3)} +/- {round(stats.sem(var_push_x),3)} px2")
print(f"bypassed ORC: {round(np.mean(var_bypass_x),3)} +/- {round(stats.sem(var_bypass_x),3)} px2")
print(f"stuck ORC: {round(np.mean(var_stuck_x),3)} +/- {round(stats.sem(var_stuck_x),3)} px2")
# x Variance (perpendicular to flow) of ORC molecules pushed vs bypassed => bypassed molecules are probably NOT stuck
fig,axes = plt.subplots(figsize=(2,2))

sns.distplot(var_push_x,bins = np.linspace(0, 0.5, 21),kde=False,ax=axes,color=palettes['qualitative'][0], hist_kws={"alpha": 0.75},
             label=f"pushed (n = {len(var_push_x)})")
sns.distplot(var_bypass_x,bins = np.linspace(0, 0.5, 21),kde=False,ax=axes,color=palettes['qualitative'][4], hist_kws={"alpha": 0.75},
             label=f"bypassed (n = {len(var_bypass_x)})")
sns.distplot(var_stuck_x,bins = np.linspace(0, 0.5, 21),kde=False,ax=axes,color=palettes['qualitative'][7], hist_kws={"alpha": 0.75},
             label=f"stuck (n = {len(var_stuck_x)})")
axes.legend(loc=1,frameon=False)
axes.set_xlim(-0.025,0.4)
axes.set_ylim(0,70)
axes.set_xlabel('ORC variance x (px2)')
axes.set_ylabel('Number of occurrences')
# axes.set_title('x variance of pushed, bypassed and stuck ORC')

sns.despine()
#plt.tight_layout()

# save
plt.savefig(dir_out+'5L_Variance_ORC_populations.svg',transparent=True)<jupyter_output><empty_output><jupyter_text>Figure S5K: RNAP pushes ORC over long distances*Note*: only consider DNA w/o T7T<jupyter_code>protein = 'ORC'
# only consider molecules with 1 MCM foci being pushed
tag_filter = 'ORC_1_push'

_plot_df = (df[(~df['t7_terminator']) & (df['number_ORC'] == 1) & (df['tags'].apply(
    lambda tags: True if re.search(tag_filter,' '.join(tags)) else False))].filter(regex=(protein+"_"),axis=1))

fig,axes = plt.subplots()

sns.distplot((_plot_df.xs('stop_site',level='properties',axis=1) -
              _plot_df.xs('start_site',level='properties',axis=1))/1000,ax=axes, 
             color=sns.desaturate(palettes[protein][1],0.75), bins = np.linspace(0, 25, 51), kde=False, hist_kws={'alpha':1})
# mean+/- sem
mean_distance = pd.melt((_plot_df.xs('stop_site',level='properties',axis=1) - 
                         _plot_df.xs('start_site',level='properties',axis=1))/1000)['value'].mean()
sem_distance = pd.melt((_plot_df.xs('stop_site',level='properties',axis=1) - 
                         _plot_df.xs('start_site',level='properties',axis=1))/1000)['value'].sem()
axes.text(0.05, 0.8, f"distance = {round(mean_distance,2)} +/- {round(sem_distance,2)} kb",
        verticalalignment='top', horizontalalignment='left',
        transform=axes.transAxes, color=sns.desaturate(palettes[protein][1],0.75))

axes.set_xlim(0,20)
axes.set_ylim(0,15)
axes.set_xlabel('ORC distance pushed (kb)')
axes.set_ylabel('Number of occurrences')
#axes.legend(loc=0,frameon=False)

axes.text(0.05, 0.95, f"n = {len(_plot_df)}",
        verticalalignment='top', horizontalalignment='left',
        transform=axes.transAxes)

sns.despine()
#plt.tight_layout()

plt.savefig(dir_out+'S5K_ORC_pushed_distance.svg',transparent=True)<jupyter_output><empty_output><jupyter_text>Figure S5L: Pausing probability during transcription +/- ORC*Note*: only consider DNA w/o T7T, one ORC foci and only active pushing (pauses upon T7-ORC collision are not accounted for)<jupyter_code># 1st part, df with ORC == 1, no T7T, and tags contain ORC_1_push
df_orc = df[(~df['t7_terminator']) & (df['number_ORC'] == 1) & 
            (df['tags'].apply(lambda tags: re.search('ORC_1_push', ' '.join(tags))))]['ORC_1_']
df_orc
# 2nd part, df with MCM == 0, ORC == 0, no T7T and T7 ==1
df_t7 = df[(~df['t7_terminator']) & (df['number_T7'] == 1) & (df['number_ORC'] == 0)]['T7_1_']
df_t7['initial_intensity'] = 0
df_t7
df_pause = pd.concat([df_orc, df_t7])
df_pause
df_pause['number_ORC'] = df_pause['initial_intensity'].apply(estimate_bleaching)
df_pause
df_pause.groupby('number_ORC').describe()['number_pauses']
protein = 'ORC'

fig,axes = plt.subplots(figsize=(1.2, 2))

sns.barplot(x='number_ORC',y='number_pauses',data=df_pause,order=[0,1],
            palette=palettes[protein][::2],lw=1, edgecolor='.15', capsize=.3,errwidth=1, ax=axes, 
            n_boot=10000, seed=42, ci=68, errcolor='.15')
axes.set_xlabel('ORC pushed?')
axes.set_ylabel('Probability')
axes.set_xticklabels(['No','Yes'])
#axes.set_title(f'T7 pause frequency')
axes.set_ylim([0,1])
#calculate number of observations
nobs = df_pause['number_ORC'].value_counts().sort_index()
nobs = [str(x) for x in nobs.tolist()]
nobs = ["n = " + i for i in nobs]

#put nobs into plot
pos = range(len(nobs))
for tick,label in zip(pos,axes.get_xticklabels()):
    axes.text(pos[tick], 0.95, nobs[tick],
    horizontalalignment='center',verticalalignment='center')

sns.despine()
#plt.tight_layout()

#save
plt.savefig(dir_out+'S5L_pause_probability_ORC.svg',transparent=True)<jupyter_output><empty_output><jupyter_text>Figure S5M: Pause recovery +/- ORC*Note*: only consider DNA w/o T7T, one ORC foci and only active pushing (pauses upon T7-ORC collision are not accounted for)<jupyter_code>df_pause['number_pauses'] = df_pause['number_pauses'].fillna(0)
_plot_df = pd.DataFrame(columns=['duration','recovery','number_ORC'])
for index in df_pause.index:
    # check how many pauses we got
    
    for i in range(1,int(df_pause.loc[index,('number_pauses','')]+1)):

        _temp_df = pd.DataFrame(data=[[df_pause.loc[index,('pause_'+str(i),'duration')],
                                      df_pause.loc[index,('pause_'+str(i),'recovery')],
                                      df_pause.loc[index,('number_ORC','')]]],
                                      columns=['duration','recovery','number_ORC'])
        _plot_df = pd.concat([_plot_df,_temp_df])
    
_plot_df = _plot_df.convert_dtypes()
_plot_df.head()
_plot_df['recovery_bin'] = _plot_df['recovery'].apply(lambda recovery: 1 if recovery else 0)
_plot_df.head()
protein = 'ORC'
fig,axes = plt.subplots(figsize=(1.2, 2))

sns.barplot(x='number_ORC',y='recovery_bin', data=_plot_df,
            order=sorted(df_pause['number_ORC'].unique()),
            palette=palettes[protein][::2],lw=1, edgecolor='.15', capsize=.3,errwidth=1, ax=axes, 
            n_boot=10000, seed=42, ci=68, errcolor='.15')

axes.set_ylim(0,1)
axes.set_xlabel('ORC pushed?')
axes.set_ylabel('Probability of transient pausing')
axes.set_xticklabels(['No','Yes'])
#axes.set_title('Recovery from transcription pauses')

#calculate number of observations
nobs = _plot_df['number_ORC'].value_counts().sort_index()
nobs = [str(x) for x in nobs.tolist()]
nobs = ["n = " + i for i in nobs]

#put nobs into plot
pos = range(len(nobs))

for tick,label in zip(pos,axes.get_xticklabels()):
    transform=axes.transAxes, axes.text(pos[tick], 0.95, nobs[tick],
    horizontalalignment='center',verticalalignment='center')

#axes.set_xticklabels(['No','Yes'])

sns.despine()
#plt.tight_layout()

plt.savefig(dir_out+'S5M_pause_recovery_vs_#ORC.svg',transparent=True)<jupyter_output><empty_output><jupyter_text>Figure S5N: Pause durations (only transient pauses)*Note*: only consider DNA w/o T7T, one ORC foci and only active pushing (pauses upon T7-ORC collision are not accounted for)<jupyter_code>protein = 'ORC'
fig,axes = plt.subplots(figsize=(1.2, 2))

sns.swarmplot(x='number_ORC',y='duration', data=_plot_df[_plot_df['recovery']],
              order=sorted(df_pause['number_ORC'].unique()), palette=palettes[protein][::2], ax=axes)
sns.barplot(x='number_ORC',y='duration', data=_plot_df[_plot_df['recovery']],
            order=sorted(df_pause['number_ORC'].unique()), facecolor=(1, 1, 1, 0),
            palette=palettes[protein][::2],lw=1, edgecolor='.15', capsize=.3,errwidth=1, ax=axes, 
            n_boot=10000, seed=42, ci=68, errcolor='.15')

axes.set_ylim(0,600)
axes.set_xlabel('ORC pushed?')
axes.set_ylabel('Pause duration (s)')
axes.set_xticklabels(['No','Yes'])
#axes.set_title('Recovery from transcription pauses')

#calculate number of observations
nobs = _plot_df[_plot_df['recovery']]['number_ORC'].value_counts().sort_index()
nobs = [str(x) for x in nobs.tolist()]
nobs = ["n = " + i for i in nobs]

#put nobs into plot
pos = range(len(nobs))

for tick,label in zip(pos,axes.get_xticklabels()):
    transform=axes.transAxes, axes.text(pos[tick], 570, nobs[tick],
    horizontalalignment='center',verticalalignment='center')

sns.despine()
#plt.tight_layout()

plt.savefig(dir_out+'S5N_pause_duration_ORC.svg',transparent=True)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13483190455497177, 'fraction_numerical': 0.01769841583376131, 'mean_word_length': 3.4582599506868617, 'pattern_counts': {'":': 3, '<': 64, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 25, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '541702', 'license': 'BSD-2-Clause', 'n_tokens_mistral': 9101, 'n_tokens_neox': 8393, 'n_words': 1608, 'path': 'Analysis_software/Figures_5_S5/Figures_5I+J+L_S5K-N.ipynb', 'repo_name': 'mjosch/Born-to-slide', 'size': '25313'}