diff --git a/wx/lib/plot/demo.py b/wx/lib/plot/demo.py new file mode 100644 index 00000000..2bc76e84 --- /dev/null +++ b/wx/lib/plot/demo.py @@ -0,0 +1,947 @@ +# -*- coding: utf-8 -*- +# pylint: disable=E1101, C0330, C0103 +# E1101: Module X has no Y member +# C0330: Wrong continued indentation +# C0103: Invalid attribute/variable/method name +# +""" +demo.py +======= + +This is a demo showing off some of the cababilities of the ``wx.lib.plot`` +package. It is intended to be run as a standalone module via:: + + python wx\lib\plot\demo.py + +""" +__docformat__ = "restructuredtext en" + +import wx +from plot import ( + PolyPoints, + PolyLine, + PolySpline, + PolyMarker, + PolyBars, + PolyHistogram, + BoxPlot, + PlotGraphics, + PlotCanvas, + PlotPrintout, +) + +# Needs NumPy +try: + import numpy as np +except: + msg = """ + This module requires the NumPy module, which could not be + imported. It probably is not installed (it's not part of the + standard Python distribution). See the Numeric Python site + (http://numpy.scipy.org) for information on downloading source or + binaries.""" + raise ImportError("NumPy not found.\n" + msg) + + +### ------------------------------------------------------------------------- +### Examples and Demo Frame +### ------------------------------------------------------------------------- +def _draw1Objects(): + """Sin, Cos, and Points""" + # 100 points sin function, plotted as green circles + data1 = 2. * np.pi * np.arange(-200, 200) / 200. + data1.shape = (200, 2) + data1[:, 1] = np.sin(data1[:, 0]) + markers1 = PolyMarker(data1, + legend='Green Markers', + colour='green', + marker='circle', + size=1, + ) + + # 50 points cos function, plotted as red line and markers + data1 = 2. * np.pi * np.arange(-100, 100) / 100. + data1.shape = (100, 2) + data1[:, 1] = np.cos(data1[:, 0]) + lines = PolySpline(data1, legend='Red Line', colour='red') + markers3 = PolyMarker(data1, + legend='Red Dot', + colour='red', + marker='circle', + size=1, + ) + + # A few more points... + pi = np.pi + pts = [(0., 0.), (pi / 4., 1.), (pi / 2, 0.), (3. * pi / 4., -1)] + markers2 = PolyMarker(pts, + legend='Cross Legend', + colour='blue', + marker='cross', + ) + line2 = PolyLine(pts, drawstyle='steps-post') + + return PlotGraphics([markers1, lines, markers3, markers2, line2], + "Graph Title", + "X Axis", + "Y Axis") + + +def _draw2Objects(): + """Sin, Cos, Points, and lines between points""" + # 100 points sin function, plotted as green dots + data1 = 2. * np.pi * np.arange(200) / 200. + data1.shape = (100, 2) + data1[:, 1] = np.sin(data1[:, 0]) + line1 = PolySpline(data1, + legend='Green Line', + colour='green', + width=6, + style=wx.PENSTYLE_DOT) + + # 25 points cos function, plotted as red dot-dash with steps. + data1 = 2. * np.pi * np.arange(50) / 50. + data1.shape = (25, 2) + data1[:, 1] = np.cos(data1[:, 0]) + line2 = PolyLine(data1, + legend='Red Line', + colour='red', + width=2, + style=wx.PENSTYLE_DOT_DASH, + drawstyle='steps-post', + ) + + # data points for the 25pt cos function. + pts2 = PolyMarker(data1, + legend='Red Points', + colour='red', + size=1.5, + ) + + # A few more points... + pi = np.pi + pts = [(0., 0.), (pi / 4., 1.), (pi / 2, 0.), (3. * pi / 4., -1)] + markers1 = PolyMarker(pts, + legend='Cross Hatch Square', + colour='blue', + width=3, + size=6, + fillcolour='red', + fillstyle=wx.CROSSDIAG_HATCH, + marker='square', + ) + marker_line = PolyLine(pts, + legend='Cross Hatch Square', + colour='blue', + width=3, + ) + + return PlotGraphics([markers1, line1, line2, pts2, marker_line], + "Big Markers with Different Line Styles") + + +def _draw3Objects(): + """Various Marker Types""" + markerList = ['circle', 'dot', 'square', 'triangle', 'triangle_down', + 'cross', 'plus', 'circle'] + m = [] + for i in range(len(markerList)): + m.append(PolyMarker([(2 * i + .5, i + .5)], + legend=markerList[i], + colour='blue', + marker=markerList[i]) + ) + return PlotGraphics(m, "Selection of Markers", "Minimal Axis", "No Axis") + + +def _draw4Objects(): + """25,000 point line and markers""" + # Points + data1 = np.random.normal(loc=7.5e5, scale=70000, size=50000) + data1.shape = (25000, 2) + markers2 = PolyMarker(data1, legend='Dots', colour='blue', + marker='square', + size=1, + ) + + # Line + data1 = np.arange(5e5, 1e6, 10) + data1.shape = (25000, 2) + line1 = PolyLine(data1, legend='Wide Line', colour='green', width=4) + + return PlotGraphics([markers2, line1], "25,000 Points", "Value X", "") + + +def _draw5Objects(): + """Empty graph with axes but no points""" + points = [] + line1 = PolyLine(points, legend='Wide Line', colour='green', width=5) + return PlotGraphics([line1], + "Empty Plot With Just Axes", + "Value X", + "Value Y") + + +def _draw6Objects(): + """Faking a Bar graph""" + points1 = [(1, 0), (1, 10)] + line1 = PolyLine(points1, colour='green', legend='Feb.', width=10) + points1g = [(2, 0), (2, 4)] + line1g = PolyLine(points1g, colour='red', legend='Mar.', width=10) + points1b = [(3, 0), (3, 6)] + line1b = PolyLine(points1b, colour='blue', legend='Apr.', width=10) + + points2 = [(4, 0), (4, 12)] + line2 = PolyLine(points2, colour='Yellow', legend='May', width=10) + points2g = [(5, 0), (5, 8)] + line2g = PolyLine(points2g, colour='orange', legend='June', width=10) + points2b = [(6, 0), (6, 4)] + line2b = PolyLine(points2b, colour='brown', legend='July', width=10) + + return PlotGraphics([line1, line1g, line1b, line2, line2g, line2b], + "Bar Graph - (Turn on Grid, Legend)", + "Months", + "Number of Students") + + +def _draw7Objects(): + """Log10 on both axes""" + x = np.arange(-1000, 1000, 1) + y1 = 4.5 * x ** 2 + y2 = 2.2 * x ** 3 + points1 = np.transpose([x, y1]) + points2 = np.transpose([x, y2]) + line1 = PolyLine(points1, legend='quadratic', colour='blue', width=1) + line2 = PolyLine(points2, legend='cubic', colour='red', width=1) + return PlotGraphics([line1, line2], + "double log plot", + "Value X", + "Value Y") + + +def _draw8Objects(): + """ + Box plot + """ + data1 = np.array([np.NaN, 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]) + 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, + 538, 577, 679, 415, 326, 417, 635, 319, 350, 97]) + + data2 = data2 * 0.9 + + data1 = np.array([(0, x) for x in data1]) + data2 = np.array([(1, x) for x in data2]) + + data3 = np.random.gamma(2, 2, 500) * 30 + 100 + data3 = np.array([(2, x) for x in data3]) + + boxplot = BoxPlot(data1, legend="Weights") + boxplot2 = BoxPlot(data2, legend="Heights") + boxplot3 = BoxPlot(data3, legend="GammaDistribution") + return PlotGraphics([boxplot, boxplot2, boxplot3], + "Box Plot", + "", + "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, (800, 600)) + + # Now Create the menu bar and items + self.mainmenu = wx.MenuBar() + + # ------------------------------------------------------------------- + ### "File" Menu Items ############################################### + # ------------------------------------------------------------------- + menu = wx.Menu() + menu.Append(200, 'Page Setup...', 'Setup the printer page') + self.Bind(wx.EVT_MENU, self.OnFilePageSetup, id=200) + menu.Append(201, 'Print Preview...', 'Show the current plot on page') + self.Bind(wx.EVT_MENU, self.OnFilePrintPreview, id=201) + menu.Append(202, 'Print...', 'Print the current plot') + self.Bind(wx.EVT_MENU, self.OnFilePrint, id=202) + menu.Append(203, 'Save Plot...', 'Save current plot') + self.Bind(wx.EVT_MENU, self.OnSaveFile, id=203) + menu.Append(205, 'E&xit', 'Enough of this already!') + self.Bind(wx.EVT_MENU, self.OnFileExit, id=205) + self.mainmenu.Append(menu, '&File') + + # ------------------------------------------------------------------- + ### "Plot" Menu Items ############################################### + # ------------------------------------------------------------------- + menu = wx.Menu() + 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 Sin and Cos curves with some large joined makers') + self.Bind(wx.EVT_MENU, self.OnPlotDraw2, id=207) + menu.Append(208, 'Draw3 - various markers', + 'Demo various markers') + self.Bind(wx.EVT_MENU, self.OnPlotDraw3, id=208) + 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', + 'An empty plot') + self.Bind(wx.EVT_MENU, self.OnPlotDraw5, id=210) + 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', + 'Plot a Log-Log graph') + self.Bind(wx.EVT_MENU, self.OnPlotDraw7, id=261) + 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() + + menu.Append(211, '&Redraw', 'Redraw plots') + self.Bind(wx.EVT_MENU, self.OnPlotRedraw, id=211) + menu.Append(212, '&Clear', 'Clear canvas') + self.Bind(wx.EVT_MENU, self.OnPlotClear, id=212) + menu.Append(213, '&Scale', 'Scale canvas') + self.Bind(wx.EVT_MENU, self.OnPlotScale, id=213) + + menu.AppendSeparator() + + menu.Append(225, 'Scroll Up 1', 'Move View Up 1 Unit') + self.Bind(wx.EVT_MENU, self.OnScrUp, id=225) + menu.Append(230, 'Scroll Rt 2', 'Move View Right 2 Units') + self.Bind(wx.EVT_MENU, self.OnScrRt, id=230) + menu.Append(235, '&Plot Reset', 'Reset to original plot') + self.Bind(wx.EVT_MENU, self.OnReset, id=235) + + self.mainmenu.Append(menu, '&Plot') + + # ------------------------------------------------------------------- + ### "Options" Menu Items ############################################ + # ------------------------------------------------------------------- + + menu = wx.Menu() + + menu.Append(214, 'Enable &Zoom', + 'Enable Mouse Zoom', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableZoom, id=214) + + menu.Append(217, 'Enable &Drag', + 'Activates dragging mode', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableDrag, id=217) + + menu.Append(222, 'Enable &Point Label', + 'Show Closest Point', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnablePointLabel, id=222) + + menu.Append(223, 'Enable &Anti-Aliasing', + 'Smooth output', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableAntiAliasing, id=223) + + menu.Append(224, 'Enable &High-Resolution AA', + 'Draw in higher resolution', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableHiRes, id=224) + + menu.AppendSeparator() + + menu.Append(226, 'Enable Center Lines', + 'Draw center lines', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableCenterLines, id=226) + + menu.Append(227, 'Enable Diagonal Lines', + 'Draw diagonal lines', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableDiagonals, id=227) + + menu.Append(220, 'Enable &Legend', + 'Turn on Legend', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableLegend, id=220) + + ### SubMenu for Grid + submenu = wx.Menu() + self.gridSubMenu = submenu + + submenu.AppendCheckItem(2151, "X Gridlines", "Enable X gridlines") + submenu.AppendCheckItem(2152, "Y Gridlines", "Enable Y gridlines") + submenu.AppendCheckItem(2153, "All Gridlines", "Enable All gridlines") + submenu.Check(2151, True) + submenu.Check(2152, True) + submenu.Check(2153, True) + + self.Bind(wx.EVT_MENU, self.OnEnableGridX, id=2151) + self.Bind(wx.EVT_MENU, self.OnEnableGridY, id=2152) + self.Bind(wx.EVT_MENU, self.OnEnableGridAll, id=2153) + + menu.Append(215, 'Enable Grid', submenu, 'Turn on Grid') +# self.Bind(wx.EVT_MENU, self.OnEnableGrid, id=215) + + ### SubMenu for Axes + submenu = wx.Menu() + submenu_items = ("Bottom", "Left", "Top", "Right", + "Bottom+Left", "All") + self.axesSubMenu = submenu + for _i, item in enumerate(submenu_items, 2401): + submenu.AppendCheckItem(_i, item, "Enables {} axis".format(item)) + submenu.Check(_i, True) + + self.Bind(wx.EVT_MENU, self.OnEnableAxesBottom, id=2401) + self.Bind(wx.EVT_MENU, self.OnEnableAxesLeft, id=2402) + self.Bind(wx.EVT_MENU, self.OnEnableAxesTop, id=2403) + self.Bind(wx.EVT_MENU, self.OnEnableAxesRight, id=2404) + self.Bind(wx.EVT_MENU, self.OnEnableAxesBottomLeft, id=2405) + self.Bind(wx.EVT_MENU, self.OnEnableAxesAll, id=2406) + + menu.Append(240, 'Enable Axes', submenu, + 'Enables the display of the Axes') + + submenu = wx.Menu() + submenu_items = ("Bottom", "Left", "Top", "Right") + help_txt = "Enables {} axis values" + self.axesValuesSubMenu = submenu + for _i, item in enumerate(submenu_items, 2451): + submenu.AppendCheckItem(_i, item, help_txt.format(item)) + + submenu.Check(2451, True) + submenu.Check(2452, True) + submenu.Check(2453, False) + submenu.Check(2454, False) + + self.Bind(wx.EVT_MENU, self.OnEnableAxesValuesBottom, id=2451) + self.Bind(wx.EVT_MENU, self.OnEnableAxesValuesLeft, id=2452) + self.Bind(wx.EVT_MENU, self.OnEnableAxesValuesTop, id=2453) + self.Bind(wx.EVT_MENU, self.OnEnableAxesValuesRight, id=2454) + + menu.Append(245, 'Enable Axes Values', submenu, + 'Enables the display of the axes values') + + submenu = wx.Menu() + submenu_items = ("Bottom", "Left", "Top", "Right") + help_txt = "Enables {} ticks" + self.ticksSubMenu = submenu + for _i, item in enumerate(submenu_items, 2501): + submenu.AppendCheckItem(_i, item, help_txt.format(item)) + + submenu.Check(2501, False) + submenu.Check(2502, False) + submenu.Check(2503, False) + submenu.Check(2504, False) + + self.Bind(wx.EVT_MENU, self.OnEnableTicksBottom, id=2501) + self.Bind(wx.EVT_MENU, self.OnEnableTicksLeft, id=2502) + self.Bind(wx.EVT_MENU, self.OnEnableTicksTop, id=2503) + self.Bind(wx.EVT_MENU, self.OnEnableTicksRight, id=2504) + + menu.Append(250, 'Enable Ticks', submenu, + 'Enables the display of the ticks') + + menu.Append(255, 'Enable Plot Title', + 'Enables the plot title', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnablePlotTitle, id=255) + menu.Check(255, True) + + menu.Append(270, 'Enable Axes Labels', + 'Enables the X and Y axes labels', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableAxesLabels, id=270) + menu.Check(270, True) + + menu.Append(271, 'Enable Log-Y', + 'Changes the Y axis to log10 scale', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnLogY, id=271) + menu.Append(272, 'Enable Log-X', + 'Changes the X axis to log10 scale', kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnLogX, id=272) + + menu.Append(273, 'Enable Abs(X)', + 'Applies absolute value transform to X axis', + kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnAbsX, id=273) + menu.Append(274, 'Enable Abs(Y)', + 'Applies absolute value transform to Y axis', + kind=wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnAbsY, id=274) + + menu.AppendSeparator() + + menu.Append(231, 'Set Gray Background', + 'Change background colour to gray') + self.Bind(wx.EVT_MENU, self.OnBackgroundGray, id=231) + menu.Append(232, 'Set &White Background', + 'Change background colour to white') + self.Bind(wx.EVT_MENU, self.OnBackgroundWhite, id=232) + menu.Append(233, 'Set Red Label Text', + 'Change label text colour to red') + self.Bind(wx.EVT_MENU, self.OnForegroundRed, id=233) + menu.Append(234, 'Set &Black Label Text', + 'Change label text colour to black') + self.Bind(wx.EVT_MENU, self.OnForegroundBlack, id=234) + + self.mainmenu.Append(menu, '&Options') + + self.plot_options_menu = menu + + # ------------------------------------------------------------------- + ### "Help" Menu Items ############################################ + # ------------------------------------------------------------------- + menu = wx.Menu() + menu.Append(300, '&About', 'About this thing...') + self.Bind(wx.EVT_MENU, self.OnHelpAbout, id=300) + self.mainmenu.Append(menu, '&Help') + + self.SetMenuBar(self.mainmenu) + + # A status bar to tell people what's happening + self.CreateStatusBar(1) + + self.client = PlotCanvas(self) + # define the function for drawing pointLabels +# self.client.SetPointLabelFunc(self.DrawPointLabel) + self.client.pointLabelFunc = self.DrawPointLabel + # Create mouse event for showing cursor coords in status bar + self.client.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) + # Show closest point when enabled + self.client.canvas.Bind(wx.EVT_MOTION, self.OnMotion) + + self.Show(True) + + def DrawPointLabel(self, dc, mDataDict): + """ + This is the fuction that defines how the pointLabels are plotted + + :param dc: DC that will be passed + :param mDataDict: Dictionary of data that you want to use + for the pointLabel + + As an example I have decided I want a box at the curve point + with some text information about the curve plotted below. + Any wxDC method can be used. + + """ + # ---------- + dc.SetPen(wx.Pen(wx.BLACK)) + dc.SetBrush(wx.Brush(wx.BLACK, wx.BRUSHSTYLE_SOLID)) + + sx, sy = mDataDict["scaledXY"] # scaled x,y of closest point + # 10by10 square centered on point + dc.DrawRectangle(sx - 5, sy - 5, 10, 10) + px, py = mDataDict["pointXY"] + cNum = mDataDict["curveNum"] + pntIn = mDataDict["pIndex"] + legend = mDataDict["legend"] + # make a string to display + s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" % ( + cNum, legend, px, py, pntIn) + dc.DrawText(s, sx, sy + 1) + # ----------- + + def OnMouseLeftDown(self, event): + s = "Left Mouse Down at Point: (%.4f, %.4f)" % self.client._getXY( + event) + self.SetStatusText(s) + event.Skip() # allows plotCanvas OnMouseLeftDown to be called + + def OnMotion(self, event): + # show closest point (when enbled) + if self.client.enablePointLabel: + # make up dict with info for the pointLabel + # I've decided to mark the closest point on the closest curve + dlst = self.client.GetClosestPoint( + self.client._getXY(event), pointScaled=True) + if dlst != []: # returns [] if none + curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst + # make up dictionary to pass to my user function (see + # DrawPointLabel) + mDataDict = {"curveNum": curveNum, + "legend": legend, + "pIndex": pIndex, + "pointXY": pointXY, + "scaledXY": scaledXY} + # pass dict to update the pointLabel + self.client.UpdatePointLabel(mDataDict) + event.Skip() # go to next handler + + def OnFilePageSetup(self, event): + self.client.PageSetup() + + def OnFilePrintPreview(self, event): + self.client.PrintPreview() + + def OnFilePrint(self, event): + self.client.Printout() + + def OnSaveFile(self, event): + self.client.SaveFile() + + def OnFileExit(self, event): + self.Close() + + def OnPlotDraw1(self, event): + self.resetDefaults() + self.client.Draw(_draw1Objects()) + + def OnPlotDraw2(self, event): + self.resetDefaults() + self.client.Draw(_draw2Objects()) + + def OnPlotDraw3(self, event): + self.resetDefaults() + self.client.SetFont(wx.Font(10, + wx.FONTFAMILY_SCRIPT, + wx.FONTSTYLE_NORMAL, + wx.FONTWEIGHT_NORMAL) + ) + self.client.fontSizeAxis = 20 + self.client.fontSizeLegend = 12 + self.client.xSpec = 'min' + self.client.ySpec = 'none' + self.client.Draw(_draw3Objects()) + + def OnPlotDraw4(self, event): + self.resetDefaults() + drawObj = _draw4Objects() + self.client.Draw(drawObj) +# profile +# start = _time.perf_counter() +# for x in range(10): +# self.client.Draw(drawObj) +## print("10x of Draw4 took: %f sec."%(_time.perf_counter() - start)) +# profile end + + def OnPlotDraw5(self, event): + # Empty plot with just axes + self.resetDefaults() + drawObj = _draw5Objects() + # make the axis X= (0,5), Y=(0,10) + # (default with None is X= (-1,1), Y= (-1,1)) + self.client.Draw(drawObj, xAxis=(0, 5), yAxis=(0, 10)) + + def OnPlotDraw6(self, event): + # Bar Graph Example + self.resetDefaults() + # self.client.SetEnableLegend(True) #turn on Legend + # self.client.SetEnableGrid(True) #turn on Grid + self.client.xSpec = 'none' + self.client.ySpec = 'auto' + self.client.Draw(_draw6Objects(), xAxis=(0, 7)) + + def OnPlotDraw7(self, event): + # log scale example + self.resetDefaults() + self.plot_options_menu.Check(271, True) + self.plot_options_menu.Check(272, True) + self.client.logScale = (True, True) + self.client.Draw(_draw7Objects()) + + def OnPlotDraw8(self, event): + """Box Plot example""" + 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() + + def OnPlotClear(self, event): + self.client.Clear() + + def OnPlotScale(self, event): + if self.client.last_draw is not None: + graphics, xAxis, yAxis = self.client.last_draw + self.client.Draw(graphics, (1, 3.05), (0, 1)) + + def OnEnableZoom(self, event): + self.client.enableZoom = event.IsChecked() + if self.mainmenu.IsChecked(217): + self.mainmenu.Check(217, False) + + ### Grid Events ### + + def _checkOtherGridMenuItems(self): + """ check or uncheck the submenu items """ + self.gridSubMenu.Check(2151, self.client.enableGrid[0]) + self.gridSubMenu.Check(2152, self.client.enableGrid[1]) + self.gridSubMenu.Check(2153, all(self.client.enableGrid)) + + def OnEnableGridX(self, event): + old = self.client.enableGrid + self.client.enableGrid = (event.IsChecked(), old[1]) + self._checkOtherGridMenuItems() + + def OnEnableGridY(self, event): + old = self.client.enableGrid + self.client.enableGrid = (old[0], event.IsChecked()) + self._checkOtherGridMenuItems() + + def OnEnableGridAll(self, event): + self.client.enableGrid = event.IsChecked() + self._checkOtherGridMenuItems() + self.gridSubMenu.Check(2151, event.IsChecked()) + self.gridSubMenu.Check(2152, event.IsChecked()) + + def OnEnableDrag(self, event): + self.client.enableDrag = event.IsChecked() + if self.mainmenu.IsChecked(214): + self.mainmenu.Check(214, False) + + def OnEnableLegend(self, event): + self.client.enableLegend = event.IsChecked() + + def OnEnablePointLabel(self, event): + self.client.enablePointLabel = event.IsChecked() + + def OnEnableAntiAliasing(self, event): + self.client.enableAntiAliasing = event.IsChecked() + + def OnEnableHiRes(self, event): + self.client.enableHiRes = event.IsChecked() + + ### Axes Events ### + + def _checkOtherAxesMenuItems(self): + """ check or uncheck the submenu items """ + self.axesSubMenu.Check(2401, self.client.enableAxes[0]) + self.axesSubMenu.Check(2402, self.client.enableAxes[1]) + self.axesSubMenu.Check(2403, self.client.enableAxes[2]) + self.axesSubMenu.Check(2404, self.client.enableAxes[3]) + self.axesSubMenu.Check(2405, all(self.client.enableAxes[:2])) + self.axesSubMenu.Check(2406, all(self.client.enableAxes)) + + def OnEnableAxesBottom(self, event): + old = self.client.enableAxes + self.client.enableAxes = (event.IsChecked(), old[1], old[2], old[3]) + self._checkOtherAxesMenuItems() + + def OnEnableAxesLeft(self, event): + old = self.client.enableAxes + self.client.enableAxes = (old[0], event.IsChecked(), old[2], old[3]) + self._checkOtherAxesMenuItems() + + def OnEnableAxesTop(self, event): + old = self.client.enableAxes + self.client.enableAxes = (old[0], old[1], event.IsChecked(), old[3]) + self._checkOtherAxesMenuItems() + + def OnEnableAxesRight(self, event): + old = self.client.enableAxes + self.client.enableAxes = (old[0], old[1], old[2], event.IsChecked()) + self._checkOtherAxesMenuItems() + + def OnEnableAxesBottomLeft(self, event): + checked = event.IsChecked() + old = self.client.enableAxes + self.client.enableAxes = (checked, checked, old[2], old[3]) + self._checkOtherAxesMenuItems() + + def OnEnableAxesAll(self, event): + checked = event.IsChecked() + self.client.enableAxes = (checked, checked, checked, checked) + self._checkOtherAxesMenuItems() + + ### Ticks Events ### + + def _checkOtherTicksMenuItems(self): + """ check or uncheck the submenu items """ + self.ticksSubMenu.Check(2501, self.client.enableTicks[0]) + self.ticksSubMenu.Check(2502, self.client.enableTicks[1]) + self.ticksSubMenu.Check(2503, self.client.enableTicks[2]) + self.ticksSubMenu.Check(2504, self.client.enableTicks[3]) +# self.ticksSubMenu.Check(2505, all(self.client.enableTicks[:2])) +# self.axesSubMenu.Check(2506, all(self.client.enableTicks)) + + def OnEnableTicksBottom(self, event): + old = self.client.enableTicks + self.client.enableTicks = (event.IsChecked(), old[1], + old[2], old[3]) + self._checkOtherTicksMenuItems() + + def OnEnableTicksLeft(self, event): + old = self.client.enableTicks + self.client.enableTicks = (old[0], event.IsChecked(), + old[2], old[3]) + self._checkOtherTicksMenuItems() + + def OnEnableTicksTop(self, event): + old = self.client.enableTicks + self.client.enableTicks = (old[0], old[1], + event.IsChecked(), old[3]) + self._checkOtherTicksMenuItems() + + def OnEnableTicksRight(self, event): + old = self.client.enableTicks + self.client.enableTicks = (old[0], old[1], + old[2], event.IsChecked()) + self._checkOtherTicksMenuItems() + + ### AxesValues Events ### + + def OnEnableAxesValuesBottom(self, event): + old = self.client.enableAxesValues + self.client.enableAxesValues = (event.IsChecked(), old[1], + old[2], old[3]) + + def OnEnableAxesValuesLeft(self, event): + old = self.client.enableAxesValues + self.client.enableAxesValues = (old[0], event.IsChecked(), + old[2], old[3]) + + def OnEnableAxesValuesTop(self, event): + old = self.client.enableAxesValues + self.client.enableAxesValues = (old[0], old[1], + event.IsChecked(), old[3]) + + def OnEnableAxesValuesRight(self, event): + old = self.client.enableAxesValues + self.client.enableAxesValues = (old[0], old[1], + old[2], event.IsChecked()) + + ### Other Events ### + + def OnEnablePlotTitle(self, event): + self.client.enablePlotTitle = event.IsChecked() + + def OnEnableAxesLabels(self, event): + self.client.enableAxesLabels = event.IsChecked() + + def OnEnableCenterLines(self, event): + self.client.enableCenterLines = event.IsChecked() + + def OnEnableDiagonals(self, event): + self.client.enableDiagonals = event.IsChecked() + + def OnBackgroundGray(self, event): + self.client.SetBackgroundColour("#CCCCCC") + self.client.Redraw() + + def OnBackgroundWhite(self, event): + self.client.SetBackgroundColour("white") + self.client.Redraw() + + def OnForegroundRed(self, event): + self.client.SetForegroundColour("red") + self.client.Redraw() + + def OnForegroundBlack(self, event): + self.client.SetForegroundColour("black") + self.client.Redraw() + + def OnLogX(self, event): + self.client.logScale = (event.IsChecked(), self.client.logScale[1]) + self.client.Redraw() + + def OnLogY(self, event): + self.client.logScale = (self.client.logScale[0], event.IsChecked()) + self.client.Redraw() + + def OnAbsX(self, event): + self.client.absScale = (event.IsChecked(), self.client.absScale[1]) + self.client.Redraw() + + def OnAbsY(self, event): + self.client.absScale = (self.client.absScale[0], event.IsChecked()) + self.client.Redraw() + + def OnScrUp(self, event): + self.client.ScrollUp(1) + + def OnScrRt(self, event): + self.client.ScrollRight(2) + + def OnReset(self, event): + self.client.Reset() + + def OnHelpAbout(self, event): + from wx.lib.dialogs import ScrolledMessageDialog + about = ScrolledMessageDialog(self, __doc__, "About...") + about.ShowModal() + + def resetDefaults(self): + """Just to reset the fonts back to the PlotCanvas defaults""" + self.client.SetFont(wx.Font(10, + wx.FONTFAMILY_SWISS, + wx.FONTSTYLE_NORMAL, + wx.FONTWEIGHT_NORMAL) + ) + self.client.fontSizeAxis = 10 + self.client.fontSizeLegend = 7 + self.client.logScale = (False, False) + self.client.xSpec = 'auto' + self.client.ySpec = 'auto' + + +def __test(): + + class MyApp(wx.App): + + def OnInit(self): + wx.InitAllImageHandlers() + frame = TestFrame(None, -1, "PlotCanvas") + # frame.Show(True) + self.SetTopWindow(frame) + return True + + app = MyApp(0) + app.MainLoop() + + +if __name__ == '__main__': + __test() diff --git a/wx/lib/plot/plot.py b/wx/lib/plot/plot.py index a957142e..463bf53b 100644 --- a/wx/lib/plot/plot.py +++ b/wx/lib/plot/plot.py @@ -1818,10 +1818,11 @@ class PlotCanvas(wx.Panel): self.Bind(wx.EVT_SCROLL_LINEDOWN, self.OnScroll) # set curser as cross-hairs - self.canvas.SetCursor(wx.CROSS_CURSOR) - self.HandCursor = wx.Cursor(Hand.GetImage()) - self.GrabHandCursor = wx.Cursor(GrabHand.GetImage()) - self.MagCursor = wx.Cursor(MagPlus.GetImage()) + self.defaultCursor = wx.Cursor(wx.CURSOR_ARROW) + self.HandCursor = wx.Cursor(wx.CURSOR_SIZING) + self.GrabHandCursor = wx.Cursor(wx.CURSOR_SIZING) + self.MagCursor = wx.Cursor(wx.CURSOR_MAGNIFIER) + self.canvas.SetCursor(self.defaultCursor) # Things for printing self._print_data = None @@ -2606,7 +2607,7 @@ class PlotCanvas(wx.Panel): self.enableZoom = False self.SetCursor(self.HandCursor) else: - self.SetCursor(wx.CROSS_CURSOR) + self.SetCursor(self.defaultCursor) self._dragEnabled = value @PendingDeprecation("self.enableZoom property") @@ -2662,7 +2663,7 @@ class PlotCanvas(wx.Panel): self.enableDrag = False self.SetCursor(self.MagCursor) else: - self.SetCursor(wx.CROSS_CURSOR) + self.SetCursor(self.defaultCursor) self._zoomEnabled = value @PendingDeprecation("self.enableGrid property") @@ -4756,935 +4757,4 @@ class PlotPrintout(wx.Printout): return True -#---------------------------------------------------------------------- -from wx.lib.embeddedimage import PyEmbeddedImage -MagPlus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAOFJ" - "REFUeJy1VdEOxCAIo27//8XbuKfuPASGZ0Zisoi2FJABbZM3bY8c13lo5GvbjioBPAUEB0Yc" - "VZ0iGRRc56Ee8DcikEgrJD8EFpzRegQASiRtBtzuA0hrdRPYQxaEKyJPG6IHyiK3xnNZvUSS" - "NvUuzgYh0il4y14nCFPk5XgmNbRbQbVotGo9msj47G3UXJ7fuz8Q8FAGEu0/PbZh2D3NoshU" - "1VUydBGVZKMimlGeErdNGUmf/x7YpjMjcf8HVYvS2adr6aFVlCy/5Ijk9q8SeCR9isJR8SeJ" - "8pv7S0Wu2Acr0qdj3w7DRAAAAABJRU5ErkJggg==") - -GrabHand = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAARFJ" - "REFUeJy1VdESgzAIS2j//4s3s5fRQ6Rad5M7H0oxCZhWSpK1TjwUBCBJAIBItL1fijlfe1yJ" - "8noCGC9KgrXO7f0SyZEDAF/H2opsAHv9V/548nplT5Jo7YAFQKQ1RMWzmHUS96suqdBrHkuV" - "uxpdJjCS8CfGXWdJ2glzcquKSR5c46QOtCpgNyIHj6oieAXg3282QvMX45hy8a8H0VonJZUO" - "clesjOPg/dhBTq64o1Kacz4Ri2x5RKsf8+wcWQaJJL+A+xRcZHeQeBKjK+5EFiVJ4xy4x2Mn" - "1Vk4U5/DWmfPieiqbye7a3tV/cCsWKu76K76KUFFchVnhigJ/hmktelm/m3e3b8k+Ec8PqLH" - "CT4JRfyK9o1xYwAAAABJRU5ErkJggg==") - -Hand = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAARBJ" - "REFUeJytluECwiAIhDn1/Z942/UnjCGoq+6XNeWDC1xAqbKr6zyo61Ibds60J8GBT0yS3IEM" - "ABuIpJTa4IOLiAAQksuKyixLH1ShHgTgZl8KiALxOsODPoEMkgJ25Su6zoO3ZrjRnI96OLIq" - "k7dsqOCboDa4XV/nwQEQVeFtmMnvbSJja+oagKBUaLn9hzd7VipRa9ostIv0O1uhzzaqNJxk" - "hViwDVxqg51kksMg9r2rDDIFwHCap130FBhdMzeAfWg//6Ki5WWQrHSv6EIUeVs0g3wT3J7r" - "FmWQp/JJDXeRh2TXcJa91zAH2uN2mvXFsrIrsjS8rnftWmWfAiLIStuD9m9h9belvzgS/1fP" - "X7075IwDENteAAAAAElFTkSuQmCC") - - -### ------------------------------------------------------------------------- -### Examples and Demo Frame -### ------------------------------------------------------------------------- -def _draw1Objects(): - """Sin, Cos, and Points""" - # 100 points sin function, plotted as green circles - data1 = 2. * np.pi * np.arange(-200, 200) / 200. - data1.shape = (200, 2) - data1[:, 1] = np.sin(data1[:, 0]) - markers1 = PolyMarker(data1, - legend='Green Markers', - colour='green', - marker='circle', - size=1, - ) - - # 50 points cos function, plotted as red line and markers - data1 = 2. * np.pi * np.arange(-100, 100) / 100. - data1.shape = (100, 2) - data1[:, 1] = np.cos(data1[:, 0]) - lines = PolySpline(data1, legend='Red Line', colour='red') - markers3 = PolyMarker(data1, - legend='Red Dot', - colour='red', - marker='circle', - size=1, - ) - - # A few more points... - pi = np.pi - pts = [(0., 0.), (pi / 4., 1.), (pi / 2, 0.), (3. * pi / 4., -1)] - markers2 = PolyMarker(pts, - legend='Cross Legend', - colour='blue', - marker='cross', - ) - line2 = PolyLine(pts, drawstyle='steps-post') - - return PlotGraphics([markers1, lines, markers3, markers2, line2], - "Graph Title", - "X Axis", - "Y Axis") - - -def _draw2Objects(): - """Sin, Cos, Points, and lines between points""" - # 100 points sin function, plotted as green dots - data1 = 2. * np.pi * np.arange(200) / 200. - data1.shape = (100, 2) - data1[:, 1] = np.sin(data1[:, 0]) - line1 = PolySpline(data1, - legend='Green Line', - colour='green', - width=6, - style=wx.PENSTYLE_DOT) - - # 25 points cos function, plotted as red dot-dash with steps. - data1 = 2. * np.pi * np.arange(50) / 50. - data1.shape = (25, 2) - data1[:, 1] = np.cos(data1[:, 0]) - line2 = PolyLine(data1, - legend='Red Line', - colour='red', - width=2, - style=wx.PENSTYLE_DOT_DASH, - drawstyle='steps-post', - ) - - # data points for the 25pt cos function. - pts2 = PolyMarker(data1, - legend='Red Points', - colour='red', - size=1.5, - ) - - # A few more points... - pi = np.pi - pts = [(0., 0.), (pi / 4., 1.), (pi / 2, 0.), (3. * pi / 4., -1)] - markers1 = PolyMarker(pts, - legend='Cross Hatch Square', - colour='blue', - width=3, - size=6, - fillcolour='red', - fillstyle=wx.CROSSDIAG_HATCH, - marker='square', - ) - marker_line = PolyLine(pts, - legend='Cross Hatch Square', - colour='blue', - width=3, - ) - - return PlotGraphics([markers1, line1, line2, pts2, marker_line], - "Big Markers with Different Line Styles") - - -def _draw3Objects(): - """Various Marker Types""" - markerList = ['circle', 'dot', 'square', 'triangle', 'triangle_down', - 'cross', 'plus', 'circle'] - m = [] - for i in range(len(markerList)): - m.append(PolyMarker([(2 * i + .5, i + .5)], - legend=markerList[i], - colour='blue', - marker=markerList[i]) - ) - return PlotGraphics(m, "Selection of Markers", "Minimal Axis", "No Axis") - - -def _draw4Objects(): - """25,000 point line and markers""" - # Points - data1 = np.random.normal(loc=7.5e5, scale=70000, size=50000) - data1.shape = (25000, 2) - markers2 = PolyMarker(data1, legend='Dots', colour='blue', - marker='square', - size=1, - ) - - # Line - data1 = np.arange(5e5, 1e6, 10) - data1.shape = (25000, 2) - line1 = PolyLine(data1, legend='Wide Line', colour='green', width=4) - - return PlotGraphics([markers2, line1], "25,000 Points", "Value X", "") - - -def _draw5Objects(): - """Empty graph with axes but no points""" - points = [] - line1 = PolyLine(points, legend='Wide Line', colour='green', width=5) - return PlotGraphics([line1], - "Empty Plot With Just Axes", - "Value X", - "Value Y") - - -def _draw6Objects(): - """Faking a Bar graph""" - points1 = [(1, 0), (1, 10)] - line1 = PolyLine(points1, colour='green', legend='Feb.', width=10) - points1g = [(2, 0), (2, 4)] - line1g = PolyLine(points1g, colour='red', legend='Mar.', width=10) - points1b = [(3, 0), (3, 6)] - line1b = PolyLine(points1b, colour='blue', legend='Apr.', width=10) - - points2 = [(4, 0), (4, 12)] - line2 = PolyLine(points2, colour='Yellow', legend='May', width=10) - points2g = [(5, 0), (5, 8)] - line2g = PolyLine(points2g, colour='orange', legend='June', width=10) - points2b = [(6, 0), (6, 4)] - line2b = PolyLine(points2b, colour='brown', legend='July', width=10) - - return PlotGraphics([line1, line1g, line1b, line2, line2g, line2b], - "Bar Graph - (Turn on Grid, Legend)", - "Months", - "Number of Students") - - -def _draw7Objects(): - """Log10 on both axes""" - x = np.arange(-1000, 1000, 1) - y1 = 4.5 * x ** 2 - y2 = 2.2 * x ** 3 - points1 = np.transpose([x, y1]) - points2 = np.transpose([x, y2]) - line1 = PolyLine(points1, legend='quadratic', colour='blue', width=1) - line2 = PolyLine(points2, legend='cubic', colour='red', width=1) - return PlotGraphics([line1, line2], - "double log plot", - "Value X", - "Value Y") - - -def _draw8Objects(): - """ - Box plot - """ - data1 = np.array([np.NaN, 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]) - 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, - 538, 577, 679, 415, 326, 417, 635, 319, 350, 97]) - - data2 = data2 * 0.9 - - data1 = np.array([(0, x) for x in data1]) - data2 = np.array([(1, x) for x in data2]) - - data3 = np.random.gamma(2, 2, 500) * 30 + 100 - data3 = np.array([(2, x) for x in data3]) - - boxplot = BoxPlot(data1, legend="Weights") - boxplot2 = BoxPlot(data2, legend="Heights") - boxplot3 = BoxPlot(data3, legend="GammaDistribution") - return PlotGraphics([boxplot, boxplot2, boxplot3], - "Box Plot", - "", - "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, (800, 600)) - - # Now Create the menu bar and items - self.mainmenu = wx.MenuBar() - - # ------------------------------------------------------------------- - ### "File" Menu Items ############################################### - # ------------------------------------------------------------------- - menu = wx.Menu() - menu.Append(200, 'Page Setup...', 'Setup the printer page') - self.Bind(wx.EVT_MENU, self.OnFilePageSetup, id=200) - menu.Append(201, 'Print Preview...', 'Show the current plot on page') - self.Bind(wx.EVT_MENU, self.OnFilePrintPreview, id=201) - menu.Append(202, 'Print...', 'Print the current plot') - self.Bind(wx.EVT_MENU, self.OnFilePrint, id=202) - menu.Append(203, 'Save Plot...', 'Save current plot') - self.Bind(wx.EVT_MENU, self.OnSaveFile, id=203) - menu.Append(205, 'E&xit', 'Enough of this already!') - self.Bind(wx.EVT_MENU, self.OnFileExit, id=205) - self.mainmenu.Append(menu, '&File') - - # ------------------------------------------------------------------- - ### "Plot" Menu Items ############################################### - # ------------------------------------------------------------------- - menu = wx.Menu() - 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 Sin and Cos curves with some large joined makers') - self.Bind(wx.EVT_MENU, self.OnPlotDraw2, id=207) - menu.Append(208, 'Draw3 - various markers', - 'Demo various markers') - self.Bind(wx.EVT_MENU, self.OnPlotDraw3, id=208) - 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', - 'An empty plot') - self.Bind(wx.EVT_MENU, self.OnPlotDraw5, id=210) - 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', - 'Plot a Log-Log graph') - self.Bind(wx.EVT_MENU, self.OnPlotDraw7, id=261) - 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() - - menu.Append(211, '&Redraw', 'Redraw plots') - self.Bind(wx.EVT_MENU, self.OnPlotRedraw, id=211) - menu.Append(212, '&Clear', 'Clear canvas') - self.Bind(wx.EVT_MENU, self.OnPlotClear, id=212) - menu.Append(213, '&Scale', 'Scale canvas') - self.Bind(wx.EVT_MENU, self.OnPlotScale, id=213) - - menu.AppendSeparator() - - menu.Append(225, 'Scroll Up 1', 'Move View Up 1 Unit') - self.Bind(wx.EVT_MENU, self.OnScrUp, id=225) - menu.Append(230, 'Scroll Rt 2', 'Move View Right 2 Units') - self.Bind(wx.EVT_MENU, self.OnScrRt, id=230) - menu.Append(235, '&Plot Reset', 'Reset to original plot') - self.Bind(wx.EVT_MENU, self.OnReset, id=235) - - self.mainmenu.Append(menu, '&Plot') - - # ------------------------------------------------------------------- - ### "Options" Menu Items ############################################ - # ------------------------------------------------------------------- - - menu = wx.Menu() - - menu.Append(214, 'Enable &Zoom', - 'Enable Mouse Zoom', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnableZoom, id=214) - - menu.Append(217, 'Enable &Drag', - 'Activates dragging mode', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnableDrag, id=217) - - menu.Append(222, 'Enable &Point Label', - 'Show Closest Point', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnablePointLabel, id=222) - - menu.Append(223, 'Enable &Anti-Aliasing', - 'Smooth output', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnableAntiAliasing, id=223) - - menu.Append(224, 'Enable &High-Resolution AA', - 'Draw in higher resolution', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnableHiRes, id=224) - - menu.AppendSeparator() - - menu.Append(226, 'Enable Center Lines', - 'Draw center lines', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnableCenterLines, id=226) - - menu.Append(227, 'Enable Diagonal Lines', - 'Draw diagonal lines', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnableDiagonals, id=227) - - menu.Append(220, 'Enable &Legend', - 'Turn on Legend', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnableLegend, id=220) - - ### SubMenu for Grid - submenu = wx.Menu() - self.gridSubMenu = submenu - - submenu.AppendCheckItem(2151, "X Gridlines", "Enable X gridlines") - submenu.AppendCheckItem(2152, "Y Gridlines", "Enable Y gridlines") - submenu.AppendCheckItem(2153, "All Gridlines", "Enable All gridlines") - submenu.Check(2151, True) - submenu.Check(2152, True) - submenu.Check(2153, True) - - self.Bind(wx.EVT_MENU, self.OnEnableGridX, id=2151) - self.Bind(wx.EVT_MENU, self.OnEnableGridY, id=2152) - self.Bind(wx.EVT_MENU, self.OnEnableGridAll, id=2153) - - menu.Append(215, 'Enable Grid', submenu, 'Turn on Grid') -# self.Bind(wx.EVT_MENU, self.OnEnableGrid, id=215) - - ### SubMenu for Axes - submenu = wx.Menu() - submenu_items = ("Bottom", "Left", "Top", "Right", - "Bottom+Left", "All") - self.axesSubMenu = submenu - for _i, item in enumerate(submenu_items, 2401): - submenu.AppendCheckItem(_i, item, "Enables {} axis".format(item)) - submenu.Check(_i, True) - - self.Bind(wx.EVT_MENU, self.OnEnableAxesBottom, id=2401) - self.Bind(wx.EVT_MENU, self.OnEnableAxesLeft, id=2402) - self.Bind(wx.EVT_MENU, self.OnEnableAxesTop, id=2403) - self.Bind(wx.EVT_MENU, self.OnEnableAxesRight, id=2404) - self.Bind(wx.EVT_MENU, self.OnEnableAxesBottomLeft, id=2405) - self.Bind(wx.EVT_MENU, self.OnEnableAxesAll, id=2406) - - menu.Append(240, 'Enable Axes', submenu, - 'Enables the display of the Axes') - - submenu = wx.Menu() - submenu_items = ("Bottom", "Left", "Top", "Right") - help_txt = "Enables {} axis values" - self.axesValuesSubMenu = submenu - for _i, item in enumerate(submenu_items, 2451): - submenu.AppendCheckItem(_i, item, help_txt.format(item)) - - submenu.Check(2451, True) - submenu.Check(2452, True) - submenu.Check(2453, False) - submenu.Check(2454, False) - - self.Bind(wx.EVT_MENU, self.OnEnableAxesValuesBottom, id=2451) - self.Bind(wx.EVT_MENU, self.OnEnableAxesValuesLeft, id=2452) - self.Bind(wx.EVT_MENU, self.OnEnableAxesValuesTop, id=2453) - self.Bind(wx.EVT_MENU, self.OnEnableAxesValuesRight, id=2454) - - menu.Append(245, 'Enable Axes Values', submenu, - 'Enables the display of the axes values') - - submenu = wx.Menu() - submenu_items = ("Bottom", "Left", "Top", "Right") - help_txt = "Enables {} ticks" - self.ticksSubMenu = submenu - for _i, item in enumerate(submenu_items, 2501): - submenu.AppendCheckItem(_i, item, help_txt.format(item)) - - submenu.Check(2501, False) - submenu.Check(2502, False) - submenu.Check(2503, False) - submenu.Check(2504, False) - - self.Bind(wx.EVT_MENU, self.OnEnableTicksBottom, id=2501) - self.Bind(wx.EVT_MENU, self.OnEnableTicksLeft, id=2502) - self.Bind(wx.EVT_MENU, self.OnEnableTicksTop, id=2503) - self.Bind(wx.EVT_MENU, self.OnEnableTicksRight, id=2504) - - menu.Append(250, 'Enable Ticks', submenu, - 'Enables the display of the ticks') - - menu.Append(255, 'Enable Plot Title', - 'Enables the plot title', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnablePlotTitle, id=255) - menu.Check(255, True) - - menu.Append(270, 'Enable Axes Labels', - 'Enables the X and Y axes labels', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnEnableAxesLabels, id=270) - menu.Check(270, True) - - menu.Append(271, 'Enable Log-Y', - 'Changes the Y axis to log10 scale', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnLogY, id=271) - menu.Append(272, 'Enable Log-X', - 'Changes the X axis to log10 scale', kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnLogX, id=272) - - menu.Append(273, 'Enable Abs(X)', - 'Applies absolute value transform to X axis', - kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnAbsX, id=273) - menu.Append(274, 'Enable Abs(Y)', - 'Applies absolute value transform to Y axis', - kind=wx.ITEM_CHECK) - self.Bind(wx.EVT_MENU, self.OnAbsY, id=274) - - menu.AppendSeparator() - - menu.Append(231, 'Set Gray Background', - 'Change background colour to gray') - self.Bind(wx.EVT_MENU, self.OnBackgroundGray, id=231) - menu.Append(232, 'Set &White Background', - 'Change background colour to white') - self.Bind(wx.EVT_MENU, self.OnBackgroundWhite, id=232) - menu.Append(233, 'Set Red Label Text', - 'Change label text colour to red') - self.Bind(wx.EVT_MENU, self.OnForegroundRed, id=233) - menu.Append(234, 'Set &Black Label Text', - 'Change label text colour to black') - self.Bind(wx.EVT_MENU, self.OnForegroundBlack, id=234) - - self.mainmenu.Append(menu, '&Options') - - self.plot_options_menu = menu - - # ------------------------------------------------------------------- - ### "Help" Menu Items ############################################ - # ------------------------------------------------------------------- - menu = wx.Menu() - menu.Append(300, '&About', 'About this thing...') - self.Bind(wx.EVT_MENU, self.OnHelpAbout, id=300) - self.mainmenu.Append(menu, '&Help') - - self.SetMenuBar(self.mainmenu) - - # A status bar to tell people what's happening - self.CreateStatusBar(1) - - self.client = PlotCanvas(self) - # define the function for drawing pointLabels -# self.client.SetPointLabelFunc(self.DrawPointLabel) - self.client.pointLabelFunc = self.DrawPointLabel - # Create mouse event for showing cursor coords in status bar - self.client.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) - # Show closest point when enabled - self.client.canvas.Bind(wx.EVT_MOTION, self.OnMotion) - - self.Show(True) - - def DrawPointLabel(self, dc, mDataDict): - """ - This is the fuction that defines how the pointLabels are plotted - - :param dc: DC that will be passed - :param mDataDict: Dictionary of data that you want to use - for the pointLabel - - As an example I have decided I want a box at the curve point - with some text information about the curve plotted below. - Any wxDC method can be used. - - """ - # ---------- - dc.SetPen(wx.Pen(wx.BLACK)) - dc.SetBrush(wx.Brush(wx.BLACK, wx.BRUSHSTYLE_SOLID)) - - sx, sy = mDataDict["scaledXY"] # scaled x,y of closest point - # 10by10 square centered on point - dc.DrawRectangle(sx - 5, sy - 5, 10, 10) - px, py = mDataDict["pointXY"] - cNum = mDataDict["curveNum"] - pntIn = mDataDict["pIndex"] - legend = mDataDict["legend"] - # make a string to display - s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" % ( - cNum, legend, px, py, pntIn) - dc.DrawText(s, sx, sy + 1) - # ----------- - - def OnMouseLeftDown(self, event): - s = "Left Mouse Down at Point: (%.4f, %.4f)" % self.client._getXY( - event) - self.SetStatusText(s) - event.Skip() # allows plotCanvas OnMouseLeftDown to be called - - def OnMotion(self, event): - # show closest point (when enbled) - if self.client.enablePointLabel: - # make up dict with info for the pointLabel - # I've decided to mark the closest point on the closest curve - dlst = self.client.GetClosestPoint( - self.client._getXY(event), pointScaled=True) - if dlst != []: # returns [] if none - curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst - # make up dictionary to pass to my user function (see - # DrawPointLabel) - mDataDict = {"curveNum": curveNum, - "legend": legend, - "pIndex": pIndex, - "pointXY": pointXY, - "scaledXY": scaledXY} - # pass dict to update the pointLabel - self.client.UpdatePointLabel(mDataDict) - event.Skip() # go to next handler - - def OnFilePageSetup(self, event): - self.client.PageSetup() - - def OnFilePrintPreview(self, event): - self.client.PrintPreview() - - def OnFilePrint(self, event): - self.client.Printout() - - def OnSaveFile(self, event): - self.client.SaveFile() - - def OnFileExit(self, event): - self.Close() - - def OnPlotDraw1(self, event): - self.resetDefaults() - self.client.Draw(_draw1Objects()) - - def OnPlotDraw2(self, event): - self.resetDefaults() - self.client.Draw(_draw2Objects()) - - def OnPlotDraw3(self, event): - self.resetDefaults() - self.client.SetFont(wx.Font(10, - wx.FONTFAMILY_SCRIPT, - wx.FONTSTYLE_NORMAL, - wx.FONTWEIGHT_NORMAL) - ) - self.client.fontSizeAxis = 20 - self.client.fontSizeLegend = 12 - self.client.xSpec = 'min' - self.client.ySpec = 'none' - self.client.Draw(_draw3Objects()) - - def OnPlotDraw4(self, event): - self.resetDefaults() - drawObj = _draw4Objects() - self.client.Draw(drawObj) -# profile -# start = _time.perf_counter() -# for x in range(10): -# self.client.Draw(drawObj) -## print("10x of Draw4 took: %f sec."%(_time.perf_counter() - start)) -# profile end - - def OnPlotDraw5(self, event): - # Empty plot with just axes - self.resetDefaults() - drawObj = _draw5Objects() - # make the axis X= (0,5), Y=(0,10) - # (default with None is X= (-1,1), Y= (-1,1)) - self.client.Draw(drawObj, xAxis=(0, 5), yAxis=(0, 10)) - - def OnPlotDraw6(self, event): - # Bar Graph Example - self.resetDefaults() - # self.client.SetEnableLegend(True) #turn on Legend - # self.client.SetEnableGrid(True) #turn on Grid - self.client.xSpec = 'none' - self.client.ySpec = 'auto' - self.client.Draw(_draw6Objects(), xAxis=(0, 7)) - - def OnPlotDraw7(self, event): - # log scale example - self.resetDefaults() - self.plot_options_menu.Check(271, True) - self.plot_options_menu.Check(272, True) - self.client.logScale = (True, True) - self.client.Draw(_draw7Objects()) - - def OnPlotDraw8(self, event): - """Box Plot example""" - 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() - - def OnPlotClear(self, event): - self.client.Clear() - - def OnPlotScale(self, event): - if self.client.last_draw is not None: - graphics, xAxis, yAxis = self.client.last_draw - self.client.Draw(graphics, (1, 3.05), (0, 1)) - - def OnEnableZoom(self, event): - self.client.enableZoom = event.IsChecked() - if self.mainmenu.IsChecked(217): - self.mainmenu.Check(217, False) - - ### Grid Events ### - - def _checkOtherGridMenuItems(self): - """ check or uncheck the submenu items """ - self.gridSubMenu.Check(2151, self.client.enableGrid[0]) - self.gridSubMenu.Check(2152, self.client.enableGrid[1]) - self.gridSubMenu.Check(2153, all(self.client.enableGrid)) - - def OnEnableGridX(self, event): - old = self.client.enableGrid - self.client.enableGrid = (event.IsChecked(), old[1]) - self._checkOtherGridMenuItems() - - def OnEnableGridY(self, event): - old = self.client.enableGrid - self.client.enableGrid = (old[0], event.IsChecked()) - self._checkOtherGridMenuItems() - - def OnEnableGridAll(self, event): - self.client.enableGrid = event.IsChecked() - self._checkOtherGridMenuItems() - self.gridSubMenu.Check(2151, event.IsChecked()) - self.gridSubMenu.Check(2152, event.IsChecked()) - - def OnEnableDrag(self, event): - self.client.enableDrag = event.IsChecked() - if self.mainmenu.IsChecked(214): - self.mainmenu.Check(214, False) - - def OnEnableLegend(self, event): - self.client.enableLegend = event.IsChecked() - - def OnEnablePointLabel(self, event): - self.client.enablePointLabel = event.IsChecked() - - def OnEnableAntiAliasing(self, event): - self.client.enableAntiAliasing = event.IsChecked() - - def OnEnableHiRes(self, event): - self.client.enableHiRes = event.IsChecked() - - ### Axes Events ### - - def _checkOtherAxesMenuItems(self): - """ check or uncheck the submenu items """ - self.axesSubMenu.Check(2401, self.client.enableAxes[0]) - self.axesSubMenu.Check(2402, self.client.enableAxes[1]) - self.axesSubMenu.Check(2403, self.client.enableAxes[2]) - self.axesSubMenu.Check(2404, self.client.enableAxes[3]) - self.axesSubMenu.Check(2405, all(self.client.enableAxes[:2])) - self.axesSubMenu.Check(2406, all(self.client.enableAxes)) - - def OnEnableAxesBottom(self, event): - old = self.client.enableAxes - self.client.enableAxes = (event.IsChecked(), old[1], old[2], old[3]) - self._checkOtherAxesMenuItems() - - def OnEnableAxesLeft(self, event): - old = self.client.enableAxes - self.client.enableAxes = (old[0], event.IsChecked(), old[2], old[3]) - self._checkOtherAxesMenuItems() - - def OnEnableAxesTop(self, event): - old = self.client.enableAxes - self.client.enableAxes = (old[0], old[1], event.IsChecked(), old[3]) - self._checkOtherAxesMenuItems() - - def OnEnableAxesRight(self, event): - old = self.client.enableAxes - self.client.enableAxes = (old[0], old[1], old[2], event.IsChecked()) - self._checkOtherAxesMenuItems() - - def OnEnableAxesBottomLeft(self, event): - checked = event.IsChecked() - old = self.client.enableAxes - self.client.enableAxes = (checked, checked, old[2], old[3]) - self._checkOtherAxesMenuItems() - - def OnEnableAxesAll(self, event): - checked = event.IsChecked() - self.client.enableAxes = (checked, checked, checked, checked) - self._checkOtherAxesMenuItems() - - ### Ticks Events ### - - def _checkOtherTicksMenuItems(self): - """ check or uncheck the submenu items """ - self.ticksSubMenu.Check(2501, self.client.enableTicks[0]) - self.ticksSubMenu.Check(2502, self.client.enableTicks[1]) - self.ticksSubMenu.Check(2503, self.client.enableTicks[2]) - self.ticksSubMenu.Check(2504, self.client.enableTicks[3]) -# self.ticksSubMenu.Check(2505, all(self.client.enableTicks[:2])) -# self.axesSubMenu.Check(2506, all(self.client.enableTicks)) - - def OnEnableTicksBottom(self, event): - old = self.client.enableTicks - self.client.enableTicks = (event.IsChecked(), old[1], - old[2], old[3]) - self._checkOtherTicksMenuItems() - - def OnEnableTicksLeft(self, event): - old = self.client.enableTicks - self.client.enableTicks = (old[0], event.IsChecked(), - old[2], old[3]) - self._checkOtherTicksMenuItems() - - def OnEnableTicksTop(self, event): - old = self.client.enableTicks - self.client.enableTicks = (old[0], old[1], - event.IsChecked(), old[3]) - self._checkOtherTicksMenuItems() - - def OnEnableTicksRight(self, event): - old = self.client.enableTicks - self.client.enableTicks = (old[0], old[1], - old[2], event.IsChecked()) - self._checkOtherTicksMenuItems() - - ### AxesValues Events ### - - def OnEnableAxesValuesBottom(self, event): - old = self.client.enableAxesValues - self.client.enableAxesValues = (event.IsChecked(), old[1], - old[2], old[3]) - - def OnEnableAxesValuesLeft(self, event): - old = self.client.enableAxesValues - self.client.enableAxesValues = (old[0], event.IsChecked(), - old[2], old[3]) - - def OnEnableAxesValuesTop(self, event): - old = self.client.enableAxesValues - self.client.enableAxesValues = (old[0], old[1], - event.IsChecked(), old[3]) - - def OnEnableAxesValuesRight(self, event): - old = self.client.enableAxesValues - self.client.enableAxesValues = (old[0], old[1], - old[2], event.IsChecked()) - - ### Other Events ### - - def OnEnablePlotTitle(self, event): - self.client.enablePlotTitle = event.IsChecked() - - def OnEnableAxesLabels(self, event): - self.client.enableAxesLabels = event.IsChecked() - - def OnEnableCenterLines(self, event): - self.client.enableCenterLines = event.IsChecked() - - def OnEnableDiagonals(self, event): - self.client.enableDiagonals = event.IsChecked() - - def OnBackgroundGray(self, event): - self.client.SetBackgroundColour("#CCCCCC") - self.client.Redraw() - - def OnBackgroundWhite(self, event): - self.client.SetBackgroundColour("white") - self.client.Redraw() - - def OnForegroundRed(self, event): - self.client.SetForegroundColour("red") - self.client.Redraw() - - def OnForegroundBlack(self, event): - self.client.SetForegroundColour("black") - self.client.Redraw() - - def OnLogX(self, event): - self.client.logScale = (event.IsChecked(), self.client.logScale[1]) - self.client.Redraw() - - def OnLogY(self, event): - self.client.logScale = (self.client.logScale[0], event.IsChecked()) - self.client.Redraw() - - def OnAbsX(self, event): - self.client.absScale = (event.IsChecked(), self.client.absScale[1]) - self.client.Redraw() - - def OnAbsY(self, event): - self.client.absScale = (self.client.absScale[0], event.IsChecked()) - self.client.Redraw() - - def OnScrUp(self, event): - self.client.ScrollUp(1) - - def OnScrRt(self, event): - self.client.ScrollRight(2) - - def OnReset(self, event): - self.client.Reset() - - def OnHelpAbout(self, event): - from wx.lib.dialogs import ScrolledMessageDialog - about = ScrolledMessageDialog(self, __doc__, "About...") - about.ShowModal() - - def resetDefaults(self): - """Just to reset the fonts back to the PlotCanvas defaults""" - self.client.SetFont(wx.Font(10, - wx.FONTFAMILY_SWISS, - wx.FONTSTYLE_NORMAL, - wx.FONTWEIGHT_NORMAL) - ) - self.client.fontSizeAxis = 10 - self.client.fontSizeLegend = 7 - self.client.logScale = (False, False) - self.client.xSpec = 'auto' - self.client.ySpec = 'auto' - - -def __test(): - - class MyApp(wx.App): - - def OnInit(self): - wx.InitAllImageHandlers() - frame = TestFrame(None, -1, "PlotCanvas") - # frame.Show(True) - self.SetTopWindow(frame) - return True - - app = MyApp(0) - app.MainLoop() - - -if __name__ == '__main__': - __test()