Commit 0f87706a authored by Yori Fournier's avatar Yori Fournier
Browse files

Merge branch '49-make-myaxes-client' into 'MIL-server-client-branch'

Resolve "FEATURE - make the client version of myAxes"

See merge request !43
parents 9f42d865 f33facce
......@@ -63,11 +63,14 @@ if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
from matplotlib.figure import Figure
from matplotlib import is_interactive
from matplotlib import use
from .config import D_HOST, D_PORT
from socket import socket, AF_INET, SOCK_STREAM
elif D_HIERARCHY in ('SERVER', 'server'):
print(INFO+'Import myplotlib as a server.')
from .config import D_HOST, D_PORT
from socket import socket, AF_INET, SOCK_STREAM
from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
else:
print(SEVR+'the value of D_HIERARCHY has to be SERVER or CLIENT')
......@@ -90,11 +93,42 @@ if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
# BACKEND: u'TKAgg', u'GTKAgg', u'WXAgg', u'Qt4Agg', u'MacOSX'
rcParams['backend'] = u'GTKAgg'
if D_HIERARCHY in ('CLIENT', 'client'):
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes_client import MyAxes_client as MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig_client import MyFig_client as MyFig
from .serverInterface import ServerInterface
elif(D_HIERARCHY in ('SERVER', 'server')):
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes_server import MyAxes_server as MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig_server import MyFig_server as MyFig
# from .test import FigTestServer
from .test import FigTest
elif D_HIERARCHY in ('LOCAL', 'local'):
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes import MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig import MyFig
else:
print(SEVR+'the value of D_HIERARCHY has to be SERVER, CLIENT or LOCAL')
raise ImportError
if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
_G_WINDOWS = []
......@@ -112,20 +146,6 @@ if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
else:
print(SEVR + "The backend you choosed is not supported interactive mode not available")
elif(D_HIERARCHY in ('SERVER', 'server')):
# MyAxes: Overlay on matplotlib.Axes class
from .myAxes_server import MyAxes_server as MyAxes
# MyFig: Overlay on matplotlib.Figure class
from .myFig_server import MyFig_server as MyFig
else:
print(SEVR+'the value of D_HIERARCHY has to be SERVER, CLIENT or LOCAL')
raise ImportError
# myTool.*: interface functions to use myplotlib interactively
#from .mytool import print2file # need to make tools for server ?? or just put them in client/local
#from .mytool import FigOneAxes
......@@ -141,5 +161,9 @@ if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
if D_HIERARCHY in ('CLIENT', 'client', 'LOCAL', 'local'):
from .test import myTest
from .test import testList
# from .test import myTest
# from .test import testList
from .test import FigTest
# for testing purpose
from .test import readStupidData
......@@ -149,6 +149,7 @@ elif run4Plot:
elif run4server:
from .server import Server
from .test import readStupidData
server = Server()
server.init()
......
......@@ -4,7 +4,7 @@ from .myData import MyData
D_VERSION='v5'
D_HIERARCHY='SERVER'
D_HOST='localhost'
D_PORT=50228
D_PORT=50803
# FORM -----------------------------------------------------------------
INFO = " > info-: "
......
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# ================= FILE HEADER ========================================
#
# myplotlib v3.0.1,
#
# @file myAxes.py
# @author Yori 'AGy' Fournier
# @licence CC-BY-SA
#
# MyAxes class: Overlay of matplotlib Axes class
# It is done such that the user can concentrate on
# the important aspect of the figure and not the
# technical part. It consists of a constructor,
# that requires a Figure, the ratio of the xaxis over
# the yaxis, and the frame in which the figure
# should be plotted.
#
# @Class MyAxes
#
# @Constructor(self, fig, ratio, frame, +user defined kw):
#
# @section Functions
#
# - plotting: this is the overwritten function
# from Axes. It is called by it's
# parent-figure's function .plot()
#
# - formatRawData: it computes out of the rawData
# given as argument some quantities that
# are returned as a dictionary and
# become accessable for plotting.
#
# @section History
#
# v 0.0.0 - MyAxes class for the myplotlib module, consists
# of a constructor, a pltting function and
# formatRawData.
#
# v 2.2.3 - Add testRawData function
#
# ======================================================================
#
#
# IMPORT ---------------------------------------------------------------
from . import SEVR, DBUG
from . import Axes
from . import rcParams
# Class MyAxes Overwriting Matplotlib.figure.Axes
class MyAxes_client(Axes):
# CONSTRUCTOR --------------------------------------------------------
def __init__(self, fig, ratio, frameRect, *args, **kwargs):
self.fig = fig
self.declareKeywords()
rect = self.computeRect(ratio, frameRect, *args, **kwargs)
kwargs.pop('forceRatioOnWidth', None)
kwargs.pop('forceRatioOnHeight', None)
# parent constructor
Axes.__init__(self, fig, rect, **kwargs)
# set a default name. Should be individualized by instance
self.name = 'default'
# COMPUTE RECT -------------------------------------------------------
def computeRect(self, ratio, frameRect, *args, **kwargs):
# Get the optional keyword
forceRatioOnWidth = kwargs.pop('forceRatioOnWidth', None)
forceRatioOnHeight = kwargs.pop('forceRatioOnHeight', None)
# get the frame allowed
framePosX, framePosY, frameWidth, frameHeight = frameRect
# get the size of the figure
figWidth = self.fig.get_figwidth()
figHeight = self.fig.get_figheight()
if(forceRatioOnWidth):
frameWidth = ratio * figWidth / (frameHeight * figHeight)
elif(forceRatioOnHeight):
frameHeight = ratio * (frameWidth * figWidth) / figHeight
rect = [framePosX, framePosY, frameWidth, frameHeight]
return(rect)
# DECLARE KEYWORDS -------------------------------------------------
def declareKeywords(self):
self.keywords = {}
# PLOTTING -----------------------------------------------------------
def plotting(self):
return(True)
# UPDATE -------------------------------------------------------------
def update(self, *args, **kwargs):
# Because matplotlib.axes.update expect kwargs and not **kwargs ... (stupid!!)
if args: # catch matplotlib kwargs
kwargs = args[0]
# kw_for_axes = {key: value for (key, value) in args[0].items() if key not in self.keywords} # Not compatible with python2.6
kw_for_axes = {}
for (key, value) in args[0].items():
if key not in self.keywords:
kw_for_axes.update({key: value})
Axes.update(self, kw_for_axes) # update matplotlib.Axes
# myplotlib update
# self.keywords.update({key: value for (key, value) in kwargs.items() if key in self.keywords}) # Not compatible with python2.6
for (key, value) in kwargs.items():
if key in self.keywords:
self.keywords.update({key: value})
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# ================= FILE HEADER ========================================
......
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# ================= FILE HEADER ========================================
#
# myplotlib v3.0.1,
#
# @file myFig.py
# @author Yori 'AGy' Fournier
# @licence CC-BY-SA
#
# MyFig class: Overlay of matplotlib Figure class
# It is done such that the user can concentrate on
# the important aspect of the figure and not the
# technical part.
#
# @Class MyFig
#
# @Constructor
#
# fignum: number of the Figure.
# reformat: flag for reComputing plotted data
# from rawData.
# debug: flag for debugging, more verbatile.
# (kw)args: user defined arguments and keywords.
#
# @section Functions
#
# - printDebug: print some debug information.
#
# - plot: overlay of Figure.plot() function,
# should be overwrited by the user.
# Consists of
# - creating axes,
# - formating the data,
# - adding the axis to the figure
# - plotting the axis
#
# - update: update the parameters in the
# keywords dictionary.
#
# @section History
#
# v 0.1.1 - MyFig class for the myplotlib module.
#
# v 1.0.0 - Changed rawdata with inputarg to allows any type
# of rawdata, can be an array.
#
# replace the attribute format (reserved word) with
# formatted.
#
# v 1.0.1 - Suppress the explicit definitions of the keywords.
# by the introduction of the keywords dictionary.
# All parameters in this dictionary are automatically
# updated.
#
# suppress the default value of fignum and hardcode it
# to be -1.
#
# add the attribute boundedToWin required for the
# interactive mode of myplotlib.
#
# v 2.2.3 - Allow the possibility of giving a unique rawdata format
# all axes. /!\ self.rawdata is a generator. /!\
#
# ======================================================================
#
#
# IMPORT ---------------------------------------------------------------
from . import os
from . import D_FIGSIZE, D_INPUTARG, D_DEBUG, D_REFORMAT, D_FORMATTED
from . import D_OFORMAT, D_OPATH
from . import DBUG, SEVR, INFO, SPCE, WARN
from . import MyData
from . import MyAxes
from . import Figure
# Class MyFig Overwriting Matplotlib.figure.Figure
class MyFig_client(Figure):
# Set the size of the Figure in inch
# (private variable can not be updated)
FIGSIZE = D_FIGSIZE
# CONSTRUCTOR --------------------------------------------------------
def __init__(self, rawdata, *args, **kwargs):
# for the update function
self._attributesToUpdateKeys = ['fignum', 'reformat', 'debug', 'formatted', 'aliases']
# initialise the attribute default values and remove them from kwargs
self.fignum = kwargs.pop('fignum', -1) # need to be hard coded for interactive mode
self.reformat = kwargs.pop('reformat', D_REFORMAT)
self.debug = kwargs.pop('debug', D_DEBUG)
self.formatted = kwargs.pop('formatted', D_FORMATTED)
self.aliases = {}
self.syncID = -1
self.client = None
self.FIGSIZE = kwargs.pop('figsize', self.FIGSIZE)
# parent constructor
Figure.__init__(self, figsize=self.FIGSIZE)
# This is required for the interactive mode
# it ensures that a figure can not be bounded
# to several windows and prevent the loss of canvas.
self.boundedToWin = False
# initialise
self._initialize(*args, **kwargs)
# INITIALIZE -------------------------------------------------------
def _initialize(self, *args, **kwargs):
# add the axes
self.addAxes()
# declare the aliases
self.declareAliases()
# update the attributes and keywords
self.update(**kwargs)
# UPDATE ----------------------------------------------------------
def update(self, **kwargs):
# check attributes in keywords
for keyword in kwargs.keys():
# if it is an attribute
if keyword in self._attributesToUpdateKeys:
# update value
setattr(self, keyword, kwargs[keyword])
# For each axes update the keywords
for ax in self.get_axes():
forax = {}
for keyword in kwargs.keys():
# ignore figure attributes
if keyword in self._attributesToUpdateKeys :
pass
# Check if a key of kwargs has an alias for this axes
elif keyword in self.aliases.keys():
alax, alkey = self.aliases[keyword]
# If an alias is found then update axkwargs
if ax == alax:
forax.update(**{alkey: kwargs[keyword]})
# use keyword as it is for the axes
else :
forax.update(**{keyword : kwargs[keyword]})
# Then eventually all collected Keywords are updated in one go
if (forax) :
if self.debug:
print (DBUG+' fig.update ', ax, 'keywords: ', forax)
ax.update(**forax)
return(True)
# DECLARE ALIASES -------------------------------------------------
def declareAliases(self):
pass
# ADD AXES ---------------------------------------------------------
def addAxes(self, *arg, **kwargs):
pass
# This overwrites MPL add_axes. It gives a name to the axis added so that it is easier to refer to
def add_axes(self, ax, name) :
# if isinstance(name, str) and issubclass(ax.__class__, MyAxes): # This lead to an error is ax is not in the same namespace
ax.name = name
# else:
# print(SEVR + " there is an error with the input type of add_axes()")
# return False
# test if an axes with that name is already present
for pax in self.get_axes() :
if pax.name == name :
print(SEVR + " an axes with that name is already present")
return False
Figure.add_axes(self, ax)
return True
# GET AXES BY NAME -------------------------------------------------
def getAxesByName(self, name):
for ax in self.get_axes() :
if ax.name == name :
return ax
#if the name is correct we should never get here.
print(SEVR + "The axes name ", name, " was not found")
return None
# FORMAT RAW DATA --------------------------------------------------
def formatRawData(self):
# HEre comes a function that send a signal to the server
# and tells him to execute the format rawdata of the
# synchronized figure (server-side)
if (self.client is not None) and (self.syncID != -1):
try:
datas = self.client.syncFigFormatRawData(self.syncID)
except:
print(SEVR+'The server-side figure could not format the data...')
return(False)
for ax, data in zip(self.get_axes(), datas):
ax.data = data
else:
print(SEVR+'The figure is not properly synchronized.')
return(False)
return(True)
# PLOT -------------------------------------------------------------
def plot(self):
status = True
if(self.debug):
print(DBUG + "currently formatting the data...")
if((self.reformat) or (not self.formatted)):
status = self.formatRawData()
if(not status): return(False)
if(self.debug):
print(DBUG + "currently plotting the axes...")
# For all axes in the figure reformat if needed and plot
for ax in self.get_axes():
# clean the axes
ax.cla()
# plot
plottingStatus = ax.plotting()
status = status and plottingStatus
return(status)
# RESET ------------------------------------------------------------
def reset(self, *args, **kwargs):
self.clf()
self._initialize(*args, **kwargs)
self.plot()
# DEBUG --------------------------------------------------------------
def printDebug(self):
className = str(self.__class__.__name__)
print('\n' + DBUG + " {0} PARAMETERS: ".format(className))
print(SPCE + " ID the figure: " + str(self.fignum))
print(SPCE + "Size of the figure: " + str(self.FIGSIZE) + ' [inch] \n')
# PRINT 2 FILE -------------------------------------------------------
def print2file(self, filename, *args, **kwargs):
# get the keywords
debug = kwargs.get('debug', D_DEBUG)
oformat = kwargs.get('oformat', D_OFORMAT)
opath = kwargs.get('opath', D_OPATH)
as_seen = kwargs.get('as_seen', False)
# set the dpi
if(oformat == 'png'):
dpi = 300.
addMetaData = True # NOT YET IMPLEENTED
else:
dpi = 100.
addMetaData = False # NOT YET IMPLEMENTED
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
# if the figure is boundedToWin
# save to canvas in a local variable and restore after saving to file.
if self.boundedToWin:
winCanvas = self.canvas
else:
winCanvas = None
canvas = FigureCanvas(self) # the canvas of the figure changed
# Plot the figure
if not as_seen:
status = self.plot()
if not status:
print(SEVR + 'Can not plot the figure. sorry --> EXIT')
return(False)
# draw the figure on the new canvas
canvas.draw() # not really needed (savefig does that)
# check if the extention is in the name
if '.png' in str(filename):
oformat = 'png'
filename = filename[:-4]
elif '.eps' in str(filename):
oformat = 'eps'
filename = filename[:-4]
# check if the path is in the name
if '/' in str(filename):
if(debug):
print(WARN + "I detect that the path is in the name of the file, will ignore D_OPATH.")
arg = filename
filename = os.path.basename(arg)
opath = os.path.dirname(arg)
# take care of the . in the extention
if oformat[0] == '.':
oformat = oformat[1:]
# clean the output path
if str(opath)[-1] == '/':
opath = str(opath)[:-1]
else:
opath = str(opath)
# print into a file
try:
self.savefig(str(opath) + '/' + str(filename) + '.' + str(oformat), dpi=dpi) # ! this not the save from plt but from fig
except IOError:
print(SEVR + 'the path to the file does not exists:')
print(SPCE + str(opath) + '/' + str(filename) + '.' + str(oformat) + ' --> EXIT')
return(False)
except:
print(SEVR + 'Can not save file. sorry --> EXIT')
return(False)
# restore the former canvas
if winCanvas is not None:
self.canvas = winCanvas
return(True)
from . import socket, AF_INET, SOCK_STREAM
from . import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
from . import D_HOST
from . import D_PORT
from . import INFO, DBUG, WARN, SEVR, SPCE
from . import readStupidData
from . import FigTest
G_RAWDATA = {}
G_FIGURES = {}
class Server():
def __init__(self):
self.soc = socket(AF_INET, SOCK_STREAM)
self.soc.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # requires some extra import
self.host = D_HOST
self.port = D_PORT
self.answer = None
def init(self):
self.soc.bind((self.host, self.port))
......@@ -20,25 +25,134 @@ class Server():
def run(self):
signal = False
while True:
if not self.answer:
if not signal:
conn, addr = self.soc.accept()
print(INFO + 'Connected by ' + str(addr))
self.answer = conn.recv(1024)
signal = conn.recv(1024)
if self.answer in ('KILL', 'kill', 'Kill'):
if signal in ('KILL', 'kill', 'Kill'):
print(INFO+"Recieved 'Kill' signal.")
conn.close()
break
elif signal != '':