#######################################################################
#
# $Id: PlotSmith.py,v 1.2 2008-04-07 05:09:35 lorenz Exp $
# 
# Copyright (C) 2004-2008 Petr Lorenz
# All rights reserved.
# 
# ##### BEGIN LICENSE BLOCK #####
#
# Version: MPL 1.1 / GPL 2.0 / LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
# 
# The Original Code is Petr Lorenz emGine Graphical User Interface (GUI).
# 
# The Initial Developer of the Original Code is Petr Lorenz.
# Portions created by the Initial Developer are Copyright (C) 2004-2008.
# All Rights Reserved.
#
# Contributor(s): Sherif Sayed Ahmed
# 
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the  "GPL"), or the
# GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
# case the provisions of the GPL or the LGPL are applicable instead of those
# above.  If you wish to allow use of your version of this file only under the
# terms of either the GPL or the LGPL and not to allow others to use your
# version of this file under the MPL, indicate your decision by deleting the
# provisions above and replace them with the notice and other provisions
# required by the GPL or LGPL.  If you do not delete the provisions above, a
# recipient may use your version of this file under the terms of any one of the
# MPL License, the GPL or the LGPL.
#
# ##### END LICENSE BLOCK #####
#
#######################################################################
# 
# $Log: PlotSmith.py,v $
# Revision 1.2  2008-04-07 05:09:35  lorenz
# Smith diagram integration.
#
# Revision 1.1  2008-03-28 06:18:27  lorenz
# Initial commit.
#
#
#######################################################################

#
# March 2008
#
# 2D plotting with matplotlib
#
import wx

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure

##import XYDataSource

# to calculate the phases
from numpy import *

##def phase(num):
##    return math.atan2(num.imag, num.real)
##  
class PlotSmith:
  def __init__(self, master):

    self.hold = 0
    
    # create the matplotlib-based Plot
    self.figure = Figure(facecolor = 'w')
  
    self.figure_canvas = FigureCanvas(master, -1, self.figure)
    self.hide()		# hide the widget

  def clear(self):
    self.figure.clf()

  def hold_on(self):
    self.hold = True
    self.axes.hold(True)

  def hold_off(self):
    self.hold = False
    self.axes.hold(False)

  def set_dimensions(self, x1, y1, x2, y2):
    self.figure_canvas.SetDimensions(x1, y1, x2, y2)

  def show(self):
    self.figure_canvas.Show(True)

  def hide(self):
    self.figure_canvas.Show(False)

  def set_legend(self, legend):
    self.axes.set_title(legend, fontsize =20)

  def set_legend_01(self, legend = None):
    #ToDo: autoscale the figure windows to allow good view for the legend box
    
##    self.axes.legend(legend)
    self.axes.legend(handlelen=0.05, loc=(1.06, 0.85), shadow=True)
##    self.axes.autoscale_view


  def plot_data(self,  real_values, imag_values , freq_values, title = "No data name"):
    
    if (len(real_values) != len(imag_values)):
      print "!! Error! Something is wrong with your data to plot"
      return

    if (len(real_values) != len(freq_values)):
      print "!! Error! Something is wrong with your data to plot"
      return

    # convert to numpy array
    data = array(real_values, dtype=complex) 
    data.imag = imag_values
    
    if not self.hold:
      self.figure.clf()
      self.axes = self.figure.add_axes([0.1,0.1,0.8,0.8], polar=True, aspect='equal')
      # plot smithchart circles
      # -----------------------
      self.plotsmithcircles()
    
    # Plot the data
    #--------------    
    self.axes.set_rmax(1)
    self.axes.plot(angle(data),abs(data),label=title,linewidth = 2,zorder=10)
    #self.axes.set_title( "Smith chart" , fontsize =20)
   
    # Show freq limits
    #-----------------
    self.axes.plot([angle(data[0])],[abs(data[0])],'oc',linewidth = 5,zorder=10)
    self.axes.plot([angle(data[len(data)-1])],[abs(data[len(data)-1])],'sm',linewidth = 5,zorder=10)

    # Disable Polar grid
    #------------------- 
    self.axes.set_rgrids([.001,999],['',''])
    self.axes.set_thetagrids([0,99],['',''])
    self.axes.grid(False)
    
  def plotsmithcircles(self):
    linetype = 'k'
    linewidth = 0.5
    linewidth2 = 1.5

    # plot R circle  
    r_array = (0.0, 0.2, 0.4, 0.7, 1.0, 1.4, 2.0, 3.0, 5.0)
    z = zeros((1,2000),complex)
    z.imag = arange(-50,50,0.05) 
    x_shift = 1e-3 # can be 1e-3 but not zero
    for r in r_array:
      z.real = r
      gamma_r = transpose((z-1)/(z+1))
      
      if r==1:
	self.axes.plot(angle(gamma_r), abs(gamma_r), linetype,linewidth = linewidth2,zorder=0)
      else:
	self.axes.plot(angle(gamma_r), abs(gamma_r), linetype,linewidth = linewidth,zorder=0)
      
      if not r==0:
	self.axes.text(angle((r+x_shift*1j-1)/(r+x_shift*1j+1)), 1e-6+abs((r+x_shift*1j-1)/(r+x_shift*1j+1)), "%.1f" %(r), backgroundcolor='white', alpha=1, horizontalalignment='center', verticalalignment='center', rotation=0)      
            
    # plot X circle   
    x_array = (0.2, 0.4, 0.6, 0.8, 1.0, 1.4, 2.0, 3.0, 5.0, 10.0)
    z = zeros((1,1000),complex)
    z.real = arange(0, 100, 0.1)
    for x in x_array:
      z.imag = x
      gamma_x = transpose((z-1)/(z+1))
      
      if x==1:
	self.axes.plot(angle(gamma_x),abs(gamma_x), linetype,linewidth = linewidth2,zorder=0)
      else:
	self.axes.plot(angle(gamma_x),abs(gamma_x), linetype,linewidth = linewidth,zorder=0)
	  
	  
      self.axes.text(angle((x*1j-1)/(x*1j+1)),1.05,"%.1f" %(x),horizontalalignment='center',verticalalignment='center',rotation=angle((x*1j-1)/(x*1j+1),'Degrees')-90)
        
    for x in multiply(-1,x_array):
      z.imag = x
      gamma_x = transpose((z-1)/(z+1))
      
      if x==-1:
	self.axes.plot(angle(gamma_x),abs(gamma_x), linetype,linewidth = linewidth2,zorder=0)
      else:
	self.axes.plot(angle(gamma_x),abs(gamma_x), linetype,linewidth = linewidth,zorder=0)
	  
      self.axes.text(angle((x*1j-1)/(x*1j+1)),1.05,"%.1f" %(x),horizontalalignment='center',verticalalignment='center',rotation=angle((x*1j-1)/(x*1j+1),'Degrees')+90)
 
    # plot X=0 line
    self.axes.plot([-pi , 0],[1 , 1], linetype,linewidth = linewidth2 ,zorder=0)
    self.axes.text(-pi ,1.0,'0',horizontalalignment='center',verticalalignment='center',rotation = 0 , backgroundcolor='white',fontsize=12)
 
    # plot infinite symbol
    self.axes.text(0 ,1.0,'$\infty$',horizontalalignment='center',verticalalignment='center',rotation = 0 , backgroundcolor='white',fontsize=12)

  def plot_dummy(self):

    r = transpose(.1+arange ( 0 , 0.7 , 0.001))
    theta = -4.5 * pi *r
    freq = r*10e9
    data = multiply(r,exp(1j*theta))

    self.plot_data(data.real, data.imag,freq,'my first data')
    
    self.hold_on()


    r = transpose(arange ( 0 , 0.9 , 0.001))
    theta = +2 * pi *r
    freq = r*10e9
    data = multiply(r,exp(1j*theta))

    self.plot_data(data.real, data.imag,freq,'my second data')
    
    self.set_legend("Smith Chart Plot")
    self.set_legend_01()

###############################################
if __name__ == '__main__':
  print "Testing PlotSmith Module..."


  app = wx.PySimpleApp()
  frame = wx.Frame(None, -1, "Testing PlotSmith Module", size = (800, 600))
  frame.Show(True)

  PlotSmith = PlotSmith(frame)
  PlotSmith.plot_dummy()
  PlotSmith.show()

  app.MainLoop()

  app.Destroy() 

