circaPy 0.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
circaPy/plots.py ADDED
@@ -0,0 +1,351 @@
1
+ import re
2
+ import pdb
3
+ import pandas as pd
4
+ import numpy as np
5
+ import matplotlib.pyplot as plt
6
+ import matplotlib.gridspec as gs
7
+ from matplotlib.transforms import Bbox
8
+ import circaPy.activity as act
9
+ import circaPy.preprocessing as prep
10
+
11
+
12
+ @prep.validate_input
13
+ @prep.invert_light_values
14
+ @prep.plot_kwarg_decorator
15
+ def plot_actogram(data,
16
+ subject_no=0,
17
+ light_col=-1,
18
+ ylim=[0, 120],
19
+ fig=False,
20
+ subplot=False,
21
+ ldralpha=0.5,
22
+ start_day=0,
23
+ day_label_size=5,
24
+ linewidth=0.5,
25
+ **kwargs):
26
+ """
27
+ Plot an double plotted actogram of activity data over several days
28
+ with background shading set by the lights
29
+
30
+ Parameters:
31
+ ----------
32
+ data : (pd.DataFrame)
33
+ time-indexed pandas dataframe with activity values in
34
+ columns for each subject and one column for the light levels.
35
+ WRONG - currently expecting list of dataframes, one for each animal
36
+ and single column for each day
37
+ subject_no : int
38
+ which column number to plot, defaults to 0
39
+ light_col : int
40
+ which columns contains light information, defaults to -1
41
+ ylim : list of two ints
42
+ set the minimum and maximum values to plot
43
+ fig : matplotlib figure object
44
+ Figure to create plot on, if not passed defaults to false and
45
+ new figure is passed
46
+ subplot : matplotlib subplotspec object
47
+ Subplotspec from larger figure on which to draw actogram.
48
+ Must be created from gridspec
49
+ If not passed
50
+ defaults to False, which requires a fig object to be provided
51
+ ldralpha : float
52
+ Set the alpha level for how opaque to have the light shading,
53
+ defaults to 0.5
54
+ startday : int
55
+ sets which day to start as day 0 in plot, defaults to 0
56
+ day_label_size : int
57
+ sets size of labels on bottom x axis, defaults to 5
58
+
59
+ Returns
60
+ -------
61
+ matplotlib.pyplot.figure
62
+ instance containing overall figure
63
+ matplotlib.pyplot.subplot
64
+ the final subplot so can manipulate for xaxis
65
+ dict
66
+ dict containing plotting kwargs
67
+ """
68
+ # grab line plot constant
69
+ if "linewidth" in kwargs:
70
+ linewidth = kwargs["linewidth"]
71
+
72
+ # check if data is empty
73
+ if data.empty:
74
+ raise ValueError("Input Dataframe is empty. Cannot plot actogram")
75
+
76
+ # select the correct data to plot for activity and light
77
+ col_data = data.columns[subject_no]
78
+ ldr_col = data.columns[light_col]
79
+ data_plot = data.loc[:, col_data].copy()
80
+ data_light = data.loc[:, ldr_col].copy()
81
+
82
+ # add entire day of 0s at start and end by extending index
83
+ # grab values from current index
84
+ freq = pd.infer_freq(data_plot.index)
85
+ start = data_plot.index.min()
86
+ end = data_plot.index.max()
87
+
88
+ # check frequency works
89
+ try:
90
+ pd.Timedelta(freq)
91
+ except BaseException:
92
+ freq = pd.Timedelta(f"1{freq}")
93
+
94
+ # Extend the range by 1 day but make sure lines up with original index
95
+ # select the length of one day
96
+ day_length = len(data_plot.loc[str(data_plot.index[0].date())])
97
+ extended_start = start - (pd.Timedelta(freq) * day_length)
98
+ extended_end = end + (pd.Timedelta(freq) * day_length)
99
+
100
+ # create new index and set data to it
101
+ extended_index = pd.date_range(
102
+ start=extended_start, end=extended_end, freq=freq)
103
+ data_plot = data_plot.reindex(extended_index, fill_value=-100)
104
+
105
+ # select just the days
106
+ days = data_plot.index.normalize().unique()
107
+
108
+ # set all 0 values to be very low so not showing on y index starting at 0
109
+ for mask in data_plot, data_light:
110
+ mask[mask == 0] = -100
111
+
112
+ # Create figure and subplot for every day
113
+ # create a new figure if not passed one when called
114
+ if not fig:
115
+ fig, ax = plt.subplots(nrows=(len(days) - 1))
116
+ fig.subplots_adjust(hspace=0)
117
+
118
+ # add subplots to figure if passed when called
119
+ else:
120
+ # remove ticks so don't draw over when we add later
121
+ subplot.set(yticks=[], xticks=[])
122
+
123
+ # draw subplots for each day on the subplot given
124
+ subplot_spec = subplot.get_subplotspec()
125
+ subplot_grid = gs.GridSpecFromSubplotSpec(nrows=(len(days) - 1),
126
+ ncols=1,
127
+ subplot_spec=subplot_spec,
128
+ wspace=0,
129
+ hspace=0)
130
+ ax = []
131
+ for grid in subplot_grid:
132
+ sub_ax = plt.Subplot(fig, grid)
133
+ fig.add_subplot(sub_ax)
134
+ ax.append(sub_ax)
135
+
136
+ # select each day to then plot on separate axis
137
+ # plot two days on each row
138
+ for day_label, axis in zip(days, ax):
139
+ # get two days of data to plot
140
+ curr_day = str(day_label.date())
141
+ next_day = str(day_label.date() + pd.Timedelta("1d"))
142
+ curr_data = data_plot.loc[curr_day:next_day]
143
+ curr_data_light = data_light.loc[curr_day:next_day]
144
+
145
+ # create masked data for fill between to avoid horizontal lines
146
+ fill_data = curr_data.where(curr_data > 0)
147
+ fill_ldr = curr_data_light.where(curr_data_light > 0)
148
+
149
+ # plot the data and light_col
150
+ axis.fill_between(fill_ldr.index,
151
+ fill_ldr,
152
+ alpha=ldralpha,
153
+ facecolor="grey")
154
+ axis.plot(curr_data, linewidth=linewidth)
155
+ axis.fill_between(fill_data.index,
156
+ fill_data)
157
+
158
+ # need to hide all the axis to make visible
159
+ axis.set(xticks=[],
160
+ xlim=[curr_data.index[0],
161
+ curr_data.index[-1]],
162
+ yticks=[],
163
+ ylim=ylim)
164
+ spines = ["left", "right", "top", "bottom"]
165
+ for pos in spines:
166
+ axis.spines[pos].set_visible(False)
167
+
168
+ # create the y labels for every 10th row
169
+ day_markers = np.arange(0, len(days), 10)
170
+ day_markers = day_markers + start_day
171
+ for axis, day in zip(ax[::10], day_markers):
172
+ axis.set_ylabel(day,
173
+ rotation=0,
174
+ va='center',
175
+ ha='right',
176
+ fontsize=day_label_size)
177
+
178
+ # create defaults dict
179
+ params_dict = {
180
+ "xlabel": "Time",
181
+ "ylabel": "Days",
182
+ "interval": 6,
183
+ "title": "Double Plotted Actogram",
184
+ "timeaxis": True,
185
+ "subplot": subplot
186
+ }
187
+
188
+ # put axis as a controllable parameter
189
+ if "timeaxis" in kwargs:
190
+ params_dict['timeaxis'] = kwargs["timeaxis"]
191
+
192
+ return fig, ax, params_dict
193
+
194
+
195
+ @prep.validate_input
196
+ @prep.invert_light_values
197
+ @prep.plot_kwarg_decorator
198
+ def plot_activity_profile(data,
199
+ col=0,
200
+ light_col=-1,
201
+ subplot=None,
202
+ resample=False,
203
+ resample_freq="h",
204
+ *args,
205
+ **kwargs):
206
+ """
207
+ Plot the activity profile with mean and SEM (Standard Error of the Mean).
208
+ Optionally resample the data before plotting.
209
+
210
+ Parameters
211
+ ----------
212
+ data : pd.DataFrame or pd.Series
213
+ Activity data indexed by time. If `data` is a DataFrame, the
214
+ function uses the column specified by `col` (default is the
215
+ first column).
216
+ col : int, optional
217
+ The index of the column to plot, used when `data` is a
218
+ DataFrame (default is 0).
219
+ subplot : matplotlib.axes._axes.Axes, optional
220
+ Subplot to plot on. If None, a new figure and axis are
221
+ created (default is None).
222
+ resample : bool, optional
223
+ Whether to resample the data before plotting.
224
+ If `True`, the data will be resampled to the frequency
225
+ specified by `resample_freq` (default is `False`).
226
+ resample_freq : str, optional
227
+ The frequency to resample the data to.
228
+ This can be any valid pandas offset string
229
+ (e.g., "h" for hourly, "min" for minutely).
230
+ The default is "h" (hourly).
231
+ *args, **kwargs : additional arguments
232
+ These are passed to the plotting function,
233
+ such as `timeaxis` to control the appearance of the x-axis.
234
+
235
+ Returns
236
+ -------
237
+ fig : matplotlib.figure.Figure
238
+ The figure containing the plot.
239
+ ax : matplotlib.axes._axes.Axes
240
+ The axis with the plot.
241
+ params_dict : dict
242
+ A dictionary containing the plot's parameters,
243
+ including labels, title, and xlim.
244
+ """
245
+ # ability to resample if required
246
+ if resample:
247
+ data = data.resample(resample_freq).mean()
248
+
249
+ # select just the subject
250
+ curr_data = data.iloc[:, col]
251
+ light_data = data.iloc[:, light_col]
252
+
253
+ # Calculate mean activity and SEM
254
+ mean, sem = act.calculate_mean_activity(curr_data, sem=True)
255
+ light_mean = act.calculate_mean_activity(light_data)
256
+
257
+ # Convert the index of mean and sem to a DatetimeIndex starting 2001-01-01
258
+ start_date = "2001-01-01"
259
+ freq = pd.infer_freq(data.index)
260
+ datetime_index = pd.date_range(
261
+ start=start_date, periods=len(mean), freq=freq)
262
+ mean.index = datetime_index
263
+ sem.index = datetime_index
264
+ light_mean.index = datetime_index
265
+
266
+ # Ensure freq has a numeric component
267
+ if not any(char.isdigit() for char in freq):
268
+ freq = pd.Timedelta('1' + freq) # Prepend '1' if missing
269
+ # Extend the light_mean data by one extra period and forward fill
270
+ light_mean = pd.concat([light_mean, pd.Series(
271
+ [light_mean.iloc[-1]], index=[light_mean.index[-1] + pd.Timedelta(freq)])])
272
+ light_mean.ffill(inplace=True)
273
+
274
+ # Offset the mean and sem data to plot in the middle of the hour
275
+ offset_time = 0.5 * pd.Timedelta(freq)
276
+ mean.index += offset_time
277
+ sem.index += offset_time
278
+ light_mean.index += offset_time
279
+
280
+ # Create plot if no subplot is provided
281
+ if subplot is None:
282
+ fig, ax = plt.subplots(figsize=(10, 6))
283
+ else:
284
+ fig = plt.gcf()
285
+ ax = subplot
286
+
287
+ # Plot the mean line
288
+ ax.plot(
289
+ mean.index, mean, label="Mean Activity", color="blue", linewidth=2)
290
+
291
+ # Add shaded SEM region
292
+ ax.fill_between(
293
+ mean.index,
294
+ mean - sem,
295
+ mean + sem,
296
+ color="blue",
297
+ alpha=0.3,
298
+ label="± SEM"
299
+ )
300
+
301
+ # get ylims to set at this level later
302
+ ylim = ax.get_ylim()
303
+
304
+ # Find the min and max of light_mean
305
+ min_light_mean = light_mean.min()
306
+ max_light_mean = light_mean.max()
307
+
308
+ # Define the target range
309
+ target_max = 1000 * ylim[1]
310
+ target_min = -1 * target_max
311
+
312
+ # Scale the light_mean values to the target range
313
+ # The formula to scale the values is:
314
+ # scaled_value = (value - min_value) / (max_value - min_value)
315
+ # * (target_max - target_min) + target_min
316
+
317
+ scaled_light_mean = (light_mean - min_light_mean
318
+ ) / (max_light_mean - min_light_mean
319
+ ) * (target_max - target_min) + target_min
320
+
321
+ # Add lights region
322
+ ax.fill_between(
323
+ scaled_light_mean.index,
324
+ scaled_light_mean,
325
+ color='grey',
326
+ alpha=0.2
327
+ )
328
+
329
+ # Add labels, legend, and title
330
+ ax.set_xlabel("Time")
331
+ ax.set_ylabel("Activity")
332
+ ax.set_ylim([0, ylim[1]])
333
+ ax.set_title("Activity Profile with Mean and SEM")
334
+ ax.legend()
335
+
336
+ # create defaults dict
337
+ xlim = [mean.index[0], (mean.index[0] + pd.Timedelta("24h"))]
338
+ params_dict = {
339
+ "xlabel": "Time",
340
+ "ylabel": "Activity",
341
+ "interval": 6,
342
+ "title": "Mean activity profile",
343
+ "timeaxis": True,
344
+ "xlim": xlim,
345
+ }
346
+
347
+ # put axis as a controllable parameter
348
+ if "timeaxis" in kwargs:
349
+ params_dict['timeaxis'] = kwargs["timeaxis"]
350
+
351
+ return fig, ax, params_dict
@@ -0,0 +1,261 @@
1
+ import pdb
2
+ from functools import wraps
3
+ import pingouin as pg
4
+ import pandas as pd
5
+ import numpy as np
6
+ import matplotlib.pyplot as plt
7
+ import matplotlib.dates as mdates
8
+ idx = pd.IndexSlice
9
+ # This script contains functions which are useful for preprocessing of
10
+ # actigraphy data
11
+
12
+ #### Decorators ####
13
+
14
+
15
+ def plot_kwarg_decorator(func):
16
+ """
17
+ Universal decorator for plot formatting and configuration.
18
+ Handles xlabels, ylabels, titles, legends, time formatting, saving,
19
+ and showing plots.
20
+ :param func: The plotting function to decorate.
21
+ :return: A decorated function that applies plot configurations.
22
+ """
23
+ @wraps(func)
24
+ def wrapper(data, *args, **kwargs):
25
+ # Call the original plotting function
26
+ fig, ax, params_dict = func(data, *args, **kwargs)
27
+
28
+ # check if multiple subplots or not
29
+ if isinstance(ax, (np.ndarray, list)):
30
+ final_ax = ax[-1]
31
+ else:
32
+ final_ax = ax
33
+
34
+ # Configure x-axis limits
35
+ if "xlim" in kwargs or "xlim" in params_dict:
36
+ xlim = kwargs.get("xlim", params_dict.get("xlim", None))
37
+ if xlim:
38
+ final_ax.set_xlim(xlim)
39
+
40
+ # Configure x-axis time formatting
41
+ if "timeaxis" in params_dict and params_dict["timeaxis"]:
42
+ xfmt = kwargs.get("xfmt", mdates.DateFormatter("%H:%M"))
43
+ final_ax.xaxis.set_major_formatter(xfmt)
44
+ interval = kwargs.get("interval", params_dict.get("interval", 1))
45
+ final_ax.xaxis.set_major_locator(
46
+ mdates.HourLocator(interval=interval))
47
+ fig.autofmt_xdate()
48
+
49
+ # Set x-axis label
50
+ xlabel = kwargs.get("xlabel", params_dict.get("xlabel", ""))
51
+ if xlabel:
52
+ final_ax.set_xlabel(
53
+ xlabel,
54
+ labelpad=5,
55
+ ha='center',
56
+ va='center')
57
+
58
+ # Set y-axis label
59
+ ylabel = kwargs.get("ylabel", params_dict.get("ylabel", ""))
60
+ ylabelpos = kwargs.get("ylabelpos", (0.02, 0.5))
61
+ subplot = kwargs.get("subplot", params_dict.get("subplot", None))
62
+ if ylabel:
63
+ if subplot:
64
+ subplot.set_ylabel(
65
+ ylabel,
66
+ labelpad=5,
67
+ ha='center',
68
+ va='center',
69
+ rotation='vertical')
70
+ else:
71
+ fig.text(
72
+ ylabelpos[0],
73
+ ylabelpos[1],
74
+ ylabel,
75
+ ha="center",
76
+ va="center",
77
+ rotation="vertical"
78
+ )
79
+
80
+ # Set plot title
81
+ title = kwargs.get("title", params_dict.get("title", ""))
82
+ if title:
83
+ fig.suptitle(title)
84
+
85
+ # Configure legend
86
+ if kwargs.get("legend", False):
87
+ legend_loc = kwargs.get("legend_loc", 1)
88
+ handles, labels = final_ax.get_legend_handles_labels()
89
+ fig.legend(handles, labels, loc=legend_loc)
90
+
91
+ # Configure figure size
92
+ if "figsize" in kwargs:
93
+ fig.set_size_inches(kwargs["figsize"])
94
+
95
+ # Save or show the plot
96
+ if kwargs.get("savefig", False):
97
+ fname = kwargs.get("fname", "plot.png")
98
+ plt.savefig(fname)
99
+ plt.close()
100
+ if kwargs.get("showfig", False):
101
+ plt.show()
102
+
103
+ return fig, ax, params_dict
104
+
105
+ return wrapper
106
+
107
+
108
+ def validate_input(func):
109
+ """
110
+ Decorator to validate DataFrames or Series passed to the function.
111
+ - Checks if any input consists only of zeros.
112
+ - Checks if any DataFrame is empty.
113
+ - Checks if the index of any DataFrame is a DatetimeIndex.
114
+ Raises a ValueError if any condition is not met.
115
+ """
116
+ @wraps(func)
117
+ def wrapper(*args, **kwargs):
118
+ # Helper function to validate a DataFrame or Series
119
+ def _validate(input_data, name):
120
+ if isinstance(
121
+ input_data,
122
+ pd.DataFrame) or isinstance(
123
+ input_data,
124
+ pd.Series):
125
+ # Check if consists only of zeros
126
+ if (input_data.values == 0).all():
127
+ raise ValueError(f"Input {name} consists only of zeros.")
128
+
129
+ # Check if empty
130
+ if input_data.empty:
131
+ raise ValueError(f"Input {name} is empty.")
132
+
133
+ # Check if index is a DatetimeIndex (only for DataFrames)
134
+ if isinstance(
135
+ input_data,
136
+ pd.DataFrame) and not isinstance(
137
+ input_data.index,
138
+ pd.DatetimeIndex):
139
+ raise TypeError(
140
+ f"Input {name} does not have a DatetimeIndex.")
141
+
142
+ # Validate positional arguments
143
+ for i, arg in enumerate(args):
144
+ _validate(arg, f"arg[{i}]")
145
+
146
+ # Validate keyword arguments
147
+ for key, value in kwargs.items():
148
+ _validate(value, f"kwarg[{key}]")
149
+
150
+ # Call the original function
151
+ return func(*args, **kwargs)
152
+
153
+ return wrapper
154
+
155
+
156
+ def invert_light_values(func):
157
+ """
158
+ Decorator to invert the light values in the given light column.
159
+ Used to ensure that on plots, darkness is shaded grey, not the lights.
160
+
161
+ Parameters
162
+ ----------
163
+ func : function
164
+ The function to wrap.
165
+
166
+ Returns
167
+ -------
168
+ function
169
+ The wrapped function with inverted light values in the specified column.
170
+ """
171
+ @wraps(func)
172
+ def wrapper(data, *args, light_col=-1, **kwargs):
173
+ # Ensure light_col is a valid index
174
+ if isinstance(light_col, int): # If specified as column index
175
+ light_col_name = data.columns[light_col]
176
+ elif isinstance(light_col, str): # If specified as column name
177
+ light_col_name = light_col
178
+ else:
179
+ raise ValueError(
180
+ "light_col must be an integer index or a column name")
181
+
182
+ # Copy the data to avoid modifying the original DataFrame
183
+ data = data.copy()
184
+
185
+ # Invert the light values
186
+ max_value = data[light_col_name].max()
187
+ min_value = data[light_col_name].min()
188
+ data[light_col_name] = max_value - data[light_col_name] + min_value
189
+
190
+ # Call the original function with the modified data
191
+ return func(data, *args, **kwargs)
192
+
193
+ return wrapper
194
+
195
+
196
+ #### Functions ####
197
+ # function to set data by circadian period
198
+ @validate_input
199
+ def set_circadian_time(
200
+ data,
201
+ period='24h'):
202
+ """
203
+ Reindexes current data to 24 hours CT instead of ZT by setting
204
+ frequency to the ratio of 24hrs/new period
205
+
206
+ Parameters
207
+ ----------
208
+ data : pd.DataFrame
209
+ Dataframe with a pandas timeindex
210
+ period : str or float
211
+ The new period to set the data to.
212
+ Timedelta string (e.g., '24h', '1d', '72h')
213
+
214
+ Returns
215
+ -------
216
+ pd.DataFrame
217
+ Original data but with a new datetimeindex, starting at the same time
218
+ as the original but now 24 hours is equal to the given period instead
219
+ of real time.
220
+ """
221
+
222
+ # Convert period string to timedelta
223
+ if isinstance(period, str):
224
+ period = pd.to_timedelta(period)
225
+ else:
226
+ raise TypeError("Period must be in timedelta string format")
227
+
228
+ # Calculate the frequency ratio based on the period
229
+ freq_ratio = 24 / (period.total_seconds() / 3600)
230
+
231
+ # get data frequency as timedelta
232
+ base_freq = pd.infer_freq(data.index)
233
+
234
+ # Ensure base_freq has a numeric component
235
+ if not any(char.isdigit() for char in base_freq):
236
+ base_freq = '1' + base_freq # Prepend '1' if missing
237
+
238
+ # convert to timedelta
239
+ base_timedelta = pd.to_timedelta(base_freq)
240
+
241
+ # calculate ratio as a string
242
+ new_timedelta = base_timedelta * freq_ratio
243
+ new_freq_str = str(np.round(new_timedelta.total_seconds() * 1000)) + "ms"
244
+
245
+ # create new index based on this
246
+ start_time = data.index[0]
247
+ data_length = len(data)
248
+ new_index = pd.date_range(
249
+ start=start_time,
250
+ periods=data_length,
251
+ freq=new_freq_str
252
+ )
253
+
254
+ # reindex the data
255
+ reindexed_data = pd.DataFrame(
256
+ data=data.values,
257
+ index=new_index,
258
+ columns=data.columns
259
+ )
260
+
261
+ return reindexed_data
@@ -0,0 +1,96 @@
1
+ # functions for sleep processing
2
+
3
+ import os
4
+ import numpy as np
5
+ import circaPy.preprocessing as prep
6
+
7
+
8
+ def sleep_process(data, window=4):
9
+ """
10
+ Function to score activity data as sleep given
11
+ a certain window of activity
12
+ Future development implement thresholds for breaking
13
+ sleep episodes.
14
+ Returns scored dataframe
15
+ :param data:
16
+ :param window:
17
+ :return:
18
+ """
19
+ # score > window as inactivity score of 1
20
+ rolling_sum_data = data.rolling(window).sum()
21
+ bool_scored_data = rolling_sum_data == 0
22
+ scored_data = bool_scored_data.astype(int)
23
+ return scored_data
24
+
25
+
26
+ def create_scored_df(data, **kwargs):
27
+ """
28
+ Function to take dataframe as input and return the same data
29
+ and labels but scored for sleep -> then appropriate to save
30
+ :param data:
31
+ :return:
32
+ """
33
+ # remove object columns, score, return columns to df
34
+ sleep_df = _score_active_times(data, **kwargs)
35
+ return sleep_df
36
+
37
+
38
+ def _score_active_times(data,
39
+ ldr_col=-1,
40
+ test_col=0,
41
+ threshold=1,
42
+ drop_level=True):
43
+ """
44
+ Scores all times between start and end of activity as sleep, sets all
45
+ other values to 0
46
+ :param data:
47
+ :param ldr_col:
48
+ :param test_col:
49
+ :param threshold:
50
+ :param drop_level:
51
+ :return:
52
+ """
53
+ if drop_level:
54
+ data = data.reset_index(0)
55
+ label_name = data.columns[0]
56
+ label_col = data.pop(label_name)
57
+
58
+ # score the df minus the LDR
59
+ ldr_label = data.columns[ldr_col]
60
+ ldr_data = data.pop(ldr_label)
61
+ scored_df = sleep_process(data)
62
+
63
+ # find start and end of activity
64
+ mask = data.iloc[:, test_col] > threshold
65
+ start = data.where(mask).first_valid_index()
66
+ end = data.where(mask)[::-1].first_valid_index()
67
+
68
+ # set scored df times outside of start and end to be 0
69
+ scored_df.loc[:start] = 0
70
+ scored_df.loc[end:] = 0
71
+ scored_df[ldr_label] = ldr_data
72
+
73
+ if drop_level:
74
+ scored_df[label_name] = label_col
75
+ new_cols = [scored_df.columns[-1], scored_df.index]
76
+ scored_df.set_index(new_cols, inplace=True)
77
+
78
+ return scored_df
79
+
80
+
81
+ def alter_file_name(file_name,
82
+ suffix,
83
+ remove_slice_after=-9):
84
+ """
85
+ Function to take in the file name and remove part of the
86
+ name, replace with "suffix" and rename the file
87
+ :param file_name:
88
+ :param suffix:
89
+ :param slice_range:
90
+ :return:
91
+ """
92
+ new_file_name = file_name.stem[:remove_slice_after] + \
93
+ suffix + \
94
+ file_name.suffix
95
+ new_file_path = file_name.parent / new_file_name
96
+ os.rename(file_name, new_file_path)