Project: s41467-024-47677-8 | Function: generate_trxyt (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Comprehensive synthetic trajectory generator implementing spatiotemporal cluster formation with constrained random walks, hotspot generation, and noise trajectories for validating NASTIC clustering algorithms

**KEY TERMS:** {
  "seeds": "spatiotemporal cluster seed points (x,y,t)",
  "trajectories": "simulated single-molecule trajectories",
  "clustercounter": "number of generated clusters",
  "radius": "cluster spatial constraint radius",
  "orbit": "constrained vs unconstrained random walk mode",
  "hotspotprobability": "probability of generating overlapping clusters",
  "noise": "unclustered background trajectories with higher mobility"
}

**CONTEXT CODE:** 		midpoint_x_list.append(point_x)
		point_y = trajy_before + (i*midpoint_y)
		midpoint_y_list.append(point_y)
	midpoint_list = zip(midpoint_x_list,midpoint_y_list)
	return(midpoint_list)
		
# READ ROI FILE	
def read_roi():
	global allx, ally, selverts, roidict,p_list,selarea_list
	print ("\nLoading NASTIC ROI file")
	print("------------------------------------------------------------")
	print("NASTIC ROI file selected: \n{}".format(roi_file))
	print("Reading ROI file...")
	roidict = {}
	allx = []
	ally = []
	with open (roi_file,"r") as infile:
		for line in infile:
			spl = line.split("\t")
			try:
				roi = int(spl[0])
				x = float(spl[1])
				y = float(spl[2])
				if x < 0:
					x = 0.0 # prevent crash if roi file contains negative x values
				if y < 0:
					y = 0.0 # prevent crash if roi file contains negative y values
				allx.append(x)
				ally.append(y)
				try:
					roidict[roi].append([x,y])
				except:	
					roidict[roi] = []
					roidict[roi].append([x,y])
			except:
				pass
	p_list = [] # list of ROI paths (1 per ROI in ROI file)
	selarea_list = [] # list of ROI selection areas (1 per ROI in ROI file)
	roi_ct = 0
	for roi in roidict:
		roi_ct+=1
		selverts =roidict[roi]
		p = path.Path(selverts)
		p_list.append(p)
		selarea =PolyArea(list(zip(*selverts))[0],list(zip(*selverts))[1])
		selarea_list.append(selarea)
	print("{} ROIs found in ROI file\n".format(roi_ct))
	return()

# GENERATE TRXYT
def generate_trxyt(Load_ROI):
	"""Comprehensive synthetic trajectory generator implementing spatiotemporal cluster formation with constrained random walks, hotspot generation, and noise trajectories for validating NASTIC clustering algorithms

	:param Load_ROI: Boolean flag to determine if ROI coordinates are used for area definition
	"""
	# MASKED: Comprehensive synthetic trajectory generator implementing spatiotemporal cluster formation with constrained random walks, hotspot generation, and noise trajectories for validating NASTIC clustering algorithms
	raise NotImplementedError("This function is masked for testing purposes.")
	
# Output
def output(traj_num_ct,stamp,Load_ROI):								 
	print("\nWriting files")
	print("------------------------------------------------------------")
	print ("Writing trxyt...")
	with open("synthetic_data_output_{}/synthetic_data_{}_{}.trxyt".format(stamp, stamp,traj_num_ct+1),"a") as outfile: 

		if Load_ROI == False:
			for tr,traj in enumerate(trajectories,start=1):
				for seg in traj:
					x,y,t = seg
					outline = "{} {} {} {}\n".format(tr,x,y,round(t,frame_time_round_val))
					outfile.write(outline)
		elif Load_ROI == True:
			if len(trajectory_list) > 1:
				trajectory_temp_list = []
				for tr, trajectory in enumerate(trajectory_list):
					for traj in trajectory:
						trajectory_temp_list.append(traj)
				for tr,traj in enumerate(trajectory_temp_list,start=1):
					for seg in traj:
						x,y,t = seg
						outline = "{} {} {} {}\n".format(tr,x,y,round(t,frame_time_round_val))
						outfile.write(outline)
			else:
				for tr,traj in enumerate(trajectories,start=1):
					for seg in traj:
						x,y,t = seg
						outline = "{} {} {} {}\n".format(tr,x,y,round(t,frame_time_round_val))
						outfile.write(outline)
	print ("Writing metrics...")
	with open("synthetic_data_output_{}/synthetic_data_{}_{}_metrics.tsv".format(stamp,stamp,traj_num_ct+1),"a") as outfile: 
		if Load_ROI == False:
			outfile.write("PARAMETERS:\n=================\n")
		elif Load_ROI == True:
			outfile.write("PARAMETERS:\n==================================\n")
		outfile.write("ACQUISITION TIME (s): {}\n".format(acquisition_time))	
		outfile.write("FRAME TIME (s): {}\n".format(frame_time))	
		if Load_ROI == True:
			outfile.write("ROI FILE: {}\n".format(roi_file))	
			outfile.write("ROI AREA: {}\n".format(selarea))	
		if Load_ROI == False:
			outfile.write("X SIZE (um): {}\n".format(x_size ))	
			outfile.write("Y SIZE (um): {}\n".format(y_size))	
		outfile.write("SEED DENSITY (per um2): {}\n".format(seed_density))	
		outfile.write("SEED RADIUS (um): {}\n".format(radius))	
		outfile.write("MIN TRAJ AROUND SEED: {}\n".format(min_traj_num))	
		outfile.write("MAX TRAJ AROUND SEED: {}\n".format(max_traj_num))	
		outfile.write("MIN TRAJ STEPS: {}\n".format(min_traj_length))	
		outfile.write("MAX TRAJ STEPS: {}\n".format(max_traj_length))
		outfile.write("MAX STEPLENGTH (um): {}\n".format(steplength))	
		outfile.write("CLUSTER TRAJ ORBIT: {}\n".format(orbit))	
		outfile.write("NOISE FACTOR: {}\n".format(noise_factor))	
		outfile.write("UNCLUST STEPLENGTH MULTIPLIER: {}\n".format(unconst))	
		outfile.write("HOTSPOT PROBABILITY: {}\n".format(hotspotprobability))	
		outfile.write("MAX CLUSTERS PER HOTSPOT: {}\n".format(hotspotmax))	
		if Load_ROI == False:
			outfile.write("\nGENERATED METRICS:\n=================\n")
			outfile.write("TOTAL TRAJECTORIES: {}\n".format(clusttrajcounter + noise))
			outfile.write("CLUSTERED TRAJECTORIES: {}\n".format(clusttrajcounter))	
			outfile.write("UNCLUSTERED TRAJECTORIES: {}\n".format(noise))	
			outfile.write("TOTAL CLUSTERS: {}\n".format(clustercounter))
			outfile.write("SINGLETON CLUSTERS: {}\n".format(seed_num))
			outfile.write("AVERAGE TRAJECTORIES PER CLUSTER: {} +/- {}\n".format(np.average(traj_nums),np.std(traj_nums)/math.sqrt(len(traj_nums))))	
			outfile.write("AVERAGE CLUSTER RADIUS: {} +/- {}\n".format(np.average(radii),np.std(radii)/math.sqrt(len(radii))))	
		if Load_ROI == True:	
			for roi,selarea_roi,clusttrajcounter_roi,noise_roi,clustercounter_roi,seed_num_roi,traj_nums_roi,radii_roi in list(zip(roidict,selarea_list,clusttrajcounter_list,noise_list,clustercounter_list,seed_num_list,traj_nums_list,radii_list)):
				outfile.write("\nGENERATED METRICS (ROI #{}):\n==================================\n".format(roi))
				outfile.write("ROI AREA: {}\n".format(selarea_roi))	
				outfile.write("TOTAL TRAJECTORIES: {}\n".format(clusttrajcounter_roi + noise_roi))
				outfile.write("CLUSTERED TRAJECTORIES: {}\n".format(clusttrajcounter_roi))
				outfile.write("UNCLUSTERED TRAJECTORIES: {}\n".format(noise_roi))	
				outfile.write("TOTAL CLUSTERS: {}\n".format(clustercounter_roi))
				outfile.write("SINGLETON CLUSTERS: {}\n".format(seed_num_roi))
				outfile.write("AVERAGE TRAJECTORIES PER CLUSTER: {} +/- {}\n".format(np.average(traj_nums_roi),np.std(traj_nums_roi)/math.sqrt(len(traj_nums_roi))))	
				outfile.write("AVERAGE CLUSTER RADIUS: {} +/- {}\n".format(np.average(radii_roi),np.std(radii_roi)/math.sqrt(len(radii_roi))))
			if len(roidict) > 1:
				outfile.write("\nGENERATED METRICS (COMBINED ROIS):\n==================================\n")
				outfile.write("ROI AREA: {}\n".format(sum(selarea_list)))
				outfile.write("TOTAL TRAJECTORIES: {}\n".format(sum(clusttrajcounter_list) + sum(noise_list)))
				outfile.write("CLUSTERED TRAJECTORIES: {}\n".format(sum(clusttrajcounter_list)))
				outfile.write("UNCLUSTERED TRAJECTORIES: {}\n".format(sum(noise_list)))	
				outfile.write("TOTAL CLUSTERS: {}\n".format(sum(clustercounter_list)))
				outfile.write("SINGLETON CLUSTERS: {}\n".format(sum(seed_num_list)))
				new_traj_nums_list = []
				for roi in traj_nums_list:
					for traj in roi:
						new_traj_nums_list.append(traj)
				new_radii_list = []
				for radii_roi in radii_list:
					for rad in radii_roi:
						new_radii_list.append(rad)


Complete the function implementation replacing "raise NotImplementedError".