1#!/usr/local/bin/python3.8
2
3# a basic realtime_receiver plotting library
4
5import sys, os
6
7# verify system libraries
8from afnipy import module_test_lib
9g_testlibs = ['gc', 'numpy', 'wx', 'matplotlib']
10if module_test_lib.num_import_failures(g_testlibs,details=0):
11   print """
12     -- for details, consider xmat_tool -test_libs
13     -- also, many computations do not require the GUI
14        (e.g. 'xmat_tool -load_xmat X.xmat.1D -show_cormat_warnings')
15   """
16   sys.exit(1)
17
18import numpy as N
19import gc
20
21# must use matplotlib with wx, not pylab
22import wx
23import matplotlib
24matplotlib.use('WX')
25
26# set some resource font values
27matplotlib.rc('axes',titlesize=11)
28matplotlib.rc('axes',labelsize=9)
29matplotlib.rc('xtick',labelsize=8)
30matplotlib.rc('ytick',labelsize=7)
31
32from matplotlib.backends.backend_wx import FigureCanvasWx as FigureCanvas
33from matplotlib.backends.backend_wx import NavigationToolbar2Wx
34from matplotlib.figure import Figure
35
36from matplotlib.ticker import FormatStrFormatter
37
38from afnipy import afni_util as UTIL
39
40# ======================================================================
41# general plotting routine:
42#
43
44def plot(data, title='', verb=1):
45   """plot data"""
46
47   frame = CanvasFrame(title=title, verb=verb)
48
49   if title == '': title = 'basic plot'
50   frame.SetTitle(title)
51
52   frame.Show(True)
53   frame.plot_data(data)
54
55   return 0, frame
56
57
58# ======================================================================
59# main plotting canvas class
60
61class CanvasFrame(wx.Frame):
62   """create a main plotting canvas
63        title   : optional window title
64        verb    : verbose level (default 1)
65   """
66
67   counter = 0
68   def __init__(self, title='', verb=1):
69      wx.Frame.__init__(self, None, -1, title, size=(400,300))
70      self.verb   = verb
71      self.figure = Figure()
72      self.canvas = FigureCanvas(self, -1, self.figure)
73      self.sizer = wx.BoxSizer(wx.VERTICAL)
74      self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
75      self.SetSizer(self.sizer)
76      self.Fit()
77
78      # toolbar?
79      # self.toolbar = NavigationToolbar2Wx(self.canvas)
80      # self.toolbar.Realize()
81      # self.sizer.Add(self.toolbar, 0, wx.BOTTOM | wx.EXPAND)
82      # self.toolbar.update()
83
84      # axis plotting info
85      self.ax     = None
86      self.xmin   = 1.0
87      self.xmax   = 0.0
88      self.ymin   = 1.0
89      self.ymax   = 0.0
90      self.xlabel = ''
91      self.ylabel = ''
92      self.style  = 'graph'
93
94      self.images = []
95
96      self.toolbar = NavigationToolbar2Wx(self.canvas)
97      self.toolbar.Realize()
98      self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
99      self.toolbar.update()
100
101   def cb_keypress(self, event):
102      if event.key == 'q':
103         self.Close()
104
105   def set_limits(self, xmin=1.0, xmax=0.0, ymin=1.0, ymax=0.0):
106      """if xmin < xmax: apply, and similarly for y"""
107      if xmin < xmax:
108         self.xmin = xmin
109         self.xmax = xmax
110         if self.verb > 2: print '-- resetting xlimits to:', xmin, xmax
111      if ymin < ymax:
112         self.ymin = ymin
113         self.ymax = ymax
114         if self.verb > 2: print '-- resetting ylimits to:', ymin, ymax
115
116   def plot_data(self, data, title=''):
117      """plot data
118         style can be 'graph' or 'bar'"""
119
120      if self.ax == None:
121         self.ax = self.figure.add_subplot(1,1,1,title=title)
122
123      self.ax.clear()
124
125      if self.style == 'graph':
126         self.ax.plot(data)
127         self.ax.grid(True)
128      else:     # bars of width 1
129         offsets = N.arange(len(data))
130         bars = self.ax.bar(offsets, data, 1)
131
132      self.ax.set_xlabel(self.xlabel)
133      self.ax.set_ylabel(self.ylabel)
134
135      # after data is plotted, set limits
136      if self.xmin < self.xmax: self.ax.set_xlim((self.xmin, self.xmax))
137      if self.ymin < self.ymax: self.ax.set_ylim((self.ymin, self.ymax))
138
139      self.Fit()        # maybe not applied without a running app loop
140      self.canvas.draw()
141
142   def exit(self):
143      self.Destroy()
144
145