Commit 8b010b61 authored by Yori Fournier's avatar Yori Fournier
Browse files

Merge branch '66-feature-resyncfig' into 'dev'

Resolve "FEATURE : reSyncFig"

Closes #66

See merge request !49
parents 35162722 6cbe381f
Pipeline #454 passed with stage
in 2 minutes and 51 seconds
...@@ -104,9 +104,32 @@ class MplClient2(): ...@@ -104,9 +104,32 @@ class MplClient2():
def listRemoteData(self): def listRemoteData(self):
""" The server retuns a list with the content of its G_RAWDATA """ The server retuns a list with the content of its G_RAWDATA
not implemented yet.
""" """
pass query = Query(Query.LISTDATA,None)
status = self.send(query)
if not status :
print('something went wrong with the sending of readData request...')
answer = self.waitForSignal()
if isinstance(answer,Answer) :
return answer.content
elif isinstance(answer,Status):
print(answer.content)
return None
def getData(self, dataname) :
""" The server returns the actual data known under "dataname" warning: this can possibly be HUGE
"""
query = Query(Query.GETDATA,dataname)
status = self.send(query)
if not status :
print('something went wrong with the sending of readData request...')
answer = self.waitForSignal()
if isinstance(answer,Answer) :
return answer.content
elif isinstance(answer,Status):
print(answer.content)
return None
def newSyncFigure(self, figname, dataname, *args, **kwargs) : def newSyncFigure(self, figname, dataname, *args, **kwargs) :
''' '''
...@@ -125,7 +148,7 @@ class MplClient2(): ...@@ -125,7 +148,7 @@ class MplClient2():
# try to create a figure of the same class on the client side # try to create a figure of the same class on the client side
if isinstance(answer,Answer) : if isinstance(answer,Answer) :
print('trying to create a figure of the same class on the client side') print('trying to create a figure of the same class on the client side')
fig = figname( MyData(), *args, **kwargs) fig = figname( dataname, *args, **kwargs)
# Link the temporary Sync Figure # Link the temporary Sync Figure
fig.syncID = answer.content fig.syncID = answer.content
fig.client = self fig.client = self
......
...@@ -136,14 +136,8 @@ class MplHandler(SocketServer.StreamRequestHandler): ...@@ -136,14 +136,8 @@ class MplHandler(SocketServer.StreamRequestHandler):
print(SPCE+"SERVER: Exception details where:",e.message, e.args ) print(SPCE+"SERVER: Exception details where:",e.message, e.args )
return Status(False,"I couldn't format the rawdata. Exception details where:",e.message, e.args) return Status(False,"I couldn't format the rawdata. Exception details where:",e.message, e.args)
# compose the answer # compose the formated data
datas = () datas = tuple(ax.data for ax in fig.get_axes())
for ax in fig.get_axes():
# ax.data is any user defined object
# ax.packFormattedData returns it's string representation
# to be unpacked by ax.unpackFormattedData
# datas.append(ax.packFormattedData(ax.data))
datas = datas + (ax.data,)
return Answer(datas) return Answer(datas)
...@@ -155,6 +149,16 @@ class MplHandler(SocketServer.StreamRequestHandler): ...@@ -155,6 +149,16 @@ class MplHandler(SocketServer.StreamRequestHandler):
else : else :
return Status(False,'Figure with ID '+str(figID)+' not found on server side.') return Status(False,'Figure with ID '+str(figID)+' not found on server side.')
def treatListData(self,content) :
""" list the keys (and possibly (later) the location from G_RAWDATA """
return Answer(G_RAWDATA.keys())
def treatGetData(self,content) :
""" from G_FIGURES """
if content in G_RAWDATA:
return Answer(G_RAWDATA[content])
else :
return Status(False,'Dataname not found in index of the server side...')
def send(self,sig): def send(self,sig):
# pickel the signal # pickel the signal
...@@ -204,6 +208,10 @@ class MplHandler(SocketServer.StreamRequestHandler): ...@@ -204,6 +208,10 @@ class MplHandler(SocketServer.StreamRequestHandler):
return self.treatSyncFigFormatRawData(sig.content) return self.treatSyncFigFormatRawData(sig.content)
elif sig.queryType == sig.DELETESYNCFIGURE : elif sig.queryType == sig.DELETESYNCFIGURE :
return self.treatDeleteSyncFigure(sig.content) return self.treatDeleteSyncFigure(sig.content)
elif sig.queryType == sig.LISTDATA :
return self.treatListData(sig.content)
elif sig.queryType == sig.GETDATA :
return self.treatGetData(sig.content)
else : else :
self.servPrint('received unknown query type') self.servPrint('received unknown query type')
return Status(False,"received unknown query type") return Status(False,"received unknown query type")
......
...@@ -83,7 +83,6 @@ class MyFig_client(Figure): ...@@ -83,7 +83,6 @@ class MyFig_client(Figure):
# (private variable can not be updated) # (private variable can not be updated)
FIGSIZE = D_FIGSIZE FIGSIZE = D_FIGSIZE
# CONSTRUCTOR --------------------------------------------------------
# CONSTRUCTOR -------------------------------------------------------- # CONSTRUCTOR --------------------------------------------------------
def __init__(self, rawdata, *args, **kwargs): def __init__(self, rawdata, *args, **kwargs):
...@@ -110,6 +109,7 @@ class MyFig_client(Figure): ...@@ -110,6 +109,7 @@ class MyFig_client(Figure):
# initialise # initialise
self._initialize(*args, **kwargs) self._initialize(*args, **kwargs)
self.set_rawdata(rawdata)
def deSyncFig(self): def deSyncFig(self):
if self.client is not None : if self.client is not None :
...@@ -119,7 +119,55 @@ class MyFig_client(Figure): ...@@ -119,7 +119,55 @@ class MyFig_client(Figure):
else : else :
print('The figure could not be deleted on the server Side') print('The figure could not be deleted on the server Side')
else: else:
print('The client is not connected to a server yet') print('The client is not connected to a server yet. Please use the client to set up a sync conection.')
def getState(self) :
""" this function collects the current state of in the figure by creating a dict that holds all keyword,value pairs (taking the aliases into account)
Warning: myplotlib allows in a transparent manner to modify the axes directly. Those changes can not be covert.
"""
state = dict()
# test for double keywords and print a waring
for ax in self.axes:
# find aliases for this specific axes
masks = dict()
for alias in self.aliases.keys() :
axes4alias,keyword = self.aliases[alias]
if axes4alias == ax :
masks.update({keyword : alias})
# collect all keywords of the axes and replace the keys with the aliases
axKeywords = ax.keywords.copy()
for mask in masks :
if mask in axKeywords :
axKeywords[masks[mask]] = axKeywords.pop(mask)
# Test if kewords are already set by an other axes
for key in axKeywords.keys() :
if key in state.keys():
print('Warning: The keyword \"',key,'\" appears in multiple axes. The Defaults will be overwritten. Prevent this by using aliases')
# update the global keyword index
state.update(axKeywords)
return state
def reSyncFig(self):
if self.client is not None :
# collect the current state of the figure
state = self.getState()
# call the client to create a new figure on the server side
newFig = self.client.newSyncFigure(self.__class__, self.remote_rawdata, **state)
# since the state matches the current instance. only the new syncID is kept.
self.syncID = newFig.syncID
else:
print('The client is not connected to a server yet. Please use the client to set up a sync conection.')
# INITIALIZE ------------------------------------------------------- # INITIALIZE -------------------------------------------------------
def _initialize(self, *args, **kwargs): def _initialize(self, *args, **kwargs):
...@@ -230,6 +278,19 @@ class MyFig_client(Figure): ...@@ -230,6 +278,19 @@ class MyFig_client(Figure):
print(SEVR + "The axes name ", name, " was not found") print(SEVR + "The axes name ", name, " was not found")
return None return None
#~ def getAxesName(self,unknownax) :
#~ """ compares all axes against the function parameter and returns the name of that axes if found in figure"""
#~
#~ for ax in self.get_axes() :
#~ if unknownax == ax :
#~ return ax.name
# SET RAW DATA -----------------------------------------------------
def set_rawdata(self, rawdata):
''' This function sets loacally the names of the remote data in a similar way as a local figure would do.
Warning : No consitancy checking is done. The server side will report the errors.
'''
self.remote_rawdata = rawdata
# FORMAT RAW DATA -------------------------------------------------- # FORMAT RAW DATA --------------------------------------------------
def formatRawData(self): def formatRawData(self):
......
...@@ -10,9 +10,11 @@ class Query(Signal) : ...@@ -10,9 +10,11 @@ class Query(Signal) :
UPDATESYNCFIGURE = 3 UPDATESYNCFIGURE = 3
SYNCFIGFORMATRAWDATA = 4 SYNCFIGFORMATRAWDATA = 4
DELETESYNCFIGURE = 5 DELETESYNCFIGURE = 5
LISTDATA = 6
GETDATA = 7
def __init__(self,queryType, content) : def __init__(self,queryType, content) :
if queryType in [Query.READDATA,Query.NEWSYNCFIGURE,Query.UPDATESYNCFIGURE,Query.SYNCFIGFORMATRAWDATA,Query.DELETESYNCFIGURE] : if queryType in range(1,8) :
self.queryType = queryType self.queryType = queryType
if queryType == Query.READDATA : if queryType == Query.READDATA :
if type(content) == dict : if type(content) == dict :
...@@ -35,6 +37,10 @@ class Query(Signal) : ...@@ -35,6 +37,10 @@ class Query(Signal) :
elif queryType == Query.DELETESYNCFIGURE : elif queryType == Query.DELETESYNCFIGURE :
self.content = content self.content = content
elif queryType == Query.LISTDATA :
self.content = content
elif queryType == Query.GETDATA :
self.content = content
else : else :
print('unknown query type!') print('unknown query type!')
raise raise
......
...@@ -12,3 +12,30 @@ class FigTest(MyFig): ...@@ -12,3 +12,30 @@ class FigTest(MyFig):
frame1 = [0.1, 0.1, 0.8, 0.8] # part of the fig that is available frame1 = [0.1, 0.1, 0.8, 0.8] # part of the fig that is available
self.add_axes(AxTest(self, ratio, frame1), "p1") self.add_axes(AxTest(self, ratio, frame1), "p1")
class FigTest2(MyFig): # Fig with two Axes
# Set the size of the Figure in inch
# (private variable can not be updated)
FIGSIZE = (8., 6.)
def addAxes(self):
ratio = 6. / 8. # height/width of the axes (in inch)
frame1 = [0.1, 0.1, 0.4, 0.8] # part of the fig that is available
frame2 = [0.6, 0.1, 0.4, 0.8] # part of the fig that is available
self.add_axes(AxTest(self, ratio, frame1),"p1")
self.add_axes(AxTest(self, ratio, frame2),"p2")
def declareAliases(self):
# it is important to not hold additional references to an axes in the figure to avoid memory leaks. use the this function
# get the plot added above
p1 = self.getAxesByName("p1")
p2 = self.getAxesByName("p2")
self.aliases = {'xRange_p1': (p1, "xRange"),
'xRange_p2': (p2, "xRange")}
return(True)
...@@ -12,3 +12,30 @@ class FigTest(MyFig): ...@@ -12,3 +12,30 @@ class FigTest(MyFig):
frame1 = [0.1, 0.1, 0.8, 0.8] # part of the fig that is available frame1 = [0.1, 0.1, 0.8, 0.8] # part of the fig that is available
self.add_axes(AxTest(self, ratio, frame1), "p1") self.add_axes(AxTest(self, ratio, frame1), "p1")
class FigTest2(MyFig): # Fig with two Axes
# Set the size of the Figure in inch
# (private variable can not be updated)
FIGSIZE = (8., 6.)
def addAxes(self):
ratio = 6. / 8. # height/width of the axes (in inch)
frame1 = [0.1, 0.1, 0.4, 0.8] # part of the fig that is available
frame2 = [0.6, 0.1, 0.4, 0.8] # part of the fig that is available
self.add_axes(AxTest(self, ratio, frame1),"p1")
self.add_axes(AxTest(self, ratio, frame2),"p2")
def declareAliases(self):
# it is important to not hold additional references to an axes in the figure to avoid memory leaks. use the this function
# get the plot added above
p1 = self.getAxesByName("p1")
p2 = self.getAxesByName("p2")
self.aliases = {'xRange_p1': (p1, "xRange"),
'xRange_p2': (p2, "xRange")}
return(True)
...@@ -2,11 +2,16 @@ import threading ...@@ -2,11 +2,16 @@ import threading
from time import sleep from time import sleep
from serverside.myIOs import readStupidData from serverside.myIOs import readStupidData
from serverside.myIOs import readStupidData2
from serverside.figTest import FigTest as FigTests from serverside.figTest import FigTest as FigTests
from clientside.figTest import FigTest as FigTestc from clientside.figTest import FigTest as FigTestc
SERVER_IOFUNCTIONS = {'readStupidData': readStupidData} # This is for the double figure
SERVER_FIGURES = {'FigTest': FigTests} from serverside.figTest import FigTest2 as FigTests2
from clientside.figTest import FigTest2 as FigTestc2
SERVER_IOFUNCTIONS = {'readStupidData': readStupidData,'readStupidData2': readStupidData2}
SERVER_FIGURES = {'FigTest': FigTests,'FigTest2': FigTests2}
import serverside.myplotlib as mpl_server import serverside.myplotlib as mpl_server
import clientside.myplotlib as mpl_client import clientside.myplotlib as mpl_client
...@@ -14,16 +19,10 @@ import clientside.myplotlib as mpl_client ...@@ -14,16 +19,10 @@ import clientside.myplotlib as mpl_client
server = mpl_server.MplServer2(port=12345, knownFunctions=SERVER_IOFUNCTIONS, knownFigures=SERVER_FIGURES) server = mpl_server.MplServer2(port=12345, knownFunctions=SERVER_IOFUNCTIONS, knownFigures=SERVER_FIGURES)
client = mpl_client.MplClient2() client = mpl_client.MplClient2()
# Start a thread with the server -- that thread will then start one server.run(as_daemon=True)
# more thread for each request print("Server loop running in thread:", server.server_thread.name)
# server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
# server_thread.daemon = True
# server_thread.start()
server.run()
print "Server loop running in thread:", server.server_thread.name
client.connect(('localhost', 12345)) client.connect(('localhost', 12345))
print("Client is now connected")
client.readData('readStupidData', 'data1') client.readData('readStupidData', 'data1')
fig1 = client.newSyncFigure(FigTestc, ('data1',)) fig1 = client.newSyncFigure(FigTestc, ('data1',))
...@@ -35,11 +34,16 @@ fig1.update(xRange=[-2, 2],yRange=[-2, 2]) ...@@ -35,11 +34,16 @@ fig1.update(xRange=[-2, 2],yRange=[-2, 2])
win.refresh() win.refresh()
sleep(2) sleep(2)
# multiple figures # multiple figures with multiple data
fig2 = client.newSyncFigure(FigTestc, ('data1',), xRange=[-1.5, 1.5], yRange=[-1.5, 1.5]) client.readData('readStupidData2', 'data2')
print("known datasets: ",client.listRemoteData())
fig2 = client.newSyncFigure(FigTestc2, ('data1','data2'), xRange_p1=[-2.0, 2.0], xRange_p2=[-3, 3], yRange=[-2.0, 2.0])
print('current state:::',fig2.getState())
win=mpl_client.MyWin(fig2) win=mpl_client.MyWin(fig2)
sleep(2)
# desync resync test
fig1.deSyncFig() fig1.deSyncFig()
fig2.deSyncFig() fig1.reSyncFig()
sleep(2)
...@@ -10,18 +10,23 @@ SERVER_FIGURES = {'FigTest': FigTests} ...@@ -10,18 +10,23 @@ SERVER_FIGURES = {'FigTest': FigTests}
import serverside.myplotlib as mpl_server import serverside.myplotlib as mpl_server
import clientside.myplotlib as mpl_client import clientside.myplotlib as mpl_client
server = mpl_server.MplServer2(port=50803, knownFunctions=SERVER_IOFUNCTIONS, knownFigures=SERVER_FIGURES) server = mpl_server.MplServer2(port=12345, knownFunctions=SERVER_IOFUNCTIONS, knownFigures=SERVER_FIGURES)
client = mpl_client.MplClient2() client = mpl_client.MplClient2()
# Start a thread with the server -- that thread will then start one server.run(as_daemon=True)
# more thread for each request print "Server loop running in thread:", server.server_thread.name
server_thread = threading.Thread(target=server.serve_forever) client.connect(('', 12345))
# Exit the server thread when the main thread terminates print("Client is now connected")
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name
client.connect(('', 50803))
# create a figure
client.readData('readStupidData', 'data1') client.readData('readStupidData', 'data1')
fig = client.newSyncFigure(FigTestc, ('data1',)) fig1 = client.newSyncFigure(FigTestc, ('data1',))
# update test
fig1.update(xRange=[-2, 2],yRange=[-2, 2])
# multiple figures
fig2 = client.newSyncFigure(FigTestc, ('data1',), xRange=[-1.5, 1.5], yRange=[-1.5, 1.5])
fig1.deSyncFig()
fig2.deSyncFig()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment