88import pyvista as pv
99import sys
1010import os
11+ import time
12+ import json
13+ import numpy as np
14+ import matplotlib .pyplot as plt
1115
12- last_mesh = None
1316
14- all_points = []
15- all_point_types = []
17+ last_meshes = {}
1618
17- boundary_points = []
18- boundary_point_types = [ 3 , 3.1 ]
19+ replay_speed = 0.05 # seconds between frames
20+ replaying = False
1921
20- point_size = 5
21- boundary_point_size = 3
22+ all_points = []
23+ all_point_types = []
2224
23- boundary_color = "#eeeeee"
2425
2526plotter = None
26-
27- offset_ = 50
28-
29- color_range = {1.1 : "blue" , 2.2 : "turquoise" }
27+ offset_ = 0
28+ slider = None
29+
30+ show_boundary = False
31+
32+
33+ def get_color_info_for_type (type_ ):
34+ """
35+ Get color, info string and point size for a given point type
36+ returns: color, info, size
37+ """
38+
39+ if type_ == 1.1 :
40+ return "#8BEBFC" , "liquid 1" , 5
41+ elif type_ == 1.2 :
42+ return "#3ACFF0" , "liquid 2" , 5
43+ elif type_ == 2.1 :
44+ return "yellow" , "elastic 1" , 5
45+ elif type_ == 2.2 :
46+ return "#FF0000" , "elastic 2" , 5
47+ elif type_ > 2 and type_ < 3 :
48+ return "#00cc00" , "elastic variable" , 5
49+ elif type_ == 3 :
50+ return "grey" , "boundary 0" , 3
51+ elif type_ == 3.1 :
52+ return "black" , "boundary 1" , 7
53+ else :
54+ return "orange" , "unknown" , 5
3055
3156
3257def add_sibernetic_model (
3358 pl ,
3459 position_file = "Sibernetic/position_buffer.txt" ,
60+ report_file = None ,
3561 swap_y_z = False ,
36- offset = 50 ,
62+ offset = 0 ,
3763 include_boundary = False ,
3864):
39- global all_points , all_point_types , last_mesh , plotter , offset_
65+ global all_points , all_point_types , last_meshes , plotter , offset_ , slider , show_boundary
4066
4167 offset_ = offset
4268 plotter = pl
69+ show_boundary = include_boundary
4370
44- points = []
71+ points = {}
4572 types = []
4673
4774 line_count = 0
4875 pcount = 0
4976 time_count = 0
5077 logStep = None
5178
79+ report_data = None
80+ count_point_types = {}
81+
82+ if report_file is not None :
83+ sim_dir = os .path .dirname (os .path .abspath (report_file ))
84+ report_data = json .load (open (report_file , "r" ))
85+ print (report_data )
86+ position_file = os .path .join (sim_dir , "position_buffer.txt" )
87+
88+ if "worm" in report_data ["configuration" ]:
89+ muscle_activation_file = os .path .join (
90+ sim_dir , "muscles_activity_buffer.txt"
91+ )
92+ print ("Loading muscle activation file from: %s" % muscle_activation_file )
93+ musc_dat = np .loadtxt (muscle_activation_file , delimiter = "\t " ).T
94+ print (musc_dat )
95+ print (musc_dat .shape )
96+ # plt.imshow(musc_dat, interpolation="none", aspect="auto", cmap="YlOrRd")
97+
98+ f , ax = plt .subplots (tight_layout = True )
99+ ax .imshow (musc_dat , interpolation = "none" , aspect = "auto" , cmap = "YlOrRd" )
100+ # ax.set_ylim([-1, 1])
101+ ax .set_xlabel ("Time (s)" )
102+ _ = ax .set_ylabel ("Muscle" )
103+
104+ h_chart = pv .ChartMPL (f , size = (0.35 , 0.35 ), loc = (0.02 , 0.06 ))
105+ h_chart .title = None
106+ h_chart .border_color = "white"
107+ h_chart .show_title = False
108+ h_chart .background_color = (1.0 , 1.0 , 1.0 , 0.4 )
109+ pl .add_chart (
110+ h_chart ,
111+ )
112+
113+ first_pass_complete = False
114+
52115 for line in open (position_file ):
53116 ws = line .split ()
54117 # print(ws)
@@ -65,40 +128,34 @@ def add_sibernetic_model(
65128
66129 if len (ws ) == 4 :
67130 type_ = float (ws [3 ])
131+ if type_ not in points :
132+ points [type_ ] = []
68133
69- if type_ not in boundary_point_types :
70- if swap_y_z :
71- points .append ([float (ws [1 ]), 1 * float (ws [0 ]), float (ws [2 ])])
72- else :
73- points .append ([float (ws [0 ]), float (ws [1 ]), float (ws [2 ])])
74-
75- types .append (type_ )
134+ if not first_pass_complete :
135+ if type_ not in count_point_types :
136+ count_point_types [type_ ] = 0
137+ count_point_types [type_ ] += 1
76138
139+ if swap_y_z :
140+ points [type_ ].append ([float (ws [1 ]), 1 * float (ws [0 ]), float (ws [2 ])])
77141 else :
78- if include_boundary :
79- if swap_y_z :
80- boundary_points .append (
81- [float (ws [1 ]), 1 * float (ws [0 ]), float (ws [2 ])]
82- )
83- else :
84- boundary_points .append (
85- [float (ws [0 ]), float (ws [1 ]), float (ws [2 ])]
86- )
87-
88- # types.append(type_)
142+ points [type_ ].append ([float (ws [0 ]), float (ws [1 ]), float (ws [2 ])])
143+
144+ types .append (type_ )
89145
90146 if logStep is not None :
91147 pcount += 1
92148
93149 if pcount == numOfBoundaryP + numOfElasticP + numOfLiquidP :
150+ first_pass_complete = True
94151 print (
95- "End of one batch of %i added, %i total points at line %i, time: %i"
96- % (len (points ), pcount , line_count , time_count )
152+ "End of one batch of %i total points ( %i types), at line %i, time: %i"
153+ % (pcount , len (points ), line_count , time_count )
97154 )
98155 all_points .append (points )
99156 all_point_types .append (types )
100157
101- points = []
158+ points = {}
102159 types = []
103160 pcount = 0
104161 numOfBoundaryP = 0
@@ -107,10 +164,8 @@ def add_sibernetic_model(
107164
108165 line_count += 1
109166
110- # all_points_np = np.array(all_points)
111-
112167 print (
113- "Loaded positions with %i elastic, %i liquid and %i boundary points (%i total), %i lines"
168+ "Loaded positions with %i elastic, %i liquid and %i boundary points (%i total), over %i lines"
114169 % (
115170 numOfElasticP ,
116171 numOfLiquidP ,
@@ -120,62 +175,106 @@ def add_sibernetic_model(
120175 )
121176 )
122177
123- if include_boundary :
124- bound_mesh = pv .PolyData (boundary_points )
125- bound_mesh .translate ((offset_ , - 50 , - 100 ), inplace = True )
126-
127- plotter .add_mesh (
128- bound_mesh ,
129- render_points_as_spheres = True ,
130- color = boundary_color ,
131- point_size = boundary_point_size ,
132- )
133-
134178 print ("Num of time points found: %i" % len (all_points ))
179+ print ("Count of point types found: %s" % dict (sorted (count_point_types .items ())))
135180
136181 create_mesh (0 )
137182
138- plotter .remove_scalar_bar ("types" )
139-
140183 max_time = len (all_points ) - 1
141- pl .add_slider_widget (create_mesh , rng = [0 , max_time ], value = 0 , title = "Time point" )
142- pl .add_timer_event (max_steps = 5 , duration = 2 , callback = create_mesh )
143184
185+ slider = pl .add_slider_widget (
186+ create_mesh , rng = [0 , max_time ], value = 0 , title = "Time point" , style = "modern"
187+ )
188+
189+ pl .add_checkbox_button_widget (play_animation , value = False )
144190
145- def create_mesh (step ):
146- import time
147191
192+ def play_animation (play ):
193+ global plotter , last_meshes , all_points , all_point_types , replaying , slider
194+ print ("Playing animation: %s" % play )
195+
196+ if not play :
197+ replaying = False
198+ print ("Animation stopped." )
199+ return
200+ else :
201+ replaying = True
202+ print ("Animation started." )
203+
204+ if last_meshes is None :
205+ print ("No meshes to animate. Please load a model first." )
206+ return
207+
208+ for i in range (len (all_points )):
209+ if not replaying :
210+ break
211+ curr_time = slider .GetSliderRepresentation ().GetValue ()
212+
213+ print (
214+ " --- Animating step %i (curr_time: %s) of %i, %s"
215+ % (i , curr_time , len (all_points ), play )
216+ )
217+ next_time = curr_time + 1
218+ slider .GetSliderRepresentation ().SetValue (next_time )
219+
220+ create_mesh (next_time )
221+ plotter .update ()
222+ plotter .render ()
223+ time .sleep (replay_speed )
224+
225+
226+ def create_mesh (step ):
148227 step_count = step
149228 value = step_count
150- global all_points , all_point_types , last_mesh , plotter , offset_
229+ global all_points , last_meshes , plotter , offset_ , replaying , show_boundary
151230
152231 index = int (value )
232+ if index >= len (all_points ):
233+ print (
234+ "Index %i out of bounds for all_points with length %i"
235+ % (index , len (all_points ))
236+ )
237+ replaying = False
238+ return
153239
154- print ("Changing to time point: %s (%s) " % (index , value ))
155- curr_points = all_points [index ]
156- curr_types = all_point_types [index ]
240+ print (" -- Creating new mesh at time point: %s (%s) " % (index , value ))
241+ curr_points_dict = all_points [index ]
157242
158- print ("Plotting %i points with %i types" % (len (curr_points ), len ( curr_types )))
243+ print (" Plotting %i point types" % (len (curr_points_dict )))
159244
160- if last_mesh is None :
161- last_mesh = pv . PolyData ( curr_points )
162- last_mesh [ "types" ] = curr_types
163- last_mesh . translate (( 0 , - 1000 , 0 ), inplace = True )
164- print ( last_mesh )
245+ for type_ , curr_points in curr_points_dict . items () :
246+ color , info , size = get_color_info_for_type ( type_ )
247+ is_boundary = "boundary" in info
248+ if show_boundary is False and is_boundary :
249+ continue
165250
166- # last_actor =
167- plotter .add_mesh (
168- last_mesh ,
169- render_points_as_spheres = True ,
170- cmap = [c for c in color_range .values ()],
171- point_size = point_size ,
251+ print (
252+ " - Plotting %i points of type '%s' (%s), color: %s, size: %i"
253+ % (len (curr_points ), type_ , info , color , size )
172254 )
173- else :
174- last_mesh .points = curr_points
175- last_mesh .translate ((offset_ , - 50 , - 100 ), inplace = True )
255+
256+ if len (curr_points ) == 0 :
257+ continue
258+ if type_ not in last_meshes :
259+ last_meshes [type_ ] = pv .PolyData (curr_points )
260+ last_meshes [type_ ].translate ((0 , 0 , 0 ), inplace = True )
261+
262+ # last_actor =
263+ plotter .add_mesh (
264+ last_meshes [type_ ],
265+ render_points_as_spheres = True ,
266+ point_size = size ,
267+ color = color ,
268+ )
269+ else :
270+ if not is_boundary :
271+ last_meshes [type_ ].points = curr_points
272+ last_meshes [type_ ].translate ((offset_ , 0 , 0 ), inplace = True )
273+ else :
274+ print ("Boundary points not translated" )
176275
177276 plotter .render ()
178- time .sleep (0.1 )
277+ # time.sleep(0.1)
179278
180279 return
181280
@@ -184,6 +283,7 @@ def create_mesh(step):
184283 plotter = pv .Plotter ()
185284
186285 position_file = "buffers/position_buffer.txt" # can be overwritten by arg
286+ report_file = None
187287
188288 if not os .path .isfile (position_file ):
189289 position_file = (
@@ -198,14 +298,25 @@ def create_mesh(step):
198298 print ("Run with -b to display boundary box" )
199299
200300 if len (sys .argv ) > 1 and os .path .isfile (sys .argv [1 ]):
201- position_file = sys .argv [1 ]
301+ if "json" in sys .argv [1 ]:
302+ position_file = None
303+ report_file = sys .argv [1 ]
304+ else :
305+ position_file = sys .argv [1 ]
202306
203307 add_sibernetic_model (
204- plotter , position_file , swap_y_z = True , include_boundary = include_boundary
308+ plotter ,
309+ position_file ,
310+ report_file ,
311+ swap_y_z = True ,
312+ include_boundary = include_boundary ,
205313 )
206314 plotter .set_background ("white" )
207315 plotter .add_axes ()
208- # plotter.set_viewup([0, 0, 10])
316+ plotter .camera_position = "zx"
317+ plotter .camera .roll = 90
318+ plotter .camera .elevation = 45
319+ print (plotter .camera_position )
209320
210321 if "-nogui" not in sys .argv :
211322 plotter .show ()
0 commit comments