diff --git a/demo/MediaCtrl.py b/demo/MediaCtrl.py index 48f37270..d481571b 100644 --- a/demo/MediaCtrl.py +++ b/demo/MediaCtrl.py @@ -26,13 +26,9 @@ class TestPanel(wx.Panel): # Create some controls try: - backend = "" - if 'wxMSW' in wx.PlatformInfo: - # the default backend doesn't always send the EVT_MEDIA_LOADED - # event which we depend upon, so use a different backend by - # default for this demo. - backend = wx.media.MEDIABACKEND_QUICKTIME - + backend = "" # let MediaCtrl choose default backend + #backend=wx.media.MEDIABACKEND_DIRECTSHOW + #backend=wx.media.MEDIABACKEND_WMP10 self.mc = wx.media.MediaCtrl() ok = self.mc.Create(self, style=wx.SIMPLE_BORDER, szBackend=backend) @@ -42,6 +38,9 @@ class TestPanel(wx.Panel): self.Destroy() raise + # the following event is not sent with the Windows default backend + # MEDIABACKEND_DIRECTSHOW + # choose above e.g. MEDIABACKEND_WMP10 if this is a problem for you self.Bind(wx.media.EVT_MEDIA_LOADED, self.OnMediaLoaded) btn1 = wx.Button(self, -1, "Load File") @@ -100,15 +99,17 @@ class TestPanel(wx.Panel): def DoLoadFile(self, path): - self.playBtn.Disable() + if not self.mc.Load(path): wx.MessageBox("Unable to load %s: Unsupported format?" % path, "ERROR", wx.ICON_ERROR | wx.OK) + self.playBtn.Disable() else: self.mc.SetInitialSize() self.GetSizer().Layout() self.slider.SetRange(0, self.mc.Length()) + self.playBtn.Enable() def OnMediaLoaded(self, evt): self.playBtn.Enable() diff --git a/etg/_xml.py b/etg/_xml.py index d371f453..771f91fa 100644 --- a/etg/_xml.py +++ b/etg/_xml.py @@ -87,6 +87,12 @@ def run(): c.piBases = ['wx.Object'] c.find('GetEncoding').ignore() c.find('SetEncoding').ignore() + + c.find('AppendToProlog.node').transfer = True + c.find('DetachDocumentNode').transferBack = True + c.find('DetachRoot').transferBack = True + c.find('SetDocumentNode.node').transfer = True + c.find('SetRoot.node').transfer = True #----------------------------------------------------------------- diff --git a/wx/lib/plot.py b/wx/lib/plot.py index 4f62c161..1d68e63d 100644 --- a/wx/lib/plot.py +++ b/wx/lib/plot.py @@ -78,6 +78,14 @@ # - Added contect manager and decorator that gets and resets the pen before # and after a function call # - updated demo for new features +# +# May 27, 2016 Douglas Thor (doug.thor@gmail.com) +# - Added PolyBars and PolyHistogram classes +# - General Cleanup +# - Added demos for PolyBars and PolyHistogram +# - updated plotNN menu items status-bar text to be descriptive. +# - increased default size of demo +# - updated XSpec and YSpec to accept a list or tuple of (min, max) values. """ This is a simple light weight plotting module that can be used with @@ -890,6 +898,219 @@ class PolyMarker(PolyPoints): dc.DrawLineList(lines.astype(np.int32)) +class PolyBars(PolyPoints): + """ + Rectangles! + """ + _attributes = {'edgecolour': 'black', + 'edgewidth': 2, + 'edgestyle': wx.PENSTYLE_SOLID, + 'legend': '', + 'fillcolour': 'red', + 'fillstyle': wx.BRUSHSTYLE_SOLID, + 'barwidth': None + } + + def __init__(self, points, **attr): + """ + Creates PolyRectangle object + + :param `points`: sequence (array, tuple or list) of (x, y) points + that define the bar. + x: the centerline of the bar. + y: the value of the bar (from y=0) + :keyword `attr`: keyword attributes, default to: + + ================================= ================================ + 'edgecolour' = 'black' wx.Pen Colour: any wx.Colour + 'edgewidth' = 1 wx.Pen width + 'edgestyle' = wx.PENSTYLE_SOLID wx.Pen style + 'legend' = '' Line Legend to display + 'fillcolour' = 'red' wx.Brush fill color: any wx.Colour + 'fillstyle' = wx.BRUSHSTYLE_SOLID The fill style for the rectangle + 'barwidth' = None The bar width. None means 0 space + between bars + ================================= ================================ + + """ + PolyPoints.__init__(self, points, attr) + + def _scaleAndShift(self, data, scale=(1, 1), shift=(0, 0)): + """same as override method, but retuns a value.""" + scaled = scale * data + shift + return scaled + + def draw(self, dc, printerScale, coord=None): + """ Draw the bars """ + pencolour = self.attributes['edgecolour'] + penwidth = self.attributes['edgewidth'] * printerScale * self._pointSize[0] + penstyle = self.attributes['edgestyle'] + fillcolour = self.attributes['fillcolour'] + fillstyle = self.attributes['fillstyle'] + barwidth = self.attributes['barwidth'] + barwidth = 1. + + if not isinstance(pencolour, wx.Colour): + pencolour = wx.Colour(pencolour) + pen = wx.Pen(pencolour, penwidth, penstyle) + pen.SetCap(wx.CAP_BUTT) + if not isinstance(fillcolour, wx.Colour): + fillcolour = wx.Colour(fillcolour) + brush = wx.Brush(fillcolour, fillstyle) + dc.SetPen(pen) + dc.SetBrush(brush) + if coord is None: + rects = [] + if isinstance(barwidth, (int, float)): + pts = ((x, y, barwidth) for x, y in self.points) + else: + pts = ((x, y, w) for (x, y), w in zip(self.points, barwidth)) + + for x, y, w in pts: + # Change the point to a format that works for _scaleAndShift + rect = [[x - w / 2, y], # left, top + [x + w / 2, 0]] # right, bottom + + # Scale the points to the plot area + rect = self._scaleAndShift(rect, + self.currentScale, + self.currentShift) + + # Convert to (left, top, width, height) + rect = [rect[0][0], # X (left) + rect[0][1], # Y (top) + rect[1][0] - rect[0][0], # Width + rect[1][1] - rect[0][1]] # Height + + rects.append(rect) + + dc.DrawRectangleList(rects) + else: + dc.DrawLines(coord) # draw legend line + + def getSymExtent(self, printerScale): + """Width and Height of Marker""" + h = self.attributes['edgewidth'] * printerScale * self._pointSize[0] + w = 5 * h + return (w, h) + + +class PolyHistogram(PolyPoints): + """ + Histogram + + Special PolyBars where the bars span the binspec. + """ + + _attributes = {'edgecolour': 'black', + 'edgewidth': 3, + 'edgestyle': wx.PENSTYLE_SOLID, + 'legend': '', + 'fillcolour': wx.GREEN, + 'fillstyle': wx.BRUSHSTYLE_SOLID, + } + + def __init__(self, hist, binspec, **attr): + """ + Creates PolyHistogram object + + :param `hist`: sequence (array, tuple or list) of y values + that define the heights of the bars (same as 1st + returned parameter from ``np.histogram(data)``). + :param `binspec`: sequence of x values that define the edges of the + bins (same as 2nd returned parameter from + ``np.histogram(data)``). + len(binspec) must equal len(hist) + 1 + :keyword `attr`: keyword attributes, default to: + + ================================= ================================ + 'edgecolour' = 'black' wx.Pen Colour: any wx.Colour + 'edgewidth' = 3 wx.Pen width + 'edgestyle' = wx.PENSTYLE_SOLID wx.Pen style + 'legend' = '' Line Legend to display + 'fillcolour' = 'blue' wx.Brush fill color: any wx.Colour + 'fillstyle' = wx.BRUSHSTYLE_SOLID The fill style for the rectangle + ================================= ================================ + + """ + if len(binspec) != len(hist) + 1: + raise ValueError("Length of binspec must = length of hist + 1") + + self.hist = hist + self.binspec = binspec + + # need to create a series of points to be used by PolyPoints + import itertools + def pairwise(iterable): + "s -> (s0,s1), (s1,s2), (s2, s3), ..." + a, b = itertools.tee(iterable) + next(b, None) + return zip(a, b) + + self.bins = list(pairwise(self.binspec)) + x = [] + for pair in self.bins: + x.append(pair[0] + (pair[1] - pair[0])/2) + + points = list(zip(x, self.hist)) + + PolyPoints.__init__(self, points, attr) + + def _scaleAndShift(self, data, scale=(1, 1), shift=(0, 0)): + """same as override method, but retuns a value.""" + scaled = scale * data + shift + return scaled + + def draw(self, dc, printerScale, coord=None): + """ Draw the bars """ + pencolour = self.attributes['edgecolour'] + penwidth = self.attributes['edgewidth'] * printerScale * self._pointSize[0] + penstyle = self.attributes['edgestyle'] + fillcolour = self.attributes['fillcolour'] + fillstyle = self.attributes['fillstyle'] + + if not isinstance(pencolour, wx.Colour): + pencolour = wx.Colour(pencolour) + pen = wx.Pen(pencolour, penwidth, penstyle) + pen.SetCap(wx.CAP_BUTT) + if not isinstance(fillcolour, wx.Colour): + fillcolour = wx.Colour(fillcolour) + brush = wx.Brush(fillcolour, fillstyle) + dc.SetPen(pen) + dc.SetBrush(brush) + if coord is None: + + rects = [] + + for y, (low, high) in zip(self.hist, self.bins): + # Change the point to a format that works for _scaleAndShift + rect = [[low, y], # left, top + [high, 0]] # right, bottom + + # Scale the points to the plot area + rect = self._scaleAndShift(rect, + self.currentScale, + self.currentShift) + + # Convert to (left, top, width, height) + rect = [rect[0][0], # X (left) + rect[0][1], # Y (top) + rect[1][0] - rect[0][0], # Width + rect[1][1] - rect[0][1]] # Height + + rects.append(rect) + + dc.DrawRectangleList(rects) + else: + dc.DrawLines(coord) # draw legend line + + def getSymExtent(self, printerScale): + """Width and Height of Marker""" + h = self.attributes['edgewidth'] * printerScale * self._pointSize[0] + w = 5 * h + return (w, h) + + class BoxPlot(PolyPoints): """ Class to contain box plots @@ -3850,9 +4071,9 @@ def _draw8Objects(): Box plot """ data1 = np.array([912, 337, 607, 583, 512, 531, 558, 381, 621, 574, - 538, 577, 679, 415, 454, 417, 635, 319, 350, 183, - 863, 337, 607, 583, 512, 531, 558, 381, 621, 574, - 538, 577, 679, 415, 454, 417, 635, 319, 350, 97]) + 538, 577, 679, 415, 454, 417, 635, 319, 350, 183, + 863, 337, 607, 583, 512, 531, 558, 381, 621, 574, + 538, 577, 679, 415, 454, 417, 635, 319, 350, 97]) data2 = np.array([912, 337, 607, 583, 512, 531, 558, 381, 621, 574, 538, 532, 829, 82, 454, 417, 635, 319, 350, 183, 863, 337, 607, 583, 512, 531, 558, 866, 621, 574, @@ -3874,11 +4095,52 @@ def _draw8Objects(): "", "Value") +def _draw9Objects(): + """ + Histogram + + The following must be true: + len(bspec) = len(hist_data) + 1 + """ + + data = 2.25 * np.random.randn(50) + 3 + heights, bins = np.histogram(data, bins=10) + + hist_fixed_binsize = PolyHistogram(heights, bins) + + # Bins can also be arbitrary widths: + hist_variable_binsize = PolyHistogram( + [2, 3, 4, 6, 3], + [18, 19, 22, 25, 26, 27], + fillcolour=wx.BLUE, + edgewidth=2, + edgecolour=wx.RED, + ) + + return PlotGraphics( + [hist_fixed_binsize, hist_variable_binsize], + "Histogram with fixed binsize (left) and variable binsize (right)", + "Value", + "Count", + ) + + +def _draw10Objects(): + """ + A real bar graph + """ + bar_height = np.array([1, 5, 8, 16, 12, 15, 18, 23, 4, 7, 9, 6]) + bar_location = np.array([0, 2, 4, 6, 8, 10, 11, 12, 16, 20, 30]) + data = list(zip(bar_location, bar_height)) + bars = [PolyBars(data)] + + return PlotGraphics(bars, "Histogram", "XValue", "Count") + class TestFrame(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, - wx.DefaultPosition, (600, 400)) + wx.DefaultPosition, (800, 600)) # Now Create the menu bar and items self.mainmenu = wx.MenuBar() @@ -3903,22 +4165,36 @@ class TestFrame(wx.Frame): ### "Plot" Menu Items ############################################### # ------------------------------------------------------------------- menu = wx.Menu() - menu.Append(206, 'Draw1 - sin, cos', 'Draw plots1') + menu.Append(206, 'Draw1 - sin, cos', + 'Draw Sin and Cos curves') self.Bind(wx.EVT_MENU, self.OnPlotDraw1, id=206) - menu.Append(207, 'Draw2 - sin, cos, large joined markers', 'Draw plots2') + menu.Append(207, 'Draw2 - sin, cos, large joined markers', + 'Draw Sin and Cos curves with some large joined makers') self.Bind(wx.EVT_MENU, self.OnPlotDraw2, id=207) - menu.Append(208, 'Draw3 - various markers', 'Draw plots3') + menu.Append(208, 'Draw3 - various markers', + 'Demo various markers') self.Bind(wx.EVT_MENU, self.OnPlotDraw3, id=208) - menu.Append(209, 'Draw4 - 25k pts', 'Draw plots4') + menu.Append(209, 'Draw4 - 25k pts', + 'Example of drawing many points quickly') self.Bind(wx.EVT_MENU, self.OnPlotDraw4, id=209) - menu.Append(210, 'Draw5 - empty plot', 'Draw plots5') + menu.Append(210, 'Draw5 - empty plot', + 'An empty plot') self.Bind(wx.EVT_MENU, self.OnPlotDraw5, id=210) - menu.Append(260, 'Draw6 - bar graph', 'Draw plots6') + menu.Append(260, 'Draw6 - fake bar graph via lines', + 'Fake a bar graph by using lines.') self.Bind(wx.EVT_MENU, self.OnPlotDraw6, id=260) - menu.Append(261, 'Draw7 - log-log', 'Draw plots7') + menu.Append(261, 'Draw7 - log-log', + 'Plot a Log-Log graph') self.Bind(wx.EVT_MENU, self.OnPlotDraw7, id=261) - menu.Append(262, 'Draw8 - Box Plots', 'Draw plots8') + menu.Append(262, 'Draw8 - Box Plots', + 'Show off some box plots') self.Bind(wx.EVT_MENU, self.OnPlotDraw8, id=262) + menu.Append(263, 'Draw9 - Histogram', + 'Plot a histogram') + self.Bind(wx.EVT_MENU, self.OnPlotDraw9, id=263) + menu.Append(264, 'Draw10 - real bar graph', + 'Plot a real bar chart (not faked with lines)') + self.Bind(wx.EVT_MENU, self.OnPlotDraw10, id=264) menu.AppendSeparator() @@ -4259,6 +4535,16 @@ class TestFrame(wx.Frame): self.resetDefaults() self.client.Draw(_draw8Objects()) + def OnPlotDraw9(self, event): + """Histogram example""" + self.resetDefaults() + self.client.Draw(_draw9Objects()) + + def OnPlotDraw10(self, event): + """Bar Chart example""" + self.resetDefaults() + self.client.Draw(_draw10Objects()) + def OnPlotRedraw(self, event): self.client.Redraw()