Commit 71cc9221 authored by Mario Hock's avatar Mario Hock

Nice output in presentation mode

- Large font for good readability on presentation slides.
- Human readable axis labels
parent eb29e46e
This diff is collapsed.
......@@ -63,7 +63,7 @@ def _create_cpu_cols_by_util(cnl_file):
def plot_area_chart(ax, cnl_file, args, cols, legend_outside, legend_title):
def plot_area_chart(ax, cnl_file, args, layout, cols, legend_outside, legend_title):
"""
Plots an area chart of the CPU utilization (usr, sys, ...).
"""
......@@ -75,7 +75,7 @@ def plot_area_chart(ax, cnl_file, args, cols, legend_outside, legend_title):
# Axes
ax.set_ylim(0,100)
#ax.set_ylabel('CPU ' + "/".join(cpu_fields) + ' (%)')
ax.set_ylabel('CPU util (%)', fontsize=args.axis_fontsize)
ax.set_ylabel('CPU util (%)', fontsize=layout.fontsize.axis_labels)
# Plot
y_offsets = numpy.array([0.0] * len(cnl_file.cols["begin"]))
......@@ -111,12 +111,12 @@ def plot_area_chart(ax, cnl_file, args, cols, legend_outside, legend_title):
# Legend
if ( legend_outside ):
## Legend on the right
if ( args.legend_fontsize == 12 or True ): ## XXX
if ( True ): ## XXX
offset = transforms.ScaledTranslation(20, 0, transforms.IdentityTransform())
trans = ax.transAxes + offset
l = ax.legend(loc='upper left', bbox_to_anchor=(1.0, 1.02),fancybox=True, shadow=True, title=legend_title,
fontsize=args.legend_fontsize)
fontsize=layout.fontsize.legend)
## Legend below
else:
......@@ -128,7 +128,7 @@ def plot_area_chart(ax, cnl_file, args, cols, legend_outside, legend_title):
#ncol=math.ceil(len(cpu_fields)/2),
ncol=len(cpu_fields),
bbox_transform = trans,
fontsize=args.legend_fontsize)
fontsize=layout.fontsize.legend)
else:
l = ax.legend(loc=0)
......@@ -136,7 +136,7 @@ def plot_area_chart(ax, cnl_file, args, cols, legend_outside, legend_title):
l.draggable(True)
def plot_top_cpus(cnl_file, args, axes, indices=[0]):
def plot_top_cpus(cnl_file, args, layout, axes, indices=[0]):
"""
This function creates "virtual top-cpus" and plots the utilization fields (usr, system, ...)
......@@ -158,5 +158,5 @@ def plot_top_cpus(cnl_file, args, axes, indices=[0]):
for ax, i in zip(axes, indices):
label = "Top #{} CPU".format(i+1)
cols = top_cpus[i]
plot_area_chart(ax, cnl_file, args, cols, True, label)
plot_area_chart(ax, cnl_file, args, layout, cols, True, label)
# -*- coding:utf-8 -*-
class Layout:
def __init__(self, name):
self.fontsize = fontsize[name]
self.margin_double_plot = margin_double[name]
self.margin_area_plot = margin_area[name]
def set_margins(self, fig, area_plot=False):
if ( area_plot ):
self.margin_area_plot.set_margins(fig)
else:
self.margin_double_plot.set_margins(fig)
def set_tick_fontsize(self, plt, *axes):
for ax in axes:
plt.setp(ax.get_xticklabels(), fontsize=self.fontsize.ticks)
plt.setp(ax.get_yticklabels(), fontsize=self.fontsize.ticks)
## TODO Maybe "named tuples" would be more appropriate than classes for Margin and Fontsize?
class Margin:
def __init__(self, left, wspace, right, top, hspace, bottom):
self.bottom = float(bottom)
self.hspace = float(hspace)
self.left = float(left)
self.right = float(right)
self.top = float(top)
self.wspace = float(wspace)
def set_margins(self, fig):
fig.subplots_adjust(left=self.left, wspace=self.wspace, right=self.right,
top=self.top, hspace=self.hspace, bottom=self.bottom)
class Fontsize:
def __init__(self, axis_labels, legend, ticks):
self.axis_labels = axis_labels
self.legend = legend
self.ticks = ticks
## Presets: Fontsize
fontsize = dict()
fontsize["default"] = Fontsize(axis_labels = 18, legend = 14, ticks = 14)
fontsize["presentation"] = Fontsize(axis_labels = 28, legend = 22, ticks = 18)
fontsize["publication"] = fontsize["default"]
## Presets: Subplot-Layout (margins)
# NOTE: These values actually work great with a screen resolution of 1920x1200.
# Since all spaces here are in relative size, this might have to be adjusted for other screen resolutions.
margin_double = dict()
margin_area = dict()
# "default": good readability on screen
margin_double["default"] = Margin(left=0.1, wspace=0.2, right=0.9, top=0.92, hspace=0.4, bottom=0.12)
margin_area["default"] = Margin(left=0.1, wspace=0.2, right=0.9, top=0.92, hspace=0.4, bottom=0.12)
# "presentation": large font, small margins
margin_double["presentation"] = Margin(left=0.05, wspace=0.15, right=0.98, top=0.97, hspace=0.33, bottom=0.11)
margin_area["presentation"] = Margin(left=0.05, wspace=0.15, right=0.90, top=0.97, hspace=0.33, bottom=0.11) # legend on the right
margin_area["presentationX"] = Margin(left=0.04, wspace=0.15, right=0.99, top=0.97, hspace=0.3, bottom=0.09) # legend below
# "publication": regular font, small margins
margin_double["publication"] = Margin(left=0.03, wspace=0.15, right=0.99, top=0.97, hspace=0.3, bottom=0.08) # small font size
margin_area["publication"] = Margin(left=0.03, wspace=0.15, right=0.93, top=0.97, hspace=0.3, bottom=0.08) # small font size
# -*- coding:utf-8 -*-
import matplotlib.ticker as ticker
from cnl_library import human_readable_from_seconds
## tick positions ##
class TimeLocator(ticker.Locator):
"""
Place the x-axis ticks to be nice seconds/minutes/hours values.
"""
def __init__(self, numticks=5):
#self._base = Base(base)
self.numticks = numticks
def __call__(self):
'Return the locations of the ticks'
vmin, vmax = self.axis.get_view_interval()
return self.tick_values(vmin, vmax)
def _shrink_to_a_multiple_of(self, origin, divisor, maxdiff=0):
diff = origin % divisor
# BRANCH: external max-diff
if ( maxdiff > 0 ):
if ( diff <= maxdiff ):
origin -= diff
# BRANCH: automatic max-diff
elif ( diff < origin * 0.2 ):
origin -= diff
return origin
def _make_nice(self, value, maxdiff=0):
## TODO Find out if this approach gets the desired results...
steps = (60*60, 60*30, 60*15, 60*10, 60*5,
60, 30, 15, 10, 5)
nice_value = value
for step in steps:
nice_value = self._shrink_to_a_multiple_of(value, step, maxdiff)
if ( nice_value != value ):
break
return nice_value
def tick_values(self, vmin, vmax):
if vmax < vmin:
vmin, vmax = vmax, vmin
## Find a nice stepping for the ticks.
diff = vmax-vmin
# If the scale starts almost with 0, concentrate on the positive side.
if ( vmin <= 0 and 0 < vmax and vmin*-1 < diff / (2*self.numticks)):
diff = vmax - 0
step = diff / self.numticks
nice_step = self._make_nice(step)
## Place the ticks.
locs = list()
# Tick »0« if it is in range
if ( vmin <= 0 and 0 < vmax ):
base = 0
else:
## TODO make nice with +, instead - ?
base = self._make_nice(vmin)
# ticks to the right
pos = base
while ( pos <= vmax ):
locs.append(pos)
pos += nice_step
# ticks to the left
pos = base - nice_step
while ( pos >= vmin ):
locs.append(pos)
pos -= nice_step
## Add an additional (still nice) max label, if appropriate.
additional_max_tick = self._make_nice(vmax, 0.25 * nice_step)
if ( additional_max_tick - max(locs) >= 0.5 * nice_step ):
locs.append(additional_max_tick)
return self.raise_if_exceeds(locs)
#def view_limits(self, dmin, dmax):
#"""
#Set the view limits to the nearest multiples of base that
#contain the data
#"""
#vmin = self._base.le(dmin)
#vmax = self._base.ge(dmax)
#if vmin == vmax:
#vmin -= 1
#vmax += 1
#return mtransforms.nonsingular(vmin, vmax)
## tick labels ##
def format_xticks_time(x, pos=None):
return human_readable_from_seconds(float(x))
def format_xticks_minutes(x, pos=None):
return "0" if x == 0 else "{:.0f}min".format(float(x)/60)
def format_yticks_10G(y, pos=None):
return "0" if y == 0 else "{:.0f}G ".format(y / 1000000000)
# -*- coding:utf-8 -*-
def split_proprtionally(text, weights, size=0, fill=" "):
"""
Split a string proportional to a given weight-distribution.
If a |size| is specified, that string is filled with |fill| at the end to match that length.
(NOTE: len(fill) must be 1)
"""
if ( size > 0 ):
## Fill text with spaces.
if ( len(text) < size ):
text += fill * (size-len(text))
## Truncate text if it's too long.
elif ( len(text) > size ):
text = text[size]
else:
size = len(text)
# sum of all weights
total_weights = float( sum(weights) )
## Calculate an int for each weight so that they sum appropriately to |size|.
float_lengths = [ (w / total_weights)*size for w in weights ]
weighted_lengths = [ int(round( f )) for f in float_lengths ]
## Compensate rounding-related inconsistencies.
# XXX I hope this actually does what's supposed to do...
# (Increase/decrease the fields with the biggest rounding differences in order to fit the size)
diff = size - sum(weighted_lengths)
while( diff != 0 ):
sign = -1 if diff < 0 else 1
## Calculate index where the rounding produced the biggest difference.
# (On equality, the latter one wins.)
max_diff = 0
index_of_max_diff = None
for i in range( len(weighted_lengths) ):
cur_diff = ( float_lengths[i] - weighted_lengths[i] ) * sign
if ( cur_diff >= max_diff ):
max_diff = cur_diff
index_of_max_diff = i
## Increase the just found index by 1.
weighted_lengths[i] += sign
diff -= sign
assert( sum(weighted_lengths) == size )
## * split *
ret = list()
last_pos = 0
for pos in weighted_lengths:
ret.append( text[last_pos:last_pos + pos] )
last_pos += pos
return ret
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