def _get_colour_range(self, min_value, max_value, config_heading): """Get the colour range for the chosen config heading, or revert back to the default one if it is invalid. """ try: colour_map = calculate_colour_map( CONFIG[config_heading]['ColourProfile']) except ValueError: colour_map = calculate_colour_map( CONFIG[config_heading]['ColourProfile'].default) return ColourRange(min_value, max_value, colour_map)
def clicks(self, last_session=False, click_type='Single', _cache_file=None): """Generate the click image.""" self._generate_start() #Attempt to load data from cache cache_data = self.cache_load(_cache_file) if cache_data is not None: (min_value, max_value), heatmap = cache_data skip_calculations = cache_data is not None if not skip_calculations: #Detect session information if last_session: clicks = self.data['Maps']['Session']['Click'][click_type] else: clicks = self.data['Maps']['Click'][click_type] lmb = CONFIG['GenerateHeatmap']['_MouseButtonLeft'] mmb = CONFIG['GenerateHeatmap']['_MouseButtonMiddle'] rmb = CONFIG['GenerateHeatmap']['_MouseButtonRight'] valid_buttons = [i for i, v in zip(('Left', 'Middle', 'Right'), (lmb, mmb, rmb)) if v] numpy_arrays = merge_resolutions(clicks, map_selection=valid_buttons)[1] width, height = CONFIG['GenerateImages']['_UpscaleResolutionX'], CONFIG['GenerateImages']['_UpscaleResolutionY'] (min_value, max_value), heatmap = arrays_to_heatmap(numpy_arrays, gaussian_size=gaussian_size(width, height), clip=1-CONFIG['Advanced']['HeatmapRangeClipping']) #Save cache if it wasn't generated if _cache_file is not None and not skip_calculations: self.cache_save(_cache_file, min_value, max_value, heatmap) #Convert each point to an RGB tuple try: colour_map = calculate_colour_map(CONFIG['GenerateHeatmap']['ColourProfile']) except ValueError: default_colours = _config_defaults['GenerateHeatmap']['ColourProfile'][0] colour_map = calculate_colour_map(default_colours) colour_range = ColourRange(min_value, max_value, colour_map) image_name = self.name.generate('Clicks', reload=True) image_output = Image.fromarray(convert_to_rgb(heatmap, colour_range)) if image_output is None: _print('No click data was found.') return None return self._generate_end(image_name, image_output, resize=True)
def tracks(self, last_session=False, _cache_file=None): """Generate the track image.""" self._generate_start() #Attempt to load data from cache cache_data = self.cache_load(_cache_file) if cache_data is not None: (min_value, max_value), numpy_arrays = cache_data skip_calculations = cache_data is not None if not skip_calculations: #Detect session information if last_session: session_start = self.data['Ticks']['Session']['Tracks'] else: session_start = None #Resize all arrays high_precision = CONFIG['GenerateImages']['HighPrecision'] (min_value, max_value), numpy_arrays = merge_resolutions( self.data['Maps']['Tracks'], session_start=session_start, high_precision=high_precision) #Save cache if it wasn't generated if _cache_file is not None and not skip_calculations: self.cache_save(_cache_file, min_value, max_value, numpy_arrays) #Convert each point to an RGB tuple try: colour_map = calculate_colour_map( CONFIG['GenerateTracks']['ColourProfile']) except ValueError: default_colours = _config_defaults['GenerateTracks'][ 'ColourProfile'][0] colour_map = calculate_colour_map(default_colours) colour_range = ColourRange(min_value, max_value, colour_map) image_name = self.name.generate('Tracks', reload=True) image_output = arrays_to_colour(colour_range, numpy_arrays) if image_output is None: _print('No tracks data was found.') return None return self._generate_end(image_name, image_output, resize=True)
def generate_coordinates(self, key_names={}): image = {'Fill': {}, 'Outline': [], 'Text': []} max_offset = {'X': 0, 'Y': 0} if CONFIG['GenerateKeyboard']['LinearMapping']: if CONFIG['GenerateKeyboard']['LinearPower'] != 1: mapping = 'exponential' else: mapping = 'linear' else: mapping = 'standard' use_time = CONFIG['GenerateKeyboard']['DataSet'].lower() == 'time' use_count = CONFIG['GenerateKeyboard']['DataSet'].lower() == 'count' #Setup the colour range if use_time: values = self.count_time.values() elif use_count: values = self.count_press.values() if mapping == 'standard': pools = sorted(set(values)) max_range = len(pools) + 1 lookup = {v: i + 1 for i, v in enumerate(pools)} lookup[0] = 0 else: max_range = max(values) if mapping == 'exponential': exponential = CONFIG['GenerateKeyboard']['LinearPower'] max_range **= exponential colours = calculate_colour_map( CONFIG['GenerateKeyboard']['ColourProfile']) colour_range = ColourRange(0, max_range, colours) #Decide on background colour #For now the options are black or while if any(i > 128 for i in colours[0][:3]): image['Background'] = self.colours['white']['Colour'] image['Shadow'] = self.colours['black']['Colour'] else: image['Background'] = self.colours['black']['Colour'] image['Shadow'] = self.colours['white']['Colour'] y_offset = IMAGE_PADDING y_current = 0 for i, row in enumerate(self.grid): x_offset = IMAGE_PADDING for values in row: x, y = values['Dimensions'] hide_background = False if values['Name'] is not None: count_time = self.count_time.get(values['Name'], 0) count_press = self.count_press.get(values['Name'], 0) if use_time: key_count = count_time elif use_count: key_count = count_press display_name = key_names.get(values['Name'], values['Name']) button_coordinates = KeyboardButton( x_offset, y_offset, x, y) #Calculate colour for key if values['CustomColour'] is None: if mapping == 'standard': fill_colour = colour_range[lookup[key_count]] elif mapping == 'exponential': fill_colour = colour_range[key_count**exponential] else: fill_colour = colour_range[key_count] else: if values['CustomColour'] == False: hide_background = True fill_colour = image['Background'] else: fill_colour = values['CustomColour'] #Calculate colour for border if get_luminance(*fill_colour) > 128: text_colour = self.colours['black']['Colour'] else: text_colour = self.colours['white']['Colour'] #Store values _values = { 'Offset': (x_offset, y_offset), 'KeyName': display_name, 'Counts': { 'press': count_press, 'time': count_time }, 'Colour': text_colour, 'Dimensions': values['DimensionMultipliers'] } image['Text'].append(_values) if not values['HideBorder']: image['Outline'] += button_coordinates.outline( KEY_BORDER) if not hide_background: try: image['Fill'][ fill_colour] += button_coordinates.fill() except KeyError: image['Fill'][ fill_colour] = button_coordinates.fill() x_offset += KEY_PADDING + x y_current = max(y_current, y) #Decrease size of empty row if row: y_offset += KEY_SIZE + KEY_PADDING else: y_offset += (KEY_SIZE + KEY_PADDING) // 2 max_offset['X'] = max(max_offset['X'], x_offset) max_offset['Y'] = max(max_offset['Y'], y_offset) y_current -= KEY_SIZE width = max_offset['X'] + IMAGE_PADDING - KEY_PADDING + 1 height = max_offset[ 'Y'] + IMAGE_PADDING + y_current - KEY_PADDING * 2 + 1 + DROP_SHADOW_Y return ((width, height), image)