Skip to content

Commit

Permalink
adds flag "Interpolate Drops" in Config >> Curves, tab Filter to disa…
Browse files Browse the repository at this point in the history
…ble data interpolation
  • Loading branch information
MAKOMO committed Nov 13, 2023
1 parent bad297c commit 3b06527
Show file tree
Hide file tree
Showing 68 changed files with 120,983 additions and 121,055 deletions.
46 changes: 37 additions & 9 deletions src/artisanlib/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ class tgraphcanvas(FigureCanvas):
'machinesetup', 'roastingnotes', 'cuppingnotes', 'roastdate', 'roastepoch', 'roastepoch_timeout', 'lastroastepoch', 'batchcounter', 'batchsequence', 'batchprefix', 'neverUpdateBatchCounter',
'roastbatchnr', 'roastbatchprefix', 'roastbatchpos', 'roasttzoffset', 'roastUUID', 'plus_default_store', 'plus_store', 'plus_store_label', 'plus_coffee',
'plus_coffee_label', 'plus_blend_spec', 'plus_blend_spec_labels', 'plus_blend_label', 'plus_custom_blend', 'plus_sync_record_hash', 'plus_file_last_modified', 'beans', 'ETprojectFlag', 'BTprojectFlag', 'curveVisibilityCache', 'ETcurve', 'BTcurve',
'ETlcd', 'BTlcd', 'swaplcds', 'LCDdecimalplaces', 'foregroundShowFullflag', 'DeltaETflag', 'DeltaBTflag', 'DeltaETlcdflag', 'DeltaBTlcdflag',
'ETlcd', 'BTlcd', 'swaplcds', 'LCDdecimalplaces', 'foregroundShowFullflag', 'interpolateDropsflag', 'DeltaETflag', 'DeltaBTflag', 'DeltaETlcdflag', 'DeltaBTlcdflag',
'swapdeltalcds', 'PIDbuttonflag', 'Controlbuttonflag', 'deltaETfilter', 'deltaBTfilter', 'curvefilter', 'deltaETspan', 'deltaBTspan',
'deltaETsamples', 'deltaBTsamples', 'profile_sampling_interval', 'background_profile_sampling_interval', 'profile_meter', 'optimalSmoothing', 'polyfitRoRcalc',
'patheffects', 'graphstyle', 'graphfont', 'buttonvisibility', 'buttonactions', 'buttonactionstrings', 'extrabuttonactions', 'extrabuttonactionstrings',
Expand Down Expand Up @@ -1401,6 +1401,7 @@ def __init__(self, parent:QWidget, dpi:int, locale:str, aw:'ApplicationWindow')
self.swaplcds:bool = False # if set draw ET curver on top of BT curve and show ET LCD above BT LCD by default
self.LCDdecimalplaces = 1
self.foregroundShowFullflag:bool = True
self.interpolateDropsflag:bool = True
self.DeltaETflag:bool = False
self.DeltaBTflag:bool = True
self.DeltaETlcdflag:bool = False
Expand Down Expand Up @@ -7669,15 +7670,19 @@ def smoothETBT(self,smooth,recomputeAllDeltas,decay_smoothing_p):
timex_lin = None

if smooth or len(self.stemp1) != len(self.timex):
temp1_nogaps = fill_gaps(self.resizeList(self.temp1,len(self.timex)))
temp1_nogaps = self.resizeList(self.temp1,len(self.timex))
if self.interpolateDropsflag:
temp1_nogaps = fill_gaps(temp1_nogaps)
if self.flagon: # we don't smooth, but remove the dropouts
self.stemp1 = temp1_nogaps
else:
if timex_lin is None and self.timex is not None and self.timex and len(self.timex)>1:
timex_lin = numpy.linspace(self.timex[0],self.timex[-1],len(self.timex))
self.stemp1 = list(self.smooth_list(self.timex,temp1_nogaps,window_len=self.curvefilter,decay_smoothing=decay_smoothing_p,a_lin=timex_lin,delta=False))
if smooth or len(self.stemp2) != len(self.timex):
temp2_nogaps = fill_gaps(self.resizeList(self.temp2,len(self.timex)))
temp2_nogaps = self.resizeList(self.temp2,len(self.timex))
if self.interpolateDropsflag:
temp2_nogaps = fill_gaps(temp2_nogaps)
if self.flagon: # we don't smooth, but remove the dropouts
self.stemp2 = temp2_nogaps
else:
Expand Down Expand Up @@ -7714,13 +7719,23 @@ def smoothETBTBkgnd(self,recomputeAllDeltas,decay_smoothing_p):
if self.flagon or len(self.stemp1B) != len(self.timex):
if timeB_lin is None and self.timeB is not None and self.timeB:
timeB_lin = numpy.linspace(self.timeB[0],self.timeB[-1],len(self.timeB))
st1 = self.smooth_list(self.timeB,fill_gaps(self.temp1B),window_len=self.curvefilter,decay_smoothing=decay_smoothing_p,a_lin=timeB_lin,delta=False)
st1 = self.smooth_list(self.timeB,
(fill_gaps(self.temp1B) if self.interpolateDropsflag else self.temp1B),
window_len=self.curvefilter,
decay_smoothing=decay_smoothing_p,
a_lin=timeB_lin,
delta=False)
else:
st1 = self.stemp1B
if self.flagon or len(self.stemp2B) != len(self.timex):
if timeB_lin is None and self.timeB is not None and self.timeB:
timeB_lin = numpy.linspace(self.timeB[0],self.timeB[-1],len(self.timeB))
st2 = self.smooth_list(self.timeB,fill_gaps(self.temp2B),window_len=self.curvefilter,decay_smoothing=decay_smoothing_p,a_lin=timeB_lin,delta=False)
st2 = self.smooth_list(self.timeB,
(fill_gaps(self.temp2B) if self.interpolateDropsflag else self.temp2B),
window_len=self.curvefilter,
decay_smoothing=decay_smoothing_p,
a_lin=timeB_lin,
delta=False)
else:
st2 = self.stemp2B

Expand Down Expand Up @@ -7779,6 +7794,9 @@ def redraw_keep_view(self, *args:bool, **kwargs:bool) -> None:
# if recomputeAllDeltas, the delta arrays and if smooth the smoothed line arrays are recomputed (incl. those of the background curves)
# re_smooth_foreground: the foreground curves (incl. extras) will be re-smoothed if called while not recording. During recording foreground will never be smoothed here.
# re_smooth_background: the background curves (incl. extras) will be re-smoothed if True (default False), also during recording
# NOTE: points for error values represented by None or masked arrays (where values are -1) are not drawn and lines are broken there
# see https://matplotlib.org/stable/gallery/lines_bars_and_markers/masked_demo.html
# to keep points and lines drawn without those breaks data should be interpolated via util:fill_gaps (controlled by the "Interpolate Drops" filter)
def redraw(self, recomputeAllDeltas:bool = True, re_smooth_foreground:bool = True, takelock:bool = True, forceRenewAxis:bool = False, re_smooth_background:bool = False) -> None: # pyright: ignore [reportGeneralTypeIssues] # Code is too complex to analyze; reduce complexity by refactoring into subroutines or reducing conditional code paths
if self.designerflag:
self.redrawdesigner(force=True)
Expand Down Expand Up @@ -9476,8 +9494,13 @@ def redraw(self, recomputeAllDeltas:bool = True, re_smooth_foreground:bool = Tru
try:
if self.aw.extraCurveVisibility1[i]:
if not self.flagon and (re_smooth_foreground or len(self.extrastemp1[i]) != len(self.extratimex[i])):
self.extrastemp1[i] = self.smooth_list(self.extratimex[i],fill_gaps(self.extratemp1[i]),window_len=self.curvefilter,decay_smoothing=decay_smoothing_p,a_lin=timexi_lin,delta=False).tolist()
else: # we don't smooth, but remove the dropouts
self.extrastemp1[i] = self.smooth_list(self.extratimex[i],
(fill_gaps(self.extratemp1[i]) if self.interpolateDropsflag else self.extratemp1[i]),
window_len=self.curvefilter,
decay_smoothing=decay_smoothing_p,
a_lin=timexi_lin,
delta=False).tolist()
elif self.interpolateDropsflag: # we don't smooth, but remove the dropouts
self.extrastemp1[i] = fill_gaps(self.extratemp1[i])
if self.aw.extraDelta1[i] and self.delta_ax is not None:
trans = self.delta_ax.transData
Expand Down Expand Up @@ -9509,8 +9532,13 @@ def redraw(self, recomputeAllDeltas:bool = True, re_smooth_foreground:bool = Tru
try:
if self.aw.extraCurveVisibility2[i]:
if not self.flagon and (re_smooth_foreground or len(self.extrastemp2[i]) != len(self.extratimex[i])):
self.extrastemp2[i] = self.smooth_list(self.extratimex[i],fill_gaps(self.extratemp2[i]),window_len=self.curvefilter,decay_smoothing=decay_smoothing_p,a_lin=timexi_lin,delta=False).tolist()
else:
self.extrastemp2[i] = self.smooth_list(self.extratimex[i],
(fill_gaps(self.extratemp2[i]) if self.interpolateDropsflag else self.extratemp2[i]),
window_len=self.curvefilter,
decay_smoothing=decay_smoothing_p,
a_lin=timexi_lin,
delta=False).tolist()
elif self.interpolateDropsflag:
self.extrastemp2[i] = fill_gaps(self.extratemp2[i])
if self.aw.extraDelta2[i] and self.delta_ax is not None:
trans = self.delta_ax.transData
Expand Down
8 changes: 4 additions & 4 deletions src/artisanlib/comparator.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ def __init__(self, aw:'ApplicationWindow', profile:'ProfileData', filepath:str,
if 'timex' in profile:
self.timex = profile['timex']
if 'temp1' in profile:
self.temp1 = fill_gaps(profile['temp1'])
self.temp1 = (fill_gaps(profile['temp1']) if self.aw.qmc.interpolateDropsflag else profile['temp1'])
if 'temp2' in profile:
self.temp2 = fill_gaps(profile['temp2'])
self.temp2 = (fill_gaps(profile['temp2']) if self.aw.qmc.interpolateDropsflag else profile['temp2'])
if 'timeindex' in profile:
for i,ti in enumerate(profile['timeindex']):
if i < len(self.timeindex):
Expand Down Expand Up @@ -204,11 +204,11 @@ def __init__(self, aw:'ApplicationWindow', profile:'ProfileData', filepath:str,
else:
self.extratimex.append(self.timex)
if len(xtemp1[i]) == len(self.timex):
self.extratemp1.append(fill_gaps(xtemp1[i]))
self.extratemp1.append(fill_gaps(xtemp1[i]) if self.aw.qmc.interpolateDropsflag else xtemp1[i])
else:
self.extratemp1.append([-1.]*len(self.timex))
if len(xtemp2[i]) == len(self.timex):
self.extratemp2.append(fill_gaps(xtemp2[i]))
self.extratemp2.append(fill_gaps(xtemp2[i]) if self.aw.qmc.interpolateDropsflag else xtemp2[i])
else:
self.extratemp2.append([-1.]*len(self.timex))
self.extraname1 = [n.format(self.etypes[0],self.etypes[1],self.etypes[2],self.etypes[3]) for n in xname1] # we apply event name substitutions
Expand Down
13 changes: 13 additions & 0 deletions src/artisanlib/curves.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,12 @@ def __init__(self, parent:QWidget, aw:'ApplicationWindow', activeTab:int = 0) ->
self.ShowFull.stateChanged.connect(self.changeShowFullFilter)
self.ShowFull.setFocusPolicy(Qt.FocusPolicy.NoFocus)

#interpolate drops
self.InterpolateDrops = QCheckBox(QApplication.translate('CheckBox', 'Interpolate Drops'))
self.InterpolateDrops.setChecked(self.aw.qmc.interpolateDropsflag)
self.InterpolateDrops.stateChanged.connect(self.changeInterpolageDrops)
self.InterpolateDrops.setFocusPolicy(Qt.FocusPolicy.NoFocus)

#dropspikes
self.DropSpikes = QCheckBox(QApplication.translate('CheckBox', 'Drop Spikes'))
self.DropSpikes.setChecked(self.aw.qmc.dropSpikes)
Expand Down Expand Up @@ -602,6 +608,7 @@ def __init__(self, parent:QWidget, aw:'ApplicationWindow', activeTab:int = 0) ->
# Render xGroup
renderVBox = QVBoxLayout()
renderVBox.addWidget(self.ShowFull)
renderVBox.addWidget(self.InterpolateDrops)
renderGroupLayout = QGroupBox(QApplication.translate('GroupBox','Display Filter'))
renderGroupLayout.setLayout(renderVBox)

Expand Down Expand Up @@ -2370,6 +2377,11 @@ def changeShowFullFilter(self, _:int = 0) -> None:
self.aw.qmc.foregroundShowFullflag = not self.aw.qmc.foregroundShowFullflag
self.aw.qmc.redraw_keep_view(recomputeAllDeltas=True,re_smooth_foreground=True)

@pyqtSlot(int)
def changeInterpolageDrops(self, _:int = 0) -> None:
self.aw.qmc.interpolateDropsflag = not self.aw.qmc.interpolateDropsflag
self.aw.qmc.redraw_keep_view(recomputeAllDeltas=True,re_smooth_foreground=True)

@pyqtSlot(int)
def changeSpikeFilter(self,_:int = 0) -> None:
self.aw.qmc.dropSpikes = not self.aw.qmc.dropSpikes
Expand Down Expand Up @@ -2545,6 +2557,7 @@ def updatetargets(self) -> None:
self.aw.qmc.filterDropOut_tmin = int(self.minLimit.value())
self.aw.qmc.filterDropOut_tmax = int(self.maxLimit.value())
self.aw.qmc.foregroundShowFullflag = self.ShowFull.isChecked()
self.aw.qmc.interpolateDropsflag = self.InterpolateDrops.isChecked()
self.aw.qmc.plotcurves[0] = str(self.equedit1.text())
self.aw.qmc.plotcurves[1] = str(self.equedit2.text())
self.aw.qmc.plotcurves[2] = str(self.equedit3.text())
Expand Down
16 changes: 1 addition & 15 deletions src/artisanlib/giesen.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,10 @@
except ImportError:
from PyQt5.QtWidgets import QApplication # type: ignore # @UnusedImport @Reimport @UnresolvedImport

from artisanlib.util import fill_gaps
from artisanlib.util import replace_duplicates

_log: Final[logging.Logger] = logging.getLogger(__name__)

def replace_duplicates(data):
lv = -1
data_core = []
for v in data:
if v == lv:
data_core.append(-1)
else:
data_core.append(v)
lv = v
# reconstruct first and last reading
if len(data)>0:
data_core[-1] = data[-1]
return fill_gaps(data_core, interpolate_max=100)

# returns a dict containing all profile information contained in the given IKAWA CSV file
def extractProfileGiesenCSV(file,aw):
res:ProfileData = {} # the interpreted data set
Expand Down
16 changes: 1 addition & 15 deletions src/artisanlib/loring.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,10 @@
from PyQt5.QtWidgets import QApplication # type: ignore # @UnusedImport @Reimport @UnresolvedImport
from PyQt5.QtCore import QDateTime, Qt # type: ignore # @UnusedImport @Reimport @UnresolvedImport

from artisanlib.util import fill_gaps, fromFtoCstrict, RoRfromFtoCstrict, encodeLocal
from artisanlib.util import replace_duplicates, fromFtoCstrict, RoRfromFtoCstrict, encodeLocal

_log: Final[logging.Logger] = logging.getLogger(__name__)

def replace_duplicates(data):
lv = -1
data_core = []
for v in data:
if v == lv:
data_core.append(-1)
else:
data_core.append(v)
lv = v
# reconstruct first and last reading
if len(data)>0:
data_core[-1] = data[-1]
return fill_gaps(data_core, interpolate_max=100)

# returns a dict containing all profile information contained in the given IKAWA CSV file
def extractProfileLoringCSV(file,aw):
res:ProfileData = {} # the interpreted data set
Expand Down
Loading

0 comments on commit 3b06527

Please sign in to comment.