예제 #1
0
 def pre_mainloop(self):
     #print "HexoSpeller::pre_main_loop"
     self._model = HexoModel(PARAMS)
     self._model.add_arrow_length_observer(self)
     self._viz = HexoViz(self, VIZ_PARAMS)
     self._viz.hexo_controller = self
     self._viz.set_symbol_lists(self.symbol_list)
     if hasattr(ColorSchemes, VIZ_PARAMS["color_scheme"]):
         scheme_dictionary = getattr(ColorSchemes, VIZ_PARAMS["color_scheme"])
         VIZ_PARAMS.update(scheme_dictionary)
     # set some public variable that can be modified from the feedback controller GUI
     # set all variables for which there is a setter with the corresponding name
     for dict in [PARAMS, VIZ_PARAMS]:
         for key in dict.keys():
             if hasattr(self, 'set_'+key):
                 set_method = getattr(self, 'set_'+key)
                 set_method(dict[key])
예제 #2
0
 def pre_mainloop(self):
     #print "HexoSpeller::pre_main_loop"
     self._model = HexoModel(PARAMS)
     self._model.add_arrow_length_observer(self)
     self._viz = HexoViz(self, VIZ_PARAMS)
     self._viz.hexo_controller = self
     self._viz.set_symbol_lists(self.symbol_list)
     if hasattr(ColorSchemes, VIZ_PARAMS["color_scheme"]):
         scheme_dictionary = getattr(ColorSchemes, VIZ_PARAMS["color_scheme"])
         VIZ_PARAMS.update(scheme_dictionary)
     # set some public variable that can be modified from the feedback controller GUI
     # set all variables for which there is a setter with the corresponding name
     for dict in [PARAMS, VIZ_PARAMS]:
         for key in dict.keys():
             if hasattr(self, 'set_'+key):
                 set_method = getattr(self, 'set_'+key)
                 set_method(dict[key])
예제 #3
0
class HexoSpeller(MainloopFeedback):
    
    states = {
              "level_one": 1, # the hexagons contain groups of symbols, the group has to be picked first
              "level_two": 2, # the hexagons contain individual symbols
              }
    
    
    def init(self):
        self.send_parallel(Marker.feedback_init)
        self.logger.debug("HexoSpeller::init")
        self._last_tick_time = time.clock()
        self._state = self.states["level_one"]
        language_model_folder_path = self._create_language_model_folder_path()
        self.load_language_model(os.path.join(language_model_folder_path, PARAMS["language_model_file"]))
        self.spelled_text = []
        self._sub_list_probs = [] # probability values for each symbol sublist
        self._selected_symbol_idx = 0
        self._selected_symbol_sublist_idx = 0
        self._arrow_locked = False
        self._arrow_locked_time = None
        self.lock_arrow()
        self._control_signal = 0
        self._viz = None
        self._model = None
        
        
        
    def pre_mainloop(self):
        #print "HexoSpeller::pre_main_loop"
        self._model = HexoModel(PARAMS)
        self._model.add_arrow_length_observer(self)
        self._viz = HexoViz(self, VIZ_PARAMS)
        self._viz.hexo_controller = self
        self._viz.set_symbol_lists(self.symbol_list)
        if hasattr(ColorSchemes, VIZ_PARAMS["color_scheme"]):
            scheme_dictionary = getattr(ColorSchemes, VIZ_PARAMS["color_scheme"])
            VIZ_PARAMS.update(scheme_dictionary)
        # set some public variable that can be modified from the feedback controller GUI
        # set all variables for which there is a setter with the corresponding name
        for dict in [PARAMS, VIZ_PARAMS]:
            for key in dict.keys():
                if hasattr(self, 'set_'+key):
                    set_method = getattr(self, 'set_'+key)
                    set_method(dict[key])
    
    def post_mainloop(self):
        """ Tries to shut down the visualization. """
        self._viz.shut_down()
        
        
    def tick(self):
        """ Is called in each iteration of the main loop. This method determines how much time has passed
        between the current and the previous tick, and then delegates that information to the _model and the view
        via their tick(dt) methods. """
        if self._viz==None or self._model==None:
            return
        # determine how much time (in seconds) has passed between this and the previous tick
        current_time = time.clock()
        dt = current_time - self._last_tick_time
        self._last_tick_time = current_time
        # delegate the tick to the back end and the front end
        self._viz.tick(dt)
        self._model.tick(dt)
        self._model.set_control_signal(self.get_control_signal())
        # if the arrow is locked and the locking period is over, unlock it
        if self.is_arrow_locked():
            if current_time - self._arrow_locked_time > self.arrow_locked_duration:
                self.unlock_arrow()
        
    def play_tick(self):
        if not self.is_arrow_locked():
            self._model.play_tick()
        self._viz.play_tick()
    
    def pause_tick(self):
        self._viz.pause_tick()
        self._model.pause_tick()
        
    def on_control_event(self, data):
        self.logger.debug('on_control_event')
        self.set_control_signal(self._data)
        
    def on_interaction_event(self, data):
        self.logger.debug("on_interaction_event") 
        if type(data)==type({}):   
            # try to set the modified attributes
            for name in data.keys():
                # if we have the attribute and the respective setter
                if hasattr(self, name) and hasattr(self, "set_"+name):
                    set_method = getattr(self, "set_"+name)
                    new_value = data[name]
                    set_method(new_value)
    
    def on_play(self):
        self.send_parallel(Marker.status_change_to_play)
        MainloopFeedback.on_play(self)
    
    def on_pause(self):
        if self._MainloopFeedback__running and self._MainloopFeedback__paused:
            self.send_parallel(Marker.status_change_to_play)
        if self._MainloopFeedback__running and not self._MainloopFeedback__paused:
            self.send_parallel(Marker.status_change_to_pause)
        MainloopFeedback.on_pause(self)
        
    def on_stop(self):
        self.send_parallel(Marker.status_change_to_stop)
        MainloopFeedback.on_stop(self)
                    
        
    def get_selected_hexagon_index(self):
        """ Returns the hexagon that the arrow is currently pointing at. """
        return self._model.get_selected_hexagon_index()
    
    def get_arrow_length(self):
        return self._model.get_arrow_length()
    
    def get_phi_degrees(self):
        return self._model.get_phi_degrees()
    
    def arrow_at_max_length(self):
        """ To be called by the _model when the arrow has reached maximum length. """
        self.logger.debug("HexoFeedback::arrow_at_max_length")
        if self._state == self.states["level_one"]:
            self.send_parallel(Marker.hex_selected_level_one)
            # signal the GUI to change the content of the hexagons to single symbols
            selected_idx = self.get_selected_hexagon_index()
            self.send_parallel(Marker.selected_hex_level_one[selected_idx])
            self._viz.set_big_symbols(self.symbol_list[selected_idx], selected_idx)
            self._selected_symbol_sublist_idx = selected_idx
            # return the arrow to start length, but don't change the angle
            self.reset_arrow_model(reset_phi=False)
            # change to _state 'second selection'
            self._state = self.states["level_two"]
            self.lock_arrow()
            self._viz.start_state_change_animation()
        elif self._state == self.states["level_two"]:
            self.send_parallel(Marker.hex_selected_level_two)
            # get and store the selected symbol
            self.get_selected_symbol()
            self.update_symbol_list()
            # update the spelled word in the GUI
            self._viz.show_spelled_text(self.text_list_to_string(self.spelled_text))
            # signal the GUI to change the content of the hexagons back to multiple symbols
            self._viz.set_symbol_lists(self.symbol_list)
            # return the arrow to start angle and start length
            current_phi = self._model.get_phi_degrees()
            new_phi = (self.get_most_probable_hexagon_index()*60 + self.hex_pre_select_bias) % 360
            self.reset_arrow_model(reset_phi=True, phi=new_phi)
            self._state = self.states["level_one"]
            self.lock_arrow()
            self._viz.start_state_change_animation(rot_arrow=True, phi_start=current_phi, phi_end=new_phi)
        
    def reset_arrow_model(self, reset_phi=False, phi=0, control_signal=0):
        """ Resets the arrow length to initial length and the arrow angle and control signal value
         according to the given values. """
        self._model.reset_arrow_length()
        self._model.set_control_signal(control_signal)
        if reset_phi:
            self._model.reset_phi(phi)
        
    def get_selected_symbol(self):
        idx = self.get_selected_hexagon_index()
        self._selected_symbol_idx = idx
        self.send_parallel(Marker.selected_hex_level_two[idx])
        symbol = self._viz.get_selected_symbol(self._selected_symbol_sublist_idx, self._selected_symbol_idx)
        if symbol == self._language_model.delete_symbol:
            # if the delete symbol was selected and there is something to delete, pop the last character from the list
            if len(self.spelled_text) > 0:
                self.spelled_text.pop() 
        elif not symbol == None:
            # if the symbol is not None, attach it to the spelled Text
            self.spelled_text.append(symbol)
            # send a marker 
            idx = self._language_model.get_symbol_index(symbol)
            if not idx == None:
                self.send_parallel(Marker.selected_letter[idx])
            
    def get_most_probable_hexagon_index(self):
        """ Returns the index of the hexagon that contains the most probable next letter, based on what is already written. """
        return self._language_model.get_most_probable_symbol_sublist_index()
    
    def update_symbol_list(self):
        """ Update the order of symbols in the symbol list based on the spelled text. """
        spelled_text = self.text_list_to_string(self.spelled_text)
        self.symbol_list = self._language_model.update_symbol_list_sorting(spelled_text)

    def _create_language_model_folder_path(self):
        """ Creates a path that points to the folder that contains the language model file. 
        I assume that the lm files lie in a folder called "LanguageModels" which itself lies
        in the same folder as the HexoSpeller.py file, whose path is given by the __file__
        variable. """
        file_path = __file__ # file_path is now something like foo/bar/Feedbacks/HexoSpeller/HexoSpeller.py
        # remove the actual file name from the path by first reversing the string, then partitioning at the
        # last occourence of the path separator end reversing the tail of the partitioning 
        reversed_file_path = file_path[::-1]
        (_file_name, _sep, hexospeller_dir) = reversed_file_path.partition(os.path.sep)
        hexospeller_dir = hexospeller_dir[::-1] # reverse it, now in correct order
        # now complete the path to point to the language model directory
        lm_path = os.path.join(hexospeller_dir,"LanguageModels")
        return lm_path
       
    def load_language_model(self, file_name):
        """ Get the language _model, preferably from file. The path should be specified in params... """
        self._language_model = LanguageModel(file_name)
        self.symbol_list = self._language_model.get_symbol_list()
        
    def text_list_to_string(self, text_list):
        text = ''
        for c in text_list:
            text = text + c
        return text
    
    def set_control_signal(self, value):
        self._control_signal = value
    
    def get_control_signal(self):
        return self._control_signal
    
    def lock_arrow(self):
        self._arrow_locked = True
        self._arrow_locked_time = time.clock()
    
    def unlock_arrow(self):
        self._arrow_locked = False
    
    def is_arrow_locked(self):
        return self._arrow_locked
    
#================================================================================
#  Setter for the variables that should be 
#  setable from the feedback controller GUI
#================================================================================
    
    def set_hexagon_default_color(self, rgb):
        self.hexagon_default_color = rgb
        if not self._viz == None:
            r,g,b, = rgb
            self._viz.set_hexagon_color(r,g,b)
    
    def set_hexagon_highlight_color(self, rgb):
        self.hexagon_highlight_color = rgb
        if not self._viz == None:
            r,g,b, = rgb
            self._viz.set_hexagon_highlight_color(r, g, b)
        
    def set_hexagon_text_color(self, rgb):
        self.hexagon_text_color = rgb
        if not self._viz == None:
            r,g,b, = rgb
            self._viz.set_hexagon_text_color(r, g, b, alpha=1)
        
    def set_arrow_color(self, rgb):
        self.arrow_color = rgb
        if not self._viz == None:
            r,g,b, = rgb
            self._viz.set_arrow_color(r,g,b)
    
    def set_state_change_animation_duration(self, dur):
        self.state_change_animation_duration = dur
        if not self._viz == None:
            self._viz.params['state_change_animation_duration'] = dur
    
    def set_arrow_growth_time(self, time):
        self.arrow_growth_time = time
        if not self._model == None:
            self._model.params['arrow_growth_time'] = time
        
    def set_arrow_shrinkage_time(self, time):
        self.arrow_shrinkage_time = time
        if not self._model == None:
            self._model.params['arrow_shrinkage_time'] = time
        
    def set_arrow_rotation_time(self, time):
        self.arrow_rotation_time = time
        if not self._model == None:
            self._model.params['arrow_rotation_time'] = time
        
    def set_arrow_locked_duration(self, duration):
        self.arrow_locked_duration = duration
    
    def set_control_signal_arrow_rotation_threshold(self, t):
        self.control_signal_arrow_rotation_threshold = t
        if not self._model == None:
            self._model.params["control_signal_arrow_rotation_threshold"] = t
        if not self._viz == None:
            self._viz.set_arrow_rotation_threshold(t)
    
    def set_control_signal_arrow_growth_threshold(self, t):
        self.control_signal_arrow_growth_threshold = t
        if not self._model == None:
            self._model.params["control_signal_arrow_growth_threshold"] = t
        if not self._viz == None:
            self._viz.set_arrow_growth_threshold(t)
        
    def set_control_signal_bar_frame_color(self, rgb):
        self.control_signal_bar_frame_color = rgb
        if not self._viz == None:
            r,g,b = rgb
            self._viz.set_control_signal_bar_frame_color(r,g,b)

    def set_control_signal_bar_color(self, rgb):
        self.control_signal_bar_color = rgb
        if not self._viz == None:
            r,g,b = rgb
            self._viz.set_control_signal_bar_color(r,g,b)
        
    def set_lm_head_factors(self, head_factors):
        self._language_model.head_factors = head_factors
        self.lm_head_factors = head_factors
    
    def set_lm_letter_factor(self, letter_factor):
        self._language_model.letter_factor = letter_factor
        self.lm_letter_factor = letter_factor
        
    def set_lm_n_pred(self, n_pred):
        self._language_model.n_pred = n_pred
        self.lm_n_pred = n_pred
        
    def set_textboard_background_color(self, rgb):
        self.textboard_background_color = rgb
        if not self._viz == None:
            r,g,b = rgb
            self._viz.set_textboard_background_color(r, g, b)
        
    def set_textboard_frame_color(self, rgb):
        self.textboard_frame_color = rgb
        if not self._viz == None:
            r,g,b = rgb
            self._viz.set_textboard_frame_color(r, g, b)
    
    def set_textboard_text_color(self, rgb):
        self.textboard_text_color = rgb
        if not self._viz == None:
            r,g,b = rgb
            self._viz.set_textboard_text_color(r, g, b)
        
    def set_background_color(self, rgb):
        self.backgroud_color = rgb
        if not self._viz == None:
            r,g,b = rgb
            self._viz.set_background_color(r,g,b)
        
    def set_hex_pre_select_bias(self, v):
        self.hex_pre_select_bias = v
예제 #4
0
class HexoSpeller(MainloopFeedback):

    states = {
        "level_one":
        1,  # the hexagons contain groups of symbols, the group has to be picked first
        "level_two": 2,  # the hexagons contain individual symbols
    }

    def init(self):
        self.send_parallel(Marker.feedback_init)
        self.logger.debug("HexoSpeller::init")
        self._last_tick_time = time.clock()
        self._state = self.states["level_one"]
        language_model_folder_path = self._create_language_model_folder_path()
        self.load_language_model(
            os.path.join(language_model_folder_path,
                         PARAMS["language_model_file"]))
        self.spelled_text = []
        self._sub_list_probs = []  # probability values for each symbol sublist
        self._selected_symbol_idx = 0
        self._selected_symbol_sublist_idx = 0
        self._arrow_locked = False
        self._arrow_locked_time = None
        self.lock_arrow()
        self._control_signal = 0
        self._viz = None
        self._model = None

    def pre_mainloop(self):
        #print "HexoSpeller::pre_main_loop"
        self._model = HexoModel(PARAMS)
        self._model.add_arrow_length_observer(self)
        self._viz = HexoViz(self, VIZ_PARAMS)
        self._viz.hexo_controller = self
        self._viz.set_symbol_lists(self.symbol_list)
        if hasattr(ColorSchemes, VIZ_PARAMS["color_scheme"]):
            scheme_dictionary = getattr(ColorSchemes,
                                        VIZ_PARAMS["color_scheme"])
            VIZ_PARAMS.update(scheme_dictionary)
        # set some public variable that can be modified from the feedback controller GUI
        # set all variables for which there is a setter with the corresponding name
        for dict in [PARAMS, VIZ_PARAMS]:
            for key in dict.keys():
                if hasattr(self, 'set_' + key):
                    set_method = getattr(self, 'set_' + key)
                    set_method(dict[key])

    def post_mainloop(self):
        """ Tries to shut down the visualization. """
        self._viz.shut_down()

    def tick(self):
        """ Is called in each iteration of the main loop. This method determines how much time has passed
        between the current and the previous tick, and then delegates that information to the _model and the view
        via their tick(dt) methods. """
        if self._viz == None or self._model == None:
            return
        # determine how much time (in seconds) has passed between this and the previous tick
        current_time = time.clock()
        dt = current_time - self._last_tick_time
        self._last_tick_time = current_time
        # delegate the tick to the back end and the front end
        self._viz.tick(dt)
        self._model.tick(dt)
        self._model.set_control_signal(self.get_control_signal())
        # if the arrow is locked and the locking period is over, unlock it
        if self.is_arrow_locked():
            if current_time - self._arrow_locked_time > self.arrow_locked_duration:
                self.unlock_arrow()

    def play_tick(self):
        if not self.is_arrow_locked():
            self._model.play_tick()
        self._viz.play_tick()

    def pause_tick(self):
        self._viz.pause_tick()
        self._model.pause_tick()

    def on_control_event(self, data):
        self.logger.debug('on_control_event')
        self.set_control_signal(self._data)

    def on_interaction_event(self, data):
        self.logger.debug("on_interaction_event")
        if type(data) == type({}):
            # try to set the modified attributes
            for name in data.keys():
                # if we have the attribute and the respective setter
                if hasattr(self, name) and hasattr(self, "set_" + name):
                    set_method = getattr(self, "set_" + name)
                    new_value = data[name]
                    set_method(new_value)

    def on_play(self):
        self.send_parallel(Marker.status_change_to_play)
        MainloopFeedback.on_play(self)

    def on_pause(self):
        if self._MainloopFeedback__running and self._MainloopFeedback__paused:
            self.send_parallel(Marker.status_change_to_play)
        if self._MainloopFeedback__running and not self._MainloopFeedback__paused:
            self.send_parallel(Marker.status_change_to_pause)
        MainloopFeedback.on_pause(self)

    def on_stop(self):
        self.send_parallel(Marker.status_change_to_stop)
        MainloopFeedback.on_stop(self)

    def get_selected_hexagon_index(self):
        """ Returns the hexagon that the arrow is currently pointing at. """
        return self._model.get_selected_hexagon_index()

    def get_arrow_length(self):
        return self._model.get_arrow_length()

    def get_phi_degrees(self):
        return self._model.get_phi_degrees()

    def arrow_at_max_length(self):
        """ To be called by the _model when the arrow has reached maximum length. """
        self.logger.debug("HexoFeedback::arrow_at_max_length")
        if self._state == self.states["level_one"]:
            self.send_parallel(Marker.hex_selected_level_one)
            # signal the GUI to change the content of the hexagons to single symbols
            selected_idx = self.get_selected_hexagon_index()
            self.send_parallel(Marker.selected_hex_level_one[selected_idx])
            self._viz.set_big_symbols(self.symbol_list[selected_idx],
                                      selected_idx)
            self._selected_symbol_sublist_idx = selected_idx
            # return the arrow to start length, but don't change the angle
            self.reset_arrow_model(reset_phi=False)
            # change to _state 'second selection'
            self._state = self.states["level_two"]
            self.lock_arrow()
            self._viz.start_state_change_animation()
        elif self._state == self.states["level_two"]:
            self.send_parallel(Marker.hex_selected_level_two)
            # get and store the selected symbol
            self.get_selected_symbol()
            self.update_symbol_list()
            # update the spelled word in the GUI
            self._viz.show_spelled_text(
                self.text_list_to_string(self.spelled_text))
            # signal the GUI to change the content of the hexagons back to multiple symbols
            self._viz.set_symbol_lists(self.symbol_list)
            # return the arrow to start angle and start length
            current_phi = self._model.get_phi_degrees()
            new_phi = (self.get_most_probable_hexagon_index() * 60 +
                       self.hex_pre_select_bias) % 360
            self.reset_arrow_model(reset_phi=True, phi=new_phi)
            self._state = self.states["level_one"]
            self.lock_arrow()
            self._viz.start_state_change_animation(rot_arrow=True,
                                                   phi_start=current_phi,
                                                   phi_end=new_phi)

    def reset_arrow_model(self, reset_phi=False, phi=0, control_signal=0):
        """ Resets the arrow length to initial length and the arrow angle and control signal value
         according to the given values. """
        self._model.reset_arrow_length()
        self._model.set_control_signal(control_signal)
        if reset_phi:
            self._model.reset_phi(phi)

    def get_selected_symbol(self):
        idx = self.get_selected_hexagon_index()
        self._selected_symbol_idx = idx
        self.send_parallel(Marker.selected_hex_level_two[idx])
        symbol = self._viz.get_selected_symbol(
            self._selected_symbol_sublist_idx, self._selected_symbol_idx)
        if symbol == self._language_model.delete_symbol:
            # if the delete symbol was selected and there is something to delete, pop the last character from the list
            if len(self.spelled_text) > 0:
                self.spelled_text.pop()
        elif not symbol == None:
            # if the symbol is not None, attach it to the spelled Text
            self.spelled_text.append(symbol)
            # send a marker
            idx = self._language_model.get_symbol_index(symbol)
            if not idx == None:
                self.send_parallel(Marker.selected_letter[idx])

    def get_most_probable_hexagon_index(self):
        """ Returns the index of the hexagon that contains the most probable next letter, based on what is already written. """
        return self._language_model.get_most_probable_symbol_sublist_index()

    def update_symbol_list(self):
        """ Update the order of symbols in the symbol list based on the spelled text. """
        spelled_text = self.text_list_to_string(self.spelled_text)
        self.symbol_list = self._language_model.update_symbol_list_sorting(
            spelled_text)

    def _create_language_model_folder_path(self):
        """ Creates a path that points to the folder that contains the language model file. 
        I assume that the lm files lie in a folder called "LanguageModels" which itself lies
        in the same folder as the HexoSpeller.py file, whose path is given by the __file__
        variable. """
        file_path = __file__  # file_path is now something like foo/bar/Feedbacks/HexoSpeller/HexoSpeller.py
        # remove the actual file name from the path by first reversing the string, then partitioning at the
        # last occourence of the path separator end reversing the tail of the partitioning
        reversed_file_path = file_path[::-1]
        (_file_name, _sep,
         hexospeller_dir) = reversed_file_path.partition(os.path.sep)
        hexospeller_dir = hexospeller_dir[::
                                          -1]  # reverse it, now in correct order
        # now complete the path to point to the language model directory
        lm_path = os.path.join(hexospeller_dir, "LanguageModels")
        return lm_path

    def load_language_model(self, file_name):
        """ Get the language _model, preferably from file. The path should be specified in params... """
        self._language_model = LanguageModel(file_name)
        self.symbol_list = self._language_model.get_symbol_list()

    def text_list_to_string(self, text_list):
        text = ''
        for c in text_list:
            text = text + c
        return text

    def set_control_signal(self, value):
        self._control_signal = value

    def get_control_signal(self):
        return self._control_signal

    def lock_arrow(self):
        self._arrow_locked = True
        self._arrow_locked_time = time.clock()

    def unlock_arrow(self):
        self._arrow_locked = False

    def is_arrow_locked(self):
        return self._arrow_locked


#================================================================================
#  Setter for the variables that should be
#  setable from the feedback controller GUI
#================================================================================

    def set_hexagon_default_color(self, rgb):
        self.hexagon_default_color = rgb
        if not self._viz == None:
            r, g, b, = rgb
            self._viz.set_hexagon_color(r, g, b)

    def set_hexagon_highlight_color(self, rgb):
        self.hexagon_highlight_color = rgb
        if not self._viz == None:
            r, g, b, = rgb
            self._viz.set_hexagon_highlight_color(r, g, b)

    def set_hexagon_text_color(self, rgb):
        self.hexagon_text_color = rgb
        if not self._viz == None:
            r, g, b, = rgb
            self._viz.set_hexagon_text_color(r, g, b, alpha=1)

    def set_arrow_color(self, rgb):
        self.arrow_color = rgb
        if not self._viz == None:
            r, g, b, = rgb
            self._viz.set_arrow_color(r, g, b)

    def set_state_change_animation_duration(self, dur):
        self.state_change_animation_duration = dur
        if not self._viz == None:
            self._viz.params['state_change_animation_duration'] = dur

    def set_arrow_growth_time(self, time):
        self.arrow_growth_time = time
        if not self._model == None:
            self._model.params['arrow_growth_time'] = time

    def set_arrow_shrinkage_time(self, time):
        self.arrow_shrinkage_time = time
        if not self._model == None:
            self._model.params['arrow_shrinkage_time'] = time

    def set_arrow_rotation_time(self, time):
        self.arrow_rotation_time = time
        if not self._model == None:
            self._model.params['arrow_rotation_time'] = time

    def set_arrow_locked_duration(self, duration):
        self.arrow_locked_duration = duration

    def set_control_signal_arrow_rotation_threshold(self, t):
        self.control_signal_arrow_rotation_threshold = t
        if not self._model == None:
            self._model.params["control_signal_arrow_rotation_threshold"] = t
        if not self._viz == None:
            self._viz.set_arrow_rotation_threshold(t)

    def set_control_signal_arrow_growth_threshold(self, t):
        self.control_signal_arrow_growth_threshold = t
        if not self._model == None:
            self._model.params["control_signal_arrow_growth_threshold"] = t
        if not self._viz == None:
            self._viz.set_arrow_growth_threshold(t)

    def set_control_signal_bar_frame_color(self, rgb):
        self.control_signal_bar_frame_color = rgb
        if not self._viz == None:
            r, g, b = rgb
            self._viz.set_control_signal_bar_frame_color(r, g, b)

    def set_control_signal_bar_color(self, rgb):
        self.control_signal_bar_color = rgb
        if not self._viz == None:
            r, g, b = rgb
            self._viz.set_control_signal_bar_color(r, g, b)

    def set_lm_head_factors(self, head_factors):
        self._language_model.head_factors = head_factors
        self.lm_head_factors = head_factors

    def set_lm_letter_factor(self, letter_factor):
        self._language_model.letter_factor = letter_factor
        self.lm_letter_factor = letter_factor

    def set_lm_n_pred(self, n_pred):
        self._language_model.n_pred = n_pred
        self.lm_n_pred = n_pred

    def set_textboard_background_color(self, rgb):
        self.textboard_background_color = rgb
        if not self._viz == None:
            r, g, b = rgb
            self._viz.set_textboard_background_color(r, g, b)

    def set_textboard_frame_color(self, rgb):
        self.textboard_frame_color = rgb
        if not self._viz == None:
            r, g, b = rgb
            self._viz.set_textboard_frame_color(r, g, b)

    def set_textboard_text_color(self, rgb):
        self.textboard_text_color = rgb
        if not self._viz == None:
            r, g, b = rgb
            self._viz.set_textboard_text_color(r, g, b)

    def set_background_color(self, rgb):
        self.backgroud_color = rgb
        if not self._viz == None:
            r, g, b = rgb
            self._viz.set_background_color(r, g, b)

    def set_hex_pre_select_bias(self, v):
        self.hex_pre_select_bias = v