class PlotPanel(wx.Panel): """ The PlotPanel """ def __init__(self, parent, name=None, color=None, dpi=None, n_axes=1, **kwargs): # initialize Panel if 'id' not in iter(kwargs.keys()): kwargs['id'] = wx.ID_ANY if 'style' not in iter(kwargs.keys()): kwargs['style'] = wx.NO_FULL_REPAINT_ON_RESIZE wx.Panel.__init__(self, parent, **kwargs) self.SetMinSize((100, 40)) # The logging logger instance. loggerName = __name__ + "." + self.__class__.__name__ self.logger = logging.getLogger(loggerName) # The name of the plot panel. self.name = name # initialize matplotlib stuff self.figure = mpl.figure.Figure(None, dpi=dpi, facecolor='white') self.canvas = FigureCanvas(self, -1, self.figure) # The axes. self._axes = [] axes_height = 1 / n_axes for k in range(n_axes): self._axes.append( self.figure.add_axes([0, k * axes_height, 1, axes_height])) self.canvas.SetMinSize((30, 10)) self.SetBackgroundColour('white') # The axes backgrounds for blit animation. self.blit_backgrounds = [] # Add the canvas to the sizer. self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.EXPAND) self.SetSizer(self.sizer) self.canvas.Bind(wx.EVT_SET_FOCUS, self.on_set_focus) self.Bind(wx.EVT_SET_FOCUS, self.on_set_focus2) self.canvas.Bind(wx.EVT_KEY_DOWN, self.on_key_down) self.Bind(wx.EVT_KEY_DOWN, self.on_key_down) self.canvas.Bind(wx.EVT_KEY_UP, self.on_key_up) self.Bind(wx.EVT_KEY_UP, self.on_key_up) self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down) self.canvas.Bind(wx.EVT_LEFT_DOWN, self.on_left_down) @property def axes(self): ''' The axes of the panel. If only one axis is present, return the axes, otherwise return a list of axes. ''' if len(self._axes) == 1: return self._axes[0] else: return self._axes def on_wx_xlick(self, event): self.logger.debug("on_wx_xlick in plot_panel %s. event: %s", self.name, event) def on_set_focus(self, event): self.logger.debug("on_set_focus in plot_panel %s. event: %s", self.name, event) self.logger.debug("Event should propagate: %s", event.ShouldPropagate()) #event.ResumePropagation(1) event.Skip() def on_set_focus2(self, event): self.logger.debug("on_set_focus2 in plot_panel %s. event: %s", self.name, event) def on_key_down(self, event): self.logger.debug("on_key_down in plot_panel %s. event: %s", self.name, event) event.ResumePropagation(1) event.Skip() def on_key_up(self, event): self.logger.debug("on_key_up in plot_panel %s. event: %s", self.name, event) event.ResumePropagation(1) event.Skip() def on_left_down(self, event): self.logger.debug("on_left_down in plot_panel %s. event: %s", self.name, event) event.ResumePropagation(30) event.Skip() def set_color(self, rgbtuple=None): ''' Set figure and canvas colours to be the same. ''' if rgbtuple is None: rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() clr = [c / 255. for c in rgbtuple] self.figure.set_facecolor(clr) self.figure.set_edgecolor(clr) self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple)) self.canvas.Refresh() def set_n_axes(self, n_axes): ''' Set the number of axes provided by the plot panel. ''' # Delete the existing axes. for cur_ax in self._axes: self.figure.delaxes(cur_ax) self._axes = [] # Create the new number of axes. axes_height = old_div(1, n_axes) for k in range(n_axes): self._axes.append( self.figure.add_axes([0, k * axes_height, 1, axes_height])) def draw(self): ''' Draw the canvas to make the changes visible. ''' self.canvas.draw() def save_blit_background(self): ''' Save the axes background for animation. ''' self.blit_backgrounds = [] for cur_axes in self._axes: self.blit_backgrounds.append( self.canvas.copy_from_bbox(cur_axes.bbox)) def restore_blit_background(self): ''' Restore the axes background for animation. ''' for k, cur_bg in enumerate(self.blit_backgrounds): self.canvas.restore_region(cur_bg, bbox=self._axes[k].bbox) def draw_blit_artists(self, artists): ''' Draw the artist for animation. ''' for cur_artist in artists: for cur_line_artist in cur_artist.line_artist: cur_line_artist.axes.draw_artist(cur_line_artist) for cur_text_artist in cur_artist.text_artist: cur_text_artist.axes.draw_artist(cur_text_artist) def update_display(self): ''' Update the display of the docking frame. ''' assert False, 'The update_display method must be defined!'
class ParticleMotionFrame(wx.Frame): ''' ''' def __init__(self, parent=None, id=wx.ID_ANY, title='particle motion', size=(600, 600), dpi=90): ''' Initialize the instance. ''' wx.Frame.__init__(self, parent=parent, id=id, title=title, pos=wx.DefaultPosition, style=wx.DEFAULT_FRAME_STYLE) self.SetMinSize(size) # initialize matplotlib stuff self.figure = mpl.figure.Figure(None, dpi=dpi, facecolor='white') self.canvas = FigureCanvas(self, -1, self.figure) #self.grid = axesgrid.AxesGrid(self.figure, 111, # nrows_ncols = (2, 2), # axes_pad = 0, # label_mode = "1") self.axes = {} self.axes['xy'] = self.figure.add_subplot(111) self.axes['xy'].set_aspect('equal') self.divider = axesgrid.make_axes_locatable(self.axes['xy']) self.axes['yz'] = self.divider.append_axes("right", size="100%", pad=0, sharey=self.axes['xy']) self.axes['xz'] = self.divider.append_axes("bottom", size="100%", pad=0, sharex=self.axes['xy']) self.annotate_axes() self.canvas.SetMinSize((30, 10)) self.SetBackgroundColour('white') # Add the canvas to the sizer. self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.EXPAND) self.SetSizer(self.sizer) # The particle motion lines. self.lines = {} self.lines['xy'] = None self.lines['xz'] = None self.lines['yz'] = None # The particle motion start markers. self.start_markers = {} self.start_markers['xy'] = None self.start_markers['xz'] = None self.start_markers['yz'] = None # The feature annotation. self.feature_text = None def annotate_axes(self): ''' Annotate the axes. ''' self.axes['xy'].set_xlabel('x') self.axes['xy'].set_ylabel('y') self.axes['xy'].xaxis.set_label_position('top') self.axes['xy'].xaxis.set_tick_params(labeltop=False, labelbottom=False) self.axes['xz'].set_xlabel('x') self.axes['xz'].set_ylabel('z') self.axes['yz'].set_xlabel('z') self.axes['yz'].set_ylabel('y') self.axes['yz'].get_xaxis().set_label_position('top') self.axes['yz'].get_yaxis().set_label_position('right') self.axes['yz'].xaxis.set_tick_params(labeltop=False, labelbottom=False) self.axes['yz'].yaxis.set_tick_params(labelleft=False, labelright=True) def clear_axes(self): ''' Clear all plots in the axes. ''' for cur_key, cur_axes in self.axes.items(): if self.lines[cur_key] is not None: cur_axes.lines.remove(self.lines[cur_key]) del self.lines[cur_key] self.lines[cur_key] = None if self.start_markers[cur_key] is not None: cur_axes.lines.remove(self.start_markers[cur_key]) del self.start_markers[cur_key] self.start_markers[cur_key] = None def plot_xy(self, x_data, y_data, start_marker=False): ''' Plot the xy particle motion. ''' self.plot(x=x_data, y=y_data, mode='xy', start_marker=start_marker) def plot_xz(self, x_data, z_data, start_marker=False): ''' Plot the xy particle motion. ''' self.plot(x=x_data, y=z_data, mode='xz', start_marker=start_marker) def plot_yz(self, y_data, z_data, start_marker=False): ''' Plot the xy particle motion. ''' self.plot(x=z_data, y=y_data, mode='yz', start_marker=start_marker) def plot(self, x, y, mode, start_marker=False): ''' Plot data in the corresponding axes. ''' cur_axes = self.axes[mode] cur_line = self.lines[mode] if cur_line is None: cur_lines = cur_axes.plot(x, y, 'k') self.lines[mode] = cur_lines[0] else: cur_line.set_xdata(x) cur_line.set_ydata(y) if start_marker: cur_lines = cur_axes.plot(x[0], y[0], 'ro') self.start_markers[mode] = cur_lines[0] def set_feature_annotation(self, features): ''' ''' if self.feature_text is not None: self.axes['xz'].texts.remove(self.feature_text) azimuth = np.rad2deg(features['azimuth']) if azimuth < 0: azimuth = azimuth + 180 msg = "Polarization features:\n\n" msg += "polarization strength: %f" % features['pol_strength'] + '\n' msg += "ellipticity: %f" % features['ellipticity'] + '\n' msg += "apparent azimuth: %f / %f" % (azimuth, azimuth + 180) + "\n" msg += "apparent incidence: %f" % np.rad2deg( features['incidence']) + "\n" self.feature_text = self.axes['xz'].text( 1.1, 0.95, msg, verticalalignment='top', horizontalalignment='left', transform=self.axes['xz'].transAxes, size=10) def set_axes_limits(self): ''' Adjust the axes limits. ''' max_amp = [] for cur_line in self.lines.values(): cur_x_max = np.max(np.abs(cur_line.get_xdata())) cur_y_max = np.max(np.abs(cur_line.get_ydata())) max_amp.append(np.max([cur_x_max, cur_y_max])) max_amp = np.max(max_amp) for cur_axes in self.axes.values(): cur_axes.set_xlim((-max_amp, max_amp)) cur_axes.set_ylim((-max_amp, max_amp))
class PlotPanel(wx.Panel): """ The PlotPanel """ def __init__(self, parent, name=None, color=None, dpi=None, **kwargs): # initialize Panel if 'id' not in kwargs.keys(): kwargs['id'] = wx.ID_ANY if 'style' not in kwargs.keys(): kwargs['style'] = wx.NO_FULL_REPAINT_ON_RESIZE wx.Panel.__init__(self, parent, **kwargs) self.SetMinSize((100, 40)) # The logging logger instance. loggerName = __name__ + "." + self.__class__.__name__ self.logger = logging.getLogger(loggerName) # The name of the plot panel. self.name = name # initialize matplotlib stuff self.figure = mpl.figure.Figure(None, dpi=dpi, facecolor='white') self.canvas = FigureCanvas(self, -1, self.figure) self.axes = self.figure.add_axes([0, 0, 1, 1]) self.canvas.SetMinSize((30, 10)) self.SetBackgroundColour('white') # Add the canvas to the sizer. self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.EXPAND) self.SetSizer(self.sizer) self.canvas.Bind(wx.EVT_SET_FOCUS, self.on_set_focus) self.Bind(wx.EVT_SET_FOCUS, self.on_set_focus2) self.canvas.Bind(wx.EVT_KEY_DOWN, self.on_key_down) self.Bind(wx.EVT_KEY_DOWN, self.on_key_down) self.canvas.Bind(wx.EVT_KEY_UP, self.on_key_up) self.Bind(wx.EVT_KEY_UP, self.on_key_up) self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down) self.canvas.Bind(wx.EVT_LEFT_DOWN, self.on_left_down) def on_wx_xlick(self, event): self.logger.debug("on_wx_xlick in plot_panel %s. event: %s", self.name, event) def on_set_focus(self, event): self.logger.debug("on_set_focus in plot_panel %s. event: %s", self.name, event) self.logger.debug("Event should propagate: %s", event.ShouldPropagate()) #event.ResumePropagation(1) event.Skip() def on_set_focus2(self, event): self.logger.debug("on_set_focus2 in plot_panel %s. event: %s", self.name, event) def on_key_down(self, event): self.logger.debug("on_key_down in plot_panel %s. event: %s", self.name, event) event.ResumePropagation(1) event.Skip() def on_key_up(self, event): self.logger.debug("on_key_up in plot_panel %s. event: %s", self.name, event) event.ResumePropagation(1) event.Skip() def on_left_down(self, event): self.logger.debug("on_left_down in plot_panel %s. event: %s", self.name, event) event.ResumePropagation(30) event.Skip() def set_color(self, rgbtuple=None): ''' Set figure and canvas colours to be the same. ''' if rgbtuple is None: rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get() clr = [c / 255. for c in rgbtuple] self.figure.set_facecolor(clr) self.figure.set_edgecolor(clr) self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple)) self.canvas.Refresh() def draw(self): ''' Draw the canvas to make the changes visible. ''' self.canvas.draw() def update_display(self): ''' Update the display of the docking frame. ''' assert False, 'The update_display method must be defined!'
class MagcalPanel(wx.Panel): _status_markup_strings = { mavlink.MAG_CAL_NOT_STARTED: 'Not started', mavlink.MAG_CAL_WAITING_TO_START: 'Waiting to start', mavlink.MAG_CAL_RUNNING_STEP_ONE: 'Step one', mavlink.MAG_CAL_RUNNING_STEP_TWO: 'Step two', mavlink.MAG_CAL_SUCCESS: '<span color="blue">Success</span>', mavlink.MAG_CAL_FAILED: '<span color="red">Failed</span>', } _empty_color = '#7ea6ce' _filled_color = '#4680b9' def __init__(self, *k, **kw): super(MagcalPanel, self).__init__(*k, **kw) facecolor = self.GetBackgroundColour().GetAsString(wx.C2S_HTML_SYNTAX) fig = plt.figure(facecolor=facecolor, figsize=(1, 1)) self._canvas = FigureCanvas(self, wx.ID_ANY, fig) self._canvas.SetMinSize((300, 300)) self._id_text = wx.StaticText(self, wx.ID_ANY) self._status_text = wx.StaticText(self, wx.ID_ANY) self._completion_pct_text = wx.StaticText(self, wx.ID_ANY) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self._id_text) sizer.Add(self._status_text) sizer.Add(self._completion_pct_text) sizer.Add(self._canvas, proportion=1, flag=wx.EXPAND) self.SetSizer(sizer) ax = fig.add_subplot(111, axis_bgcolor=facecolor, projection='3d') self.configure_plot(ax) def configure_plot(self, ax): extra = .5 lim = grid.radius + extra ax.set_xlim3d(-lim, lim) ax.set_ylim3d(-lim, lim) ax.set_zlim3d(-lim, lim) ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') ax.invert_zaxis() ax.invert_xaxis() ax.set_aspect('equal') self._polygons_collection = Poly3DCollection( grid.sections_triangles, edgecolors='#386694', ) ax.add_collection3d(self._polygons_collection) def update_status_from_mavlink(self, m): status_string = self._status_markup_strings.get(m.cal_status, '???') self._status_text.SetLabelMarkup('<b>Status:</b> %s' % status_string, ) def mavlink_magcal_report(self, m): self.update_status_from_mavlink(m) self._completion_pct_text.SetLabel('') def mavlink_magcal_progress(self, m): facecolors = [] for i, mask in enumerate(m.completion_mask): for j in range(8): section = i * 8 + j if mask & 1 << j: facecolor = self._filled_color else: facecolor = self._empty_color facecolors.append(facecolor) self._polygons_collection.set_facecolors(facecolors) self._canvas.draw() self._id_text.SetLabelMarkup('<b>Compass id:</b> %d' % m.compass_id) self._completion_pct_text.SetLabelMarkup('<b>Completion:</b> %d%%' % m.completion_pct) self.update_status_from_mavlink(m) _legend_panel = None @staticmethod def legend_panel(*k, **kw): if MagcalPanel._legend_panel: return MagcalPanel._legend_panel p = MagcalPanel._legend_panel = wx.Panel(*k, **kw) sizer = wx.BoxSizer(wx.HORIZONTAL) p.SetSizer(sizer) marker = wx.Panel(p, wx.ID_ANY, size=(10, 10)) marker.SetBackgroundColour(MagcalPanel._empty_color) sizer.Add(marker, flag=wx.ALIGN_CENTER) text = wx.StaticText(p, wx.ID_ANY) text.SetLabel('Sections not hit') sizer.Add(text, border=4, flag=wx.ALIGN_CENTER | wx.LEFT) marker = wx.Panel(p, wx.ID_ANY, size=(10, 10)) marker.SetBackgroundColour(MagcalPanel._filled_color) sizer.Add(marker, border=10, flag=wx.ALIGN_CENTER | wx.LEFT) text = wx.StaticText(p, wx.ID_ANY) text.SetLabel('Sections hit') sizer.Add(text, border=4, flag=wx.ALIGN_CENTER | wx.LEFT) return p