mirror of
https://github.com/FAUSheppy/ths-datenlogger
synced 2025-12-06 20:21:35 +01:00
refactor
This commit is contained in:
@@ -12,32 +12,54 @@ import timeutils
|
|||||||
matplotlib.rc('font', **GLOBAL_FONT)
|
matplotlib.rc('font', **GLOBAL_FONT)
|
||||||
|
|
||||||
def getlimits_y(y):
|
def getlimits_y(y):
|
||||||
ymax = max(y)+CFG("empty_space_above_plot")
|
'''Get tuple of (ymin, ymax) based on configuration'''
|
||||||
y_min_height = CFG("yaxis_minnimum_hight")
|
|
||||||
if y_min_height != 0 and y_min_height > ymax:
|
|
||||||
ymax = y_min_height
|
|
||||||
y_start_val = CFG("yaxis_start_value")
|
|
||||||
if y_start_val < min(y) or ( CFG("yaxis_force_start_value") and not min(y) < 0):
|
|
||||||
ymin=y_start_val
|
|
||||||
else:
|
|
||||||
ymin=min(y)
|
|
||||||
return (ymin,ymax)
|
|
||||||
|
|
||||||
def avg(array):
|
# calculate actual values #
|
||||||
return sum(array)/float(len(array))
|
ymax = max(y) + CFG("empty_space_above_plot")
|
||||||
|
y_min_height = CFG("yaxis_minnimum_hight")
|
||||||
|
|
||||||
|
# allow negative values when nessesary #
|
||||||
|
if y_min_height != 0 and y_min_height > ymax:
|
||||||
|
ymax = y_min_height
|
||||||
|
y_start_val = CFG("yaxis_start_value")
|
||||||
|
|
||||||
|
# force start value if set in configuration #
|
||||||
|
if y_start_val < min(y) or ( CFG("yaxis_force_start_value") and not min(y) < 0):
|
||||||
|
ymin = y_start_val
|
||||||
|
else:
|
||||||
|
ymin = min(y)
|
||||||
|
|
||||||
|
return (ymin, ymax)
|
||||||
|
|
||||||
def legend_box_contents(name, y):
|
def legend_box_contents(name, y):
|
||||||
|
'''Return a string with the formate content of the legend/caption'''
|
||||||
|
|
||||||
|
# capping values at 99 makes formating easier#
|
||||||
if CFG("cap_values_at_99"):
|
if CFG("cap_values_at_99"):
|
||||||
y = [ min([el, 99.9]) for el in y ]
|
y = [ min( [el, 99.9] ) for el in y ]
|
||||||
|
|
||||||
|
# add minimum values if configured #
|
||||||
if CFG("show_min"):
|
if CFG("show_min"):
|
||||||
name += " min: {:4.1f},".format(min(y))
|
name += " min: {:4.1f},".format(min(y))
|
||||||
|
|
||||||
|
# add maximum values if configured #
|
||||||
if CFG("show_max"):
|
if CFG("show_max"):
|
||||||
name += " max: {:4.1f},".format(max(y))
|
name += " max: {:4.1f},".format(max(y))
|
||||||
|
|
||||||
|
# show average if configured #
|
||||||
if CFG("show_avg"):
|
if CFG("show_avg"):
|
||||||
name += " Mittelwert: {:4.1f},".format(avg(y))
|
name += " Mittelwert: {:4.1f},".format(sum(y)/float(len(y)))
|
||||||
return name.rstrip(",")
|
return name.rstrip(",")
|
||||||
|
|
||||||
def general_background_setup(tup,ymin,ymax,x):
|
def general_background_setup(tup,ymin,ymax,x):
|
||||||
|
'''Setup the Canvas:
|
||||||
|
- set x/y scala limits
|
||||||
|
- draw warning lines/areas
|
||||||
|
- calculate and draw gridsetps
|
||||||
|
- calculate and draw x/y ticks
|
||||||
|
- draw labels
|
||||||
|
- draw caption
|
||||||
|
'''
|
||||||
|
|
||||||
unix_x = [ el.timestamp() for el in x ]
|
unix_x = [ el.timestamp() for el in x ]
|
||||||
|
|
||||||
@@ -45,86 +67,98 @@ def general_background_setup(tup,ymin,ymax,x):
|
|||||||
tup[AXIS].set_ylim( [ ymin, ymax ] )
|
tup[AXIS].set_ylim( [ ymin, ymax ] )
|
||||||
tup[AXIS].set_xlim( [ min(x).timestamp(), max(x).timestamp() ] )
|
tup[AXIS].set_xlim( [ min(x).timestamp(), max(x).timestamp() ] )
|
||||||
|
|
||||||
|
### draw warning lines/areas ###
|
||||||
if CFG("draw_thresholds"):
|
if CFG("draw_thresholds"):
|
||||||
hcrit=CFG("humidity_critical")
|
|
||||||
hwarn=CFG("humidity_warning")
|
humCrit = CFG("humidity_critical")
|
||||||
tlow=CFG("acceptable_temp_low")
|
humWarn = CFG("humidity_warning")
|
||||||
thigh=CFG("acceptable_temp_high")
|
tempLow = CFG("acceptable_temp_low")
|
||||||
tup[AXIS].axhline(y=CFG("target_temperatur"),ls=CFG("hline_line_style"),lw=CFG("hline_line_width"),color=CFG("acceptable_temp_color"))
|
tempHigh = CFG("acceptable_temp_high")
|
||||||
tup[AXIS].axhline(y=hcrit,ls=CFG("hline_line_style"),lw=CFG("hline_line_width"),color=CFG("humidity_crit_color"))
|
tempOptimal = CFG("target_temperatur")
|
||||||
tup[AXIS].axhspan(hwarn,hcrit,color=CFG("humidity_warning_color"),alpha=CFG("humidity_warning_alpha"))
|
|
||||||
tup[AXIS].axhspan(hcrit,ymax,color=CFG("humidity_crit_color"),alpha=CFG("humidity_crit_alpha"))
|
hLineStyle = CFG("hline_line_style")
|
||||||
tup[AXIS].axhspan(tlow,thigh,color=CFG("acceptable_temp_color"),alpha=CFG("acceptable_temp_alpha"))
|
hLineWidth = CFG("hline_line_width")
|
||||||
|
|
||||||
|
tempOptimalColor = CFG("acceptable_temp_color")
|
||||||
|
tempOptimalAlpha = CFG("acceptable_temp_alpha")
|
||||||
|
humCritColor = CFG("humidity_crit_color")
|
||||||
|
humWarnColor = CFG("humidity_warning_color")
|
||||||
|
humCritAlpha = CFG("humidity_crit_alpha")
|
||||||
|
humWarnAlpha = CFG("humidity_warning_alpha")
|
||||||
|
|
||||||
|
tup[AXIS].axhline(y=tempOptimal, ls=hLineStyle, lw=hLineWidth, color=tempOptimalColor)
|
||||||
|
tup[AXIS].axhline(y=humCrit, ls=hLineStyle, lw=hLineWidth, color=humCritColor)
|
||||||
|
|
||||||
|
tup[AXIS].axhspan(humWarn, humCrit, color=humWarnColor, alpha=humWarnAlpha)
|
||||||
|
tup[AXIS].axhspan(humCrit, ymax, color=humCritColor, alpha=humCritAlpha)
|
||||||
|
tup[AXIS].axhspan(tempLow, tempHigh, color=tempOptimalColor, alpha=tempOptimalAlpha)
|
||||||
|
|
||||||
#### GRID ####
|
#### setup grid ####
|
||||||
major_xticks = gen_xticks_from_timeseries(x)
|
major_xticks = gen_xticks_from_timeseries(x)
|
||||||
minor_xticks = get_minor_xticks_from_major(major_xticks)
|
minor_xticks = get_minor_xticks_from_major(major_xticks)
|
||||||
if CFG("raster"):
|
if CFG("raster"):
|
||||||
grid(tup,major_xticks,ymin,ymax)
|
grid(tup, major_xticks, ymin, ymax)
|
||||||
|
|
||||||
#### XTICKS ####
|
#### setup xticks ####
|
||||||
tup[AXIS].set_xticks(major_xticks)
|
tup[AXIS].set_xticks(major_xticks)
|
||||||
tup[AXIS].xaxis.set_major_formatter(ticker.FuncFormatter(xlabel_formater_callback))
|
tup[AXIS].xaxis.set_major_formatter(ticker.FuncFormatter(xlabel_formater_callback))
|
||||||
tup[AXIS].xaxis.set_major_locator(ticker.FixedLocator(major_xticks, nbins=None))
|
tup[AXIS].xaxis.set_major_locator(ticker.FixedLocator(major_xticks, nbins=None))
|
||||||
tup[AXIS].xaxis.set_minor_locator(ticker.FixedLocator(minor_xticks, nbins=None))
|
tup[AXIS].xaxis.set_minor_locator(ticker.FixedLocator(minor_xticks, nbins=None))
|
||||||
tup[AXIS].xaxis.set_tick_params(which='minor',width=0.2,direction="out")
|
tup[AXIS].xaxis.set_tick_params(which='minor', width=0.2, direction="out")
|
||||||
|
|
||||||
tup[AXIS].yaxis.set_major_locator(ticker.MultipleLocator(CFG("y_tick_interval")))
|
tup[AXIS].yaxis.set_major_locator(ticker.MultipleLocator(CFG("y_tick_interval")))
|
||||||
tup[AXIS].yaxis.set_minor_locator(ticker.MultipleLocator(1))
|
tup[AXIS].yaxis.set_minor_locator(ticker.MultipleLocator(1))
|
||||||
tup[AXIS].yaxis.set_tick_params(which='minor',width=0.2,direction="out")
|
tup[AXIS].yaxis.set_tick_params(which='minor', width=0.2, direction="out")
|
||||||
|
|
||||||
tup[AXIS].tick_params(axis='x',which="major",labelsize=CFG("xticks_font_size"));
|
tup[AXIS].tick_params(axis='x', which="major", labelsize=CFG("xticks_font_size"));
|
||||||
tup[AXIS].tick_params(axis='y',which="major",labelsize=CFG("yticks_font_size"));
|
tup[AXIS].tick_params(axis='y', which="major", labelsize=CFG("yticks_font_size"));
|
||||||
|
|
||||||
## ROTATION XLABELS ##
|
### roate xtick-labels to 45deg ###
|
||||||
rotation=CFG("xticks_label_degree")
|
rotation=CFG("xticks_label_degree")
|
||||||
if rotation > 0:
|
if rotation > 0:
|
||||||
plt.xticks(rotation=rotation,ha='right')
|
plt.xticks(rotation=rotation,ha='right')
|
||||||
|
|
||||||
## AXIS LABELS
|
### setup axis labels ###
|
||||||
ylabel_box = dict(boxstyle="square",facecolor='grey', alpha=0.4, edgecolor='black',lw=0.5)
|
ylabel_box = dict(boxstyle="square", facecolor='grey', alpha=0.4, edgecolor='black', lw=0.5)
|
||||||
xlabel_box = ylabel_box
|
xlabel_box = ylabel_box
|
||||||
label_size = CFG("label_font_size")
|
label_size = CFG("label_font_size")
|
||||||
spacing=0.1
|
spacing=0.1
|
||||||
tup[AXIS].set_ylabel(CFG("y_label"),rotation='horizontal',size=label_size,bbox=ylabel_box)
|
tup[AXIS].set_ylabel(CFG("y_label"), rotation='horizontal', size=label_size, bbox=ylabel_box)
|
||||||
tup[AXIS].yaxis.set_label_coords(0.045,0.970)
|
tup[AXIS].yaxis.set_label_coords(0.045, 0.970)
|
||||||
tup[AXIS].set_xlabel(CFG("x_label"),size=label_size,bbox=xlabel_box)
|
tup[AXIS].set_xlabel(CFG("x_label"), size=label_size, bbox=xlabel_box)
|
||||||
tup[AXIS].xaxis.set_label_coords(0.945,0.03)
|
tup[AXIS].xaxis.set_label_coords(0.945, 0.03)
|
||||||
|
|
||||||
## GENERAL LEGEND ##
|
### setup caption ###
|
||||||
legend_handle = tup[AXIS].legend(
|
legend_handle = tup[AXIS].legend(
|
||||||
loc=CFG("legend_location"),
|
loc=CFG("legend_location"),
|
||||||
edgecolor="inherit",
|
edgecolor="inherit",
|
||||||
fancybox=False,
|
fancybox=False,
|
||||||
borderaxespad=spacing,
|
borderaxespad=spacing,
|
||||||
prop={'family': 'monospace','size':CFG("legend_font_size")}
|
prop={'family': 'monospace','size':CFG("legend_font_size")}
|
||||||
)
|
)
|
||||||
legend_handle.get_frame().set_linewidth(0.2)
|
legend_handle.get_frame().set_linewidth(0.2)
|
||||||
#tup[AXIS].set_aspect(get_aspect_ratio(unix_x,ymin,ymax,major_xticks))
|
|
||||||
|
|
||||||
|
|
||||||
def get_aspect_ratio(ux,ymin,ymax,xticks):
|
def get_aspect_ratio(ux, ymin, ymax, xticks):
|
||||||
ratio = 100
|
ratio = 100
|
||||||
tmp = CFG("aspect_ratio")
|
tmp = CFG("aspect_ratio")
|
||||||
if str(tmp) == "A4":
|
if str(tmp) == "A4":
|
||||||
ratio = a4_aspect()
|
ratio = ( 1/math.sqrt(2) ) * x
|
||||||
else:
|
else:
|
||||||
ratio=tmp
|
ratio = tmp
|
||||||
magic_value = 3.25
|
magic_value = 3.25 # 2020 sheppy like: ?!??!??
|
||||||
return ratio * ( max(ux) - min(ux) ) / float(ymax - ymin + magic_value)
|
return ratio * ( max(ux) - min(ux) ) / float(ymax - ymin + magic_value)
|
||||||
|
|
||||||
def a4_aspect(x):
|
|
||||||
return ( 1/math.sqrt(2) ) * x
|
|
||||||
|
|
||||||
def grid(tup,xticks,ymin,ymax):
|
def grid(tup, xticks, ymin, ymax):
|
||||||
lw = CFG("grid_line_width")
|
lw = CFG("grid_line_width")
|
||||||
ls = CFG("grid_line_style")
|
ls = CFG("grid_line_style")
|
||||||
color = CFG("grid_line_color")
|
color = CFG("grid_line_color")
|
||||||
hour_mul = 24
|
hour_mul = 24
|
||||||
expected_vlines = len(list(filter(lambda xt: xt%3600 < 60,xticks)))
|
expected_vlines = len(list(filter(lambda xt: xt % 3600 < 60, xticks)))
|
||||||
safety_first = 60*60 +10
|
safety_first = 60 * 60 + 10
|
||||||
step = xticks[1]-xticks[0]
|
step = xticks[1] - xticks[0]
|
||||||
if step < (24*3600)-safety_first:
|
if step < ( 24 * 3600 ) - safety_first:
|
||||||
if expected_vlines <= 6:
|
if expected_vlines <= 6:
|
||||||
hour_mul = 1
|
hour_mul = 1
|
||||||
elif expected_vlines <=12:
|
elif expected_vlines <=12:
|
||||||
@@ -135,37 +169,37 @@ def grid(tup,xticks,ymin,ymax):
|
|||||||
for xt in xticks:
|
for xt in xticks:
|
||||||
leck_mich = datetime.fromtimestamp(xt)
|
leck_mich = datetime.fromtimestamp(xt)
|
||||||
if leck_mich.hour == leck_mich.minute == leck_mich.second == 0:
|
if leck_mich.hour == leck_mich.minute == leck_mich.second == 0:
|
||||||
tup[AXIS].axvline(xt,ls="-",lw=CFG("major_line_width"),color=color)
|
tup[AXIS].axvline(xt, ls="-", lw=CFG("major_line_width"), color=color)
|
||||||
else:
|
else:
|
||||||
tup[AXIS].axvline(xt,ls=ls,lw=lw,color=color)
|
tup[AXIS].axvline(xt, ls=ls, lw=lw, color=color)
|
||||||
## HLINES ##
|
## HLINES ##
|
||||||
y_interval = CFG("raster_hline_prefered_interval")
|
y_interval = CFG("raster_hline_prefered_interval")
|
||||||
cur = ymin
|
cur = ymin
|
||||||
while cur < ymax:
|
while cur < ymax:
|
||||||
cur += y_interval
|
cur += y_interval
|
||||||
tup[AXIS].axhline(cur,ls=ls,lw=lw,color=color)
|
tup[AXIS].axhline(cur, ls=ls, lw=lw, color=color)
|
||||||
|
|
||||||
def find_step(step,x,total_xticks):
|
def find_step(step,x,total_xticks):
|
||||||
intervals = parse_possible_intervals()
|
intervals = parse_possible_intervals()
|
||||||
start = min(x)
|
start = min(x)
|
||||||
if CFG("always_allow_days_as_xticks") and step > timedelta(days=1)/2:
|
if CFG("always_allow_days_as_xticks") and step > timedelta(days=1)/2:
|
||||||
step = timedelta(days=round(step.days+1))
|
step = timedelta(days=round(step.days + 1))
|
||||||
start = min(x).replace(hour=0,second=0,minute=0)
|
start = min(x).replace(hour=0, second=0, minute=0)
|
||||||
return (start,step)
|
return (start, step)
|
||||||
|
|
||||||
min_delta_step = timedelta(days=1) # the actual step that has the lowest delta
|
min_delta_step = timedelta(days=1) # the actual step that has the lowest delta
|
||||||
min_delta = timedelta(days=1000) # the delta o thus step
|
min_delta = timedelta(days=1000) # the delta of thus step
|
||||||
for s in intervals:
|
for s in intervals:
|
||||||
delta = max(s,step)-min(s,step)
|
delta = max(s, step)-min(s, step)
|
||||||
if delta < min_delta:
|
if delta < min_delta:
|
||||||
min_delta_step = s
|
min_delta_step = s
|
||||||
min_delta = delta
|
min_delta = delta
|
||||||
|
|
||||||
step = min_delta_step
|
step = min_delta_step
|
||||||
start = timeutils.round_time_to_step(start,step)
|
start = timeutils.round_time_to_step(start, step)
|
||||||
|
|
||||||
warn_on_too_much_xticks(x,total_xticks,step)
|
warn_on_too_much_xticks(x, total_xticks, step)
|
||||||
return (start,step)
|
return (start, step)
|
||||||
|
|
||||||
def parse_possible_intervals():
|
def parse_possible_intervals():
|
||||||
intervals = CFG("acceptable_x_intervals")
|
intervals = CFG("acceptable_x_intervals")
|
||||||
@@ -176,7 +210,7 @@ def parse_possible_intervals():
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError("'acceptable_x_intervals' muss die Form 'Zahl[s(econds),m(minutes),h(ours),d(days)]' haben!")
|
raise ValueError("'acceptable_x_intervals' muss die Form 'Zahl[s(econds),m(minutes),h(ours),d(days)]' haben!")
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ValueError("invalid intervals for x_labels %s [index out of bounds], did you write something like this ',,,,' ?]"%str(intervals))
|
raise ValueError("invalid intervals for x_labels %s [index out of bounds], did you write something like this ',,,,' ?]" % str(intervals))
|
||||||
if s.endswith("s"):
|
if s.endswith("s"):
|
||||||
if 60 % st != 0:
|
if 60 % st != 0:
|
||||||
raise ValueError("interval must fit to next bigger interval so basicly for hours 24%interval==0")
|
raise ValueError("interval must fit to next bigger interval so basicly for hours 24%interval==0")
|
||||||
@@ -192,7 +226,8 @@ def parse_possible_intervals():
|
|||||||
elif s.endswith("d"):
|
elif s.endswith("d"):
|
||||||
parsed_intervals += [timedelta(days=st)]
|
parsed_intervals += [timedelta(days=st)]
|
||||||
else:
|
else:
|
||||||
raise ValueError("invalide Zeitspezifizierer in %s (muss, s,m,h oder d sein)"%str(intervals))
|
raise ValueError("Invalide Zeitspezifizierer in %s (muss, s,m,h oder d sein)" % str(intervals))
|
||||||
|
|
||||||
return parsed_intervals
|
return parsed_intervals
|
||||||
|
|
||||||
def warn_on_too_much_xticks(x,total_xticks,step):
|
def warn_on_too_much_xticks(x,total_xticks,step):
|
||||||
|
|||||||
Reference in New Issue
Block a user