code: def generate_stimfunction(
      onsets,
      event_durations,
      total_time,
      weights=[1],
      timing_file=None,
      temporal_resolution=100.0,
  ):
      """Return the function for the timecourse events
  
      When do stimuli onset, how long for and to what extent should you
      resolve the fMRI time course. There are two ways to create this, either
      by supplying onset, duration and weight information or by supplying a
      timing file (in the three column format used by FSL).
  
      Parameters
      ----------
  
      onsets : list, int
          What are the timestamps (in s) for when an event you want to
          generate onsets?
  
      event_durations : list, int
          What are the durations (in s) of the events you want to
          generate? If there is only one value then this will be assigned
          to all onsets
  
      total_time : int
          How long (in s) is the experiment in total.
  
      weights : list, float
          What is the weight for each event (how high is the box car)? If
          there is only one value then this will be assigned to all onsets
  
      timing_file : string
          The filename (with path) to a three column timing file (FSL) to
          make the events. Still requires total_time to work
  
      temporal_resolution : float
          How many elements per second are you modeling for the
          timecourse. This is useful when you want to model the HRF at an
          arbitrarily high resolution (and then downsample to your TR later).
  
      Returns
      ----------
  
      stim_function : 1 by timepoint array, float
          The time course of stimulus evoked activation. This has a temporal
          resolution of temporal resolution / 1.0 elements per second
  
      """
  
      # If the timing file is supplied then use this to acquire the
      if timing_file is not None:
          # Read in text file line by line
          with open(timing_file) as f:
              text = f.readlines()  # Pull out file as a an array
  
          # Preset
          onsets = list()
          event_durations = list()
          weights = list()
  
          # Pull out the onsets, weights and durations, set as a float
          for line in text:
              onset, duration, weight = line.strip().split()
  
              # Check if the onset is more precise than the temporal resolution
              upsampled_onset = float(onset) * temporal_resolution
  
              # Because of float precision, the upsampled values might
              # not round as expected .
              # E.g. float('1.001') * 1000 = 1000.99
              if (
                  np.allclose(
                      upsampled_onset, np.round(upsampled_onset)
                  )
                  == 0
              ):
                  warning = (
                      "Your onset: " + str(onset) + " has more decimal "
                      "points than the "
                      "specified temporal "
                      "resolution can "
                      "resolve. This means"
                      " that events might"
                      " be missed. "
                      "Consider increasing"
                      " the temporal "
                      "resolution."
                  )
                  logger.warning(warning)
  
              onsets.append(float(onset))
              event_durations.append(float(duration))
              weights.append(float(weight))
  
      # If only one duration is supplied then duplicate it for the length of
      # the onset variable
      if len(event_durations) == 1:
          event_durations = event_durations * len(onsets)
  
      if len(weights) == 1:
          weights = weights * len(onsets)
  
      # Check files
      if np.max(onsets) > total_time:
          raise ValueError("Onsets outside of range of total time.")
  
      # Generate the time course as empty, each element is a millisecond by
      # default
      stimfunction = np.zeros(
          (int(round(total_time * temporal_resolution)), 1)
      )
  
      # Cycle through the onsets
      for onset_counter in list(range(len(onsets))):
          # Adjust for the resolution
          onset_idx = int(
              np.floor(onsets[onset_counter] * temporal_resolution)
          )
  
          # Adjust for the resolution
          offset_idx = int(
              np.floor(
                  (
                      onsets[onset_counter]
                      + event_durations[onset_counter]
                  )
                  * temporal_resolution
              )
          )
  
          # Store the weights
          stimfunction[onset_idx:offset_idx, 0] = [
              weights[onset_counter]
          ]
  
      return stimfunction
  
imports: import logging
  from itertools import product
  from statsmodels.tsa.arima.model import ARIMA
  import math
  import numpy
  from numpy.linalg import LinAlgError
  from pkg_resources import resource_stream
  from scipy import stats
  from scipy import signal
  import scipy.ndimage
  import copy
  from scipy import optimize
label_desc: Use image node_id 4 for calling a global function with example usage: generate_stimfunction(onsets, event_durations, total_time, weights, timing_file, temporal_resolution) and returns: stimfunction