def time_format(self, time_format): try: t = Timeline.app().current.strftime(time_format) # Throws a ValueError if supplied format is invalid self._time_format = time_format self.compute_bbox() except ValueError: post_message("Invalid time specifier", 1)
def RefreshTimeline(self): timeline = Timeline.app() current = timeline.current timeline.reset() self.UpdateTimeline(self.project.data_root) if current >= timeline.start and current <= timeline.end: timeline.current = current
def get_data(self, variable, date=None): if self._current_grid is not None and self._current_time == date and self._current_variable == variable: return self._current_grid.copy() path = os.path.abspath(self.path) if self._is_velma and self.time_info.is_temporal: if date is None: date = Timeline.app().current start = self.time_info.timestamps[0] end = self.time_info.timestamps[-1] if date < start: date = start elif date > end: date = end filename = "{}_{}".format(self.data_name, self._loop) if self._has_layer: filename = filename + '_{}'.format(self._layer) filename = filename + "_{}_{}".format(date.year, date.timetuple().tm_yday) if self._is_subday: filename = filename + '_{:2d}_{:2d}'.format(date.hour, date.minute) filename = "{}.asc".format(filename) path = os.path.join(os.path.dirname(path), filename) with rasterio.open(path) as src: self._current_grid = ma.array(src.read(1), mask=np.logical_not(src.read_masks(1))) self._current_variable = variable self._current_time = date return self._current_grid.copy()
def UpdateTimeline(self, root): timeline = Timeline.app() updated = False if root.is_data: time_info = root.data.time_info if time_info is not None and time_info.is_temporal: timestamps = time_info.timestamps if not timeline.enabled: timeline.start = timestamps[0] timeline.end = timestamps[-1] updated = True if timestamps[0] < timeline.start: timeline.start = timestamps[0] if timestamps[-1] > timeline.end: timeline.end = timestamps[-1] for t in timestamps: timeline.add_timestamp(t) elif root.is_folder: for child in root.children: updated = updated or self.UpdateTimeline(child) return updated
def ApplyFilter(self): timeline = Timeline.app() start = wx.wxdate2pydate(self.start_ctrl.GetDate()) end = wx.wxdate2pydate(self.end_ctrl.GetDate()) interval = self.interval_panel.interval time_span = timeline.end - timeline.start valid_range = start < end valid_interval = timeline.min_step <= interval < time_span if valid_range and valid_interval and timeline.enabled: timeline.filter_start = start timeline.filter_end = end timeline.filter_interval = interval timeline.use_filter = not (timeline.filter_start == timeline.start and timeline.filter_end == timeline.end and timeline.filter_interval == timeline.min_step) self._filter_has_changed = False self.RefreshTimeline() self.Refresh() return True else: if not valid_range: msg = "Invalid filter range - start date exceeds end date." elif not valid_interval: msg = "Invalid interval - interval is too large or too small." else: msg = "Invalid filter - unknown error." post_message(msg, 1) return False
def getData(self, dname, data): try: node = data[[n.data.data_name for n in data].index(dname)] except ValueError: return None date = Timeline.app().current thisdata = node.data.get_data(node.data.variables[0], date=date) return thisdata
def load(self, path, controller): with open(path) as f: data = json.load(f) # Migrate imported data to latest version if data['version'] < SAVE_FILE_VERSION: self.migrate(data) self.name = data['name'] self.data_root = FolderNode.load(data['data_root'], os.path.dirname(path)) controller.RefreshTimeline() Timeline.app().load_filter(data.get('timeline_filter', None)) self.visualization_root = FolderNode.load(data['visualization_root']) self.exporter = Exporter.load(data.get('exporter', None), self) self.is_dirty = False
def color_deltas(self, feature, data): """ Color features based on presence in the Envision Delta Array. Features absent from delta array are colored grey. """ if self.legend is None: return GREY envision_attribute = self.envision_style[self.current_attribute] shp_attribute = envision_attribute.get('column') legend = envision_attribute.get('legend') value = feature.get('properties').get(shp_attribute) idu = int(feature.get('id')) minmax = envision_attribute.get('minmax', None) string_value = '' try: if 'delta_array' not in data: data['delta_array'] = self.delta_data.get_data( shp_attribute, Timeline.app().current) data['index'] = 0 if data.get('delta_array') is None: self.feature_layer.set_color_function(self.color_shapes) post_message( 'Could not retrieve deltas, defaulting to base value.', 1) return self.color_shapes(feature, None) darray = data.get('delta_array') index = data.get('index') if darray[index].idu == idu: value += darray[index].new_value data['index'] += 1 else: if darray[index].idu < idu: while darray[index].idu <= idu: index += 1 data['index'] = index return GREY # Handle if we reached the end of the delta array except IndexError: return GREY if minmax is not None: for i, pair in enumerate(minmax): if pair[0] <= value <= pair[1]: string_value = legend[i].get('label') break color = self.legend.get_color(string_value) if color is None: color = GREY return color
def run(self): self.task.target = self.exporter.video_frames self.encoder.fps = self.exporter.video_fps self.task.progress = 0 self.task.status = Task.RUNNING timeline = Timeline.app() timeline.current = self.exporter.animation_start self.encoder.open(self.path, *self.exporter.size) delay = 0 # Give the main thread a chance to catch up for frame in range(self.exporter.video_frames): # Check if we have any reason to stop error = self.task.status == Task.SHOULD_STOP or not self.encoder.is_ok() if self.exporter.is_temporal: error |= not timeline.current <= self.exporter.animation_end if error: post_message("There was an error exporting the animation. Export may be incomplete.", 1) break # Update TaskDialog self.task.description = "Exporting frame {} of {}.".format(self.task.progress, self.task.target) # Update timeline if self.exporter.is_temporal: timeline.current = timeline.time_at_index( int(frame * self.exporter.animation_frames / self.exporter.video_frames) ) # Update flythroughs for item in self.exporter.items: if item.item_type == ExportItem.SCENE and item.flythrough is not None: local_fly_fps = item.flythrough.fps / self.exporter.flythrough_fps item.flythrough.update_camera_to_keyframe( (local_fly_fps * frame * item.flythrough.num_keyframes) / self.exporter.video_frames ) # Determine max time spend in main thread for rendering, and then add that delay t = time.time() self.sync_with_main(self.exporter.refresh_item_caches, block=True, delay=delay) elapsed = time.time() - t if delay == 0: delay = elapsed # Output items to encoder frame frame_bitmap = Image.new("RGB", self.exporter.size, (0, 0, 0)) for item in self.exporter.items: item.draw(frame_bitmap) self.encoder.write_frame(frame_bitmap, 1.0 / self.exporter.video_fps) if timeline.current > timeline.end: break self.task.inc_progress() self.encoder.finalize() self.task.status = Task.COMPLETE
def getData(self, dname, data): try: node = data[[n.data.data_name for n in data].index(dname)] except ValueError: return None variable = node.data.variables[0] stats = node.data.variable_stats(variable) date = Timeline.app().current thisdata = node.data.get_data(variable, date=date) return {'name': dname, 'data': thisdata, 'min': stats.min_value, 'max': stats.max_value}
def OnReset(self, event): # Reset timeline filter to start and finish timeline = Timeline.app() timeline.filter_start = timeline.start timeline.filter_end = timeline.end timeline.filter_interval = timeline.min_step self.interval_panel.interval = timeline.filter_interval self._filter_has_changed = False self.RefreshTimeline() self.Refresh()
def UpdateFromTimeline(self): timeline = Timeline.app() self._filter_has_changed = False self.start_ctrl.SetDateRange(wx.pydate2wxdate(timeline.start), wx.pydate2wxdate(timeline.end)) self.start_ctrl.SetDate(wx.pydate2wxdate(timeline.filter_start)) self.end_ctrl.SetDateRange(wx.pydate2wxdate(timeline.start), wx.pydate2wxdate(timeline.end)) self.end_ctrl.SetDate(wx.pydate2wxdate(timeline.filter_end)) self.interval_panel.interval = timeline.filter_interval self.Refresh()
def filter_histogram(self): if self.attribute_data is not None: variable = self._attribute.selected stats = self.attribute_data.variable_stats(variable) return Histogram(self.attribute_data.get_data( variable, Timeline.app().current), min_value=stats.min_value, max_value=stats.max_value, nodata_value=stats.nodata_value) else: return Histogram()
def UpdateEnabledInputs(self): timeline = Timeline.app() if timeline.enabled: maxstep = timeline.end - timeline.start minstep = timeline.min_step self.days.Enable(maxstep > datetime.timedelta(1, 0, 0) or datetime.timedelta(1, 0, 0) < minstep) self.seconds.Enable(maxstep > datetime.timedelta(0, 1, 0) or datetime.timedelta(1, 0, 0) < minstep) else: self.days.Disable() self.seconds.Disable()
def __init__(self, parent, id): super().__init__(parent, id) self.SetMinSize(wx.Size(200, 40)) self.timeline_ctrl = TimelineCtrl(self, wx.ID_ANY, Timeline.app()) self.playback_options_frame = PlaybackOptionsFrame(self, wx.ID_ANY) sizer = wx.BoxSizer(wx.HORIZONTAL) self.SetSizer(sizer) self.step_to_beginning_button = StaticBitmapButton(self, wx.ID_ANY, get_resource_bitmap('step_to_beginning_button.png'), wx.DefaultPosition, wx.Size(20, 20)) self.step_backward_button = StaticBitmapButton(self, wx.ID_ANY, get_resource_bitmap('step_backward_button.png'), wx.DefaultPosition, wx.Size(20, 20)) self.play_button = StaticBitmapButton(self, wx.ID_ANY, get_resource_bitmap('play_button.png'), wx.DefaultPosition, wx.Size(20, 20)) self.step_forward_button = StaticBitmapButton(self, wx.ID_ANY, get_resource_bitmap('step_forward_button.png'), wx.DefaultPosition, wx.Size(20, 20)) self.step_to_end_button = StaticBitmapButton(self, wx.ID_ANY, get_resource_bitmap('step_to_end_button.png'), wx.DefaultPosition, wx.Size(20, 20)) self.playback_options_button = StaticBitmapButton(self, wx.ID_ANY, get_resource_bitmap('playback_options_button.png'), wx.DefaultPosition, wx.Size(20, 20)) self.step_to_beginning_button.SetToolTip("Step to beginning") self.step_backward_button.SetToolTip("Step backward one frame") self.play_button.SetToolTip("Play animation") self.step_forward_button.SetToolTip("Step forward one frame") self.step_to_end_button.SetToolTip("Step to end") self.playback_options_button.SetToolTip("Expand playback options") sizer.Add(self.step_to_beginning_button, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) sizer.Add(self.step_backward_button, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) sizer.Add(self.play_button, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) sizer.Add(self.step_forward_button, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) sizer.Add(self.step_to_end_button, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) sizer.Add(self.timeline_ctrl, 1, wx.LEFT, 8) sizer.Add(self.playback_options_button, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 5) self.play_bitmap = get_resource_bitmap('play_button.png') self.pause_bitmap = get_resource_bitmap("pause_button.png") self.timer = wx.Timer(self, wx.ID_ANY) self._playing = False self.step_to_beginning_button.Bind(wx.EVT_BUTTON, self.OnStepToBeginningButton) self.step_backward_button.Bind(wx.EVT_BUTTON, self.OnStepBackwardButton) self.play_button.Bind(wx.EVT_BUTTON, self.OnPlayButton) self.step_forward_button.Bind(wx.EVT_BUTTON, self.OnStepForwardButton) self.step_to_end_button.Bind(wx.EVT_BUTTON, self.OnStepToEndButton) self.playback_options_button.Bind(wx.EVT_BUTTON, self.OnPlaybackOptionsButton) self.Bind(wx.EVT_TIMER, self.OnTimer) self.Fit()
def get_identify_detail(self, point: Vector3) -> Optional[Dict]: if self.terrain_data is not None: res = self.terrain_data.resolution cell_x = int(round((point.y / res))) cell_y = int(round((point.x / res))) terrain_attr = self._elevation_attribute.selected terrain_ref = self.terrain_data.get_data(terrain_attr) if self.attribute_data is not None: attribute_ref = self.attribute_data.get_data( self._attribute.selected, Timeline.app().current) attr_height, attr_width = attribute_ref.shape if 0 <= cell_x < attr_width and 0 <= cell_y < attr_height: result = OrderedDict() result['Point'] = "{}, {}".format(cell_x, cell_y) result['Value'] = attribute_ref[cell_y, cell_x] result['Height'] = terrain_ref[cell_y, cell_x] if self.flow_dir_data is not None: flow_dir_ref = self.flow_dir_data.get_data( self.flow_dir_data.variables[0]) direction = flow_dir_ref[cell_y, cell_x] result['Flow Direction (input)'] = direction degrees = 45.0 + 45.0 * direction result[ 'Flow Direction (degrees)'] = degrees if degrees < 360.0 else degrees - 360.0 if self.flow_acc_data is not None: result[ 'Flow Accumulation'] = self.flow_acc_data.get_data( self.flow_acc_data.variables[0])[cell_y, cell_x] self.selected_point = (cell_x, cell_y) self._needs_boundaries = True self.refresh() return result self.selected_point = (-1, -1) self._needs_boundaries = True self.refresh() return None
def get_data(self, variable, date=None): if variable != self._current_variable: # read data from disk with Dataset(self.path, 'r') as ds: slice_to_read = slice(None) # If it has a time dimension but no coord var we treat it as non-temporal if len(ds.variables[variable].shape) == 3 and not self.time_info.is_temporal: slice_to_read = -1 self._current_grid = ds.variables[variable][slice_to_read] self._current_variable = variable slice_to_return = slice(None) if self.time_info.is_temporal: if date is None: date = Timeline.app().current slice_to_return = min([i for i in enumerate(self.time_info.timestamps)], key=lambda d: abs(d[1] - date))[0] return self._current_grid[slice_to_return]
def save(self, path): if os.path.exists(path): os.remove(path) self.name = os.path.split(path)[-1] data = { 'version': SAVE_FILE_VERSION, 'name': self.name, 'data_root': self.data_root.serialize(path), 'visualization_root': self.visualization_root.serialize(), 'exporter': self.exporter.serialize(), 'timeline_filter': Timeline.app().serialize_filter() } with open(path, 'w') as f: json.dump(data, f) self.is_dirty = False
def _update_terrain_color(self): if self.terrain_mesh is not None: shader = self.terrain_mesh.shader if self.terrain_data and self.attribute_data: shader.has_color = True # Retrieve color layer attribute = self._attribute.selected data = self.attribute_data.get_data(attribute, Timeline.app().current) if type(data) is numpy.ma.MaskedArray: data = data.data color_stats = self.attribute_data.variable_stats(attribute) if color_stats.nodata_value: shader.nodata_value = color_stats.nodata_value self.terrain_mesh.geometry.values = data post_redisplay() else: shader.has_color = False
def refresh_cache(self): if self.item_type == self.TIMESTAMP: self.compute_bbox() # Timestamp label changes based on current time snapshot = Image.new("RGBA", self.size, (0, 0, 0, 0)) draw = ImageDraw.Draw(snapshot) if self.item_type == self.SCENE: if self.use_flythrough_camera: snapshot = self.flythrough.camera.render_to_bitmap(*self.size) else: snapshot = self.camera.render_to_bitmap(*self.size) elif self.item_type == self.LEGEND and self.viz_plugin is not None: snapshot = self.viz_plugin.get_legend(*self.size) elif self.item_type == self.VISUALIZATION and self.viz_plugin is not None: snapshot = self.viz_plugin.visualize(*self.size, back_thread=False) elif self.item_type == self.LABEL: draw.text((0, 0), self.label, font=self._font) elif self.item_type == self.TIMESTAMP: draw.text((0, 0), Timeline.app().current.strftime(self._time_format), font=self._font) self.cache = snapshot
def __init__(self, parent, id, timeline=None): super().__init__(parent, id, style=wx.BORDER_NONE) if timeline is None: timeline = Timeline.app() self.timeline = timeline self._scrub_time = None self.animation_speed = 1 self.live_update = False self._uniform_time_intervals = False self._dragging = False self.px_per_step = None self._calculate_px_ratio() self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.Bind(wx.EVT_MOTION, self.OnMouseMove) self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnLoseCapture) self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
def get_zonal_stats_from_feature( self, feature: LinearRing) -> List[Optional[Dict]]: results = [] if self.terrain_data: # Normalize feature coordinates to terrain resolution t_res = self.terrain_data.resolution normalized_coords = [(p[0] / t_res, p[1] / t_res) for p in feature.coords] for plugin in (x for x in (self.terrain_data, self.attribute_data, self.flow_dir_data, self.flow_dir_data) if x is not None): if plugin is self.terrain_data: var = self._elevation_attribute.selected elif plugin is self.attribute_data: var = self._attribute.selected else: var = '' raster = plugin.get_data(var, Timeline.app().current) affine = plugin.affine var_stats = plugin.variable_stats(var) nodata = var_stats.nodata_value feat = Polygon( *[[transform.xy(affine, *p) for p in normalized_coords]]) # Transform normalized raster coordinates to CRS of raster to query and obtain results result = zonal_stats(feat, raster, affine=affine, nodata=nodata, add_stats=self.zonal_stats)[0] result['Name'] = plugin.data_name results.append(result) return results
def OnWindowMenu(self, event): event_id = event.GetId() if event_id == wx.ID_ABOUT: self.OnAboutMenuItem(event) elif event_id == wx.ID_EXIT: self.main_window.Close() elif event_id == MainWindow.MENU_FILE_NEW: self.main_window.project_controller.NewProject() self.main_window.options_panel.options = None self.export_controller.RefreshExporter() self.export_controller.Reset() elif event_id == MainWindow.MENU_FILE_OPEN: self.main_window.project_controller.LoadProjectFromDialog() self.export_controller.RefreshExporter() elif event_id == MainWindow.MENU_FILE_SAVE: self.main_window.project_controller.SaveProject() elif event_id == MainWindow.MENU_FILE_SAVEAS: self.main_window.project_controller.SaveProjectAs() elif event_id == MainWindow.MENU_FILE_ADDDATA: self.main_window.project_controller.AddDataFromFile(None) elif event_id == MainWindow.MENU_VIEW_ADD_VIEWER: self.main_window.viewer_container_panel.AddViewer() elif event_id == MainWindow.MENU_VIEW_REMOVE_VIEWER: self.main_window.viewer_container_panel.RemoveViewer() elif event_id == MainWindow.MENU_VIEW_ADD_GRAPH: self.main_window.AddGraphPanel() elif event_id == MainWindow.MENU_VIEW_REMOVE_GRAPH: self.main_window.RemoveGraphPanel() elif event_id == MainWindow.MENU_VIEW_COLLAPSE: self.main_window.ToggleProjectPanel() elif event_id == MainWindow.MENU_EXPORT_EXPORT: self.export_controller.SetExportWindow( self.GetDefaultExporter(True)) self.export_controller.ShowWindow() elif event_id == MainWindow.MENU_EXPORT_CURRENT_COPY: self.RenderCurrentViewToClipboard() elif event_id == MainWindow.MENU_EXPORT_CURRENT_SAVE: self.RenderCurrentViewToFile() elif event_id == MainWindow.MENU_FLYTHROUGH_GENERATE: all_scenes = self.main_window.project_controller.project.all_scenes selector = FlythroughSceneSelector(all_scenes, None, wx.ID_ANY) if selector.ShowModal() == wx.ID_OK: selection = selector.GetSceneChoice() for i in range(len(all_scenes)): if i == selection: self.main_window.project_controller.AddFlythrough( all_scenes[i]) elif event_id == MainWindow.MENU_SYNC_CAMERAS: sync = self.main_window.GetToolBar().FindById( MainWindow.MENU_SYNC_CAMERAS).IsToggled() self.main_window.viewer_container_panel.SyncAllCameras(sync, True) elif event_id == MainWindow.MENU_OPEN_TIMELINE_FILTER: if Timeline.app().enabled: self.time_filter_window.Show() elif event_id == MainWindow.MENU_WINDOW_PLUGINS: self.plugins_window.Show() self.plugins_window.Raise() elif event_id == MainWindow.MENU_DEBUG: pass elif event_id == MainWindow.MENU_DEBUG_TOGGLE_WIREFRAME: self.main_window.viewer_container_panel.ToggleWireframe() elif event_id == MainWindow.MENU_DEBUG_TOGGLE_SELECTION_VIEW: pass # Todo elif event_id == MainWindow.MENU_HELP_REPORT_ISSUE: wx.LaunchDefaultBrowser( 'https://github.com/VISTAS-IVES/pyvistas/issues') elif event_id == MainWindow.MENU_LINREG: dlg = LinRegDialog(self.main_window) elif event_id == MainWindow.MENU_PCA: dlg = PcaDialog(self.main_window)
def OnExportFramesInput(self, event): input_frames = float(self.export_frames_ctrl.GetValue()) self.export_length_ctrl.ChangeValue( str(Timeline.app().num_timestamps / input_frames))
def OnExportLengthInput(self, event): if self.export_frames_ctrl.IsEnabled(): export_timestamps = Timeline.app( ).num_timestamps / self.export_length self.export_frames_ctrl.ChangeValue(str(export_timestamps))
def __init__(self, parent, id, enable_frames_input=True): super().__init__(parent, id, "Export Options", style=wx.CAPTION | wx.STAY_ON_TOP) main_panel = wx.Panel(self, wx.ID_ANY) encoder_static = wx.StaticText(main_panel, wx.ID_ANY, "Export As:") self.encoder_choice = wx.Choice(main_panel, wx.ID_ANY, size=wx.Size(220, -1)) self.encoder_choice.Append("Video File") self.encoder_choice.Append("Individual Image Files") self.encoder_choice.SetSelection(0) initial_export_length = 30.0 export_length_static = wx.StaticText(main_panel, wx.ID_ANY, "Length of export (in seconds):") self.export_length_ctrl = FloatCtrl(main_panel, wx.ID_ANY, value=initial_export_length, size=wx.Size(50, -1)) initial_export_timestamps = Timeline.app( ).num_timestamps / initial_export_length export_frames_static = wx.StaticText(main_panel, wx.ID_ANY, "Timestamps per second:") self.export_frames_ctrl = FloatCtrl(main_panel, wx.ID_ANY, value=initial_export_timestamps, size=wx.Size(50, -1)) self.export_frames_ctrl.Enable(enable_frames_input) main_sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(main_sizer) main_panel_sizer = wx.BoxSizer(wx.VERTICAL) main_panel.SetSizer(main_panel_sizer) main_panel_sizer.Add(encoder_static) main_panel_sizer.Add(self.encoder_choice, 0, wx.EXPAND) export_length_sizer = wx.BoxSizer(wx.HORIZONTAL) export_length_sizer.Add(export_length_static, 0, wx.RIGHT, 5) export_length_sizer.AddStretchSpacer(2) export_length_sizer.Add(self.export_length_ctrl, 0, wx.RIGHT, 5) main_panel_sizer.Add(export_length_sizer, 0, wx.ALL | wx.EXPAND, 10) export_frames_sizer = wx.BoxSizer(wx.HORIZONTAL) export_frames_sizer.Add(export_frames_static, 0, wx.RIGHT, 5) export_frames_sizer.AddStretchSpacer(2) export_frames_sizer.Add(self.export_frames_ctrl, 0, wx.RIGHT, 5) main_panel_sizer.Add(export_frames_sizer, 0, wx.ALL | wx.EXPAND, 10) main_sizer.Add(main_panel, 1, wx.EXPAND | wx.ALL, 5) main_sizer.Add(self.CreateButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND | wx.ALL, 5) self.export_length_ctrl.Bind(EVT_FLOAT, self.OnExportLengthInput) self.export_frames_ctrl.Bind(EVT_FLOAT, self.OnExportFramesInput) self.Fit()
def RefreshTimeline(self): post_timeline_change(Timeline.app().current, TimelineEvent.VALUE_CHANGED)
def GetDefaultExporter(self, add_labels=False): exporter = Exporter() viewerpanels = self.main_window.viewer_container_panel.GetAllViewerPanels( ) x_offset = 0 y_offset = 0 prev_height = 0 i = 0 num_columns = self.main_window.viewer_container_panel.num_columns for panel in viewerpanels: if i % num_columns == 0: x_offset = 0 y_offset = prev_height prev_height = 0 export_item = ExportItem(ExportItem.SCENE, (x_offset, y_offset), panel.GetSize().Get()) export_item.camera = panel.camera for node in self.main_window.project_controller.project.all_scenes: if panel.camera.scene is node.scene: export_item.project_node_id = node.node_id exporter.add_item(export_item) if add_labels: label = ExportItem(ExportItem.LABEL) label.size = (100, 100) label.label = export_item.camera.scene.name label.position = (int(x_offset + export_item.size[0] / 5 - 50), int(y_offset + export_item.size[1] / 5)) exporter.add_item(label) timestamp = ExportItem(ExportItem.TIMESTAMP) timestamp.time_format = Timeline.app().time_format timestamp.position = (int(x_offset + export_item.size[0] / 2 - timestamp.size[0] / 2), int(y_offset + export_item.size[1] / 5)) exporter.add_item(timestamp) x_offset += export_item.size[0] + PADDING prev_height = max(prev_height, export_item.size[1] + PADDING) i += 1 break x_offset = 0 y_offset = prev_height for panel in self.main_window.graph_panels: if panel.visualization is not None: node = self.main_window.project_controller.project.find_visualization_node( panel.visualization) export_item = ExportItem(ExportItem.VISUALIZATION, (x_offset, y_offset), panel.GetSize().Get()) export_item.viz_plugin = panel.visualization export_item.project_node_id = node.node_id exporter.add_item(export_item) y_offset += export_item.size[1] + PADDING exporter.fit_to_items() return exporter
def render(self, width, height): if self.data is None: return grid = self.data.get_data(self.attribute_option.selected, Timeline.app().current) background_color = self.bg_color_option.value.rgb.rgb_list label_color = self.label_color_option.value.rgb.rgb_list show_labels = self.labels_option.value num_categories = self.num_categories.value categories = self.categories_group.flat_list unique_values = dict(zip(*numpy.unique(grid, return_counts=True))) # dictionary of unique values to count values = list() colors = list() labels = list() for i in range(num_categories): try: value, label, color, _ = [opt.value for opt in categories[i*4:i*4+4]] except: continue # Bail on this index, the viz is probably updating if label == '': label = value if value in unique_values: values.append(unique_values[value]) else: values.append(0) colors.append(color.rgb.rgb_list) labels.append(label) indices = numpy.arange(len(values)) values = tuple(values) labels = tuple(labels) fig = pyplot.figure( figsize=(width / 100, height / 100), dpi=100, tight_layout=True, facecolor=self.bg_color_option.value.rgb.rgb_list ) try: ax = fig.add_subplot(1, 1, 1, facecolor=background_color) ax.margins(1 / width, 1 / height) bars = ax.bar(indices, values, color='r') for b in indices: bars[b].set_color(colors[b]) # Set unique colors here # add some text for labels, title and axes ticks ax.set_xticks(indices) ax.set_xticklabels(tuple(labels)) # labels go here ax.get_xaxis().set_visible(show_labels) ax.tick_params(color=label_color) for spine in ('left', 'bottom'): ax.spines[spine].set_color(label_color) for label in ax.get_xticklabels() + ax.get_yticklabels(): label.set_color(label_color) max_value = max(values) # attach a text label within each bar displaying the count for i, rect in enumerate(bars): count = rect.get_height() above = count < max_value / 2 label_height = count + 5 if above else count * 0.5 va = 'bottom' if above else 'center' bg_color = background_color if above else colors[i] bar_label_color = (0, 0, 0) if sum([x * 255 for x in bg_color]) > 384 else (1, 1, 1) ax.text(rect.get_x() + rect.get_width() / 2., label_height, '%d' % int(count), ha='center', va=va, color=bar_label_color) return self.fig_to_pil(fig).resize((width, height)) finally: pyplot.close(fig)
def __init__(self, parent): super().__init__(parent, wx.ID_ANY, "Timeline Filter", style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.FRAME_FLOAT_ON_PARENT) timeline = Timeline.app() self._filter_has_changed = False main_panel = wx.Panel(self, wx.ID_ANY) self.start_ctrl = wx.adv.CalendarCtrl(main_panel, wx.ID_ANY, date=wx.pydate2wxdate( timeline.start)) self.start_ctrl.SetDateRange(wx.pydate2wxdate(timeline.start), wx.pydate2wxdate(timeline.end)) self.end_ctrl = wx.adv.CalendarCtrl(main_panel, wx.ID_ANY, date=wx.pydate2wxdate( timeline.end)) self.end_ctrl.SetDateRange(wx.pydate2wxdate(timeline.start), wx.pydate2wxdate(timeline.end)) self.apply_button = wx.Button(main_panel, wx.ID_ANY, "Apply") self.apply_button.SetDefault() self.reset_button = wx.Button(main_panel, wx.ID_ANY, "Reset") main_sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(main_sizer) panel_sizer = wx.BoxSizer(wx.VERTICAL) main_panel.SetSizer(panel_sizer) start_sizer = wx.BoxSizer(wx.VERTICAL) start_label = wx.StaticText(main_panel, wx.ID_ANY, "Start Date") start_sizer.Add(start_label, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM, 10) start_sizer.Add(self.start_ctrl) end_sizer = wx.BoxSizer(wx.VERTICAL) end_label = wx.StaticText(main_panel, wx.ID_ANY, "End Date") end_sizer.Add(end_label, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM, 10) end_sizer.Add(self.end_ctrl) calendar_sizer = wx.BoxSizer(wx.HORIZONTAL) calendar_sizer.Add(start_sizer, 0, wx.EXPAND | wx.RIGHT, 10) calendar_sizer.Add(end_sizer, 0, wx.EXPAND | wx.LEFT, 10) panel_sizer.Add(calendar_sizer, 0, wx.EXPAND | wx.ALL, 10) self.interval_panel = TimeIntervalPanel(main_panel, wx.ID_ANY) panel_sizer.Add(self.interval_panel, 0, wx.ALIGN_CENTER_HORIZONTAL) button_sizer = wx.BoxSizer(wx.HORIZONTAL) button_sizer.Add(self.apply_button) button_sizer.Add(self.reset_button) panel_sizer.Add(button_sizer, 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, 10) main_sizer.Add(main_panel, 1, wx.EXPAND) self.CenterOnParent() self.Fit() self.Bind(wx.EVT_SHOW, self.OnShow) self.Bind(wx.EVT_CLOSE, self.OnClose) self.start_ctrl.Bind(wx.adv.EVT_CALENDAR_SEL_CHANGED, self.OnCalendar) self.end_ctrl.Bind(wx.adv.EVT_CALENDAR_SEL_CHANGED, self.OnCalendar) self.apply_button.Bind(wx.EVT_BUTTON, self.OnApply) self.reset_button.Bind(wx.EVT_BUTTON, self.OnReset) self.Refresh()