Skip to content

Commit

Permalink
Created images.py and moved image generation code to that file
Browse files Browse the repository at this point in the history
Added more validation for width and height keys in
validate_results_request.
Fixed a small code issue in validate_results_request.
  • Loading branch information
catalin-manciu committed Dec 6, 2016
1 parent c85040a commit 316517a
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 71 deletions.
70 changes: 70 additions & 0 deletions codespeed/images.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import cStringIO
from matplotlib.figure import Figure
from matplotlib.ticker import FormatStrFormatter
from matplotlib.backends.backend_agg import FigureCanvasAgg

DEF_CHART_W = 600
DEF_CHART_H = 500

MIN_CHART_W = 400
MIN_CHART_H = 300


def gen_image_from_results(result_data, width, height):
canvas_width = width if width is not None else DEF_CHART_W
canvas_height = height if height is not None else DEF_CHART_H

canvas_width = max(canvas_width, MIN_CHART_W)
canvas_height = max(canvas_height, MIN_CHART_H)

values = [element.value for element in result_data['results']]

max_value = max(values)
min_value = min(values)
value_range = max_value - min_value
range_increment = 0.05 * abs(value_range)

fig = Figure(figsize=(canvas_width / 100, canvas_height / 100), dpi=100)
ax = fig.add_axes([.1, .15, .85, .75])
ax.set_ylim(min_value - range_increment, max_value + range_increment)

xax = range(0, len(values))
yax = values

ax.set_xticks(xax)
ax.set_xticklabels([element.date.strftime('%d %b') for element in
result_data['results']], rotation=75)
ax.set_title(result_data['benchmark'].name)

if result_data['relative']:
ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f%%'))

font_sizes = [16, 16]
dimensions = [canvas_width, canvas_height]

for idx, value in enumerate(dimensions):
if value < 500:
font_sizes[idx] = 8
elif value < 1000:
font_sizes[idx] = 12

if result_data['relative']:
font_sizes[0] -= 2

for item in ax.get_yticklabels():
item.set_fontsize(font_sizes[0])

for item in ax.get_xticklabels():
item.set_fontsize(font_sizes[1])

ax.title.set_fontsize(font_sizes[1] + 4)

ax.scatter(xax, yax)
ax.plot(xax, yax)

canvas = FigureCanvasAgg(fig)
buf = cStringIO.StringIO()
canvas.print_png(buf)
buf_data = buf.getvalue()

return buf_data
31 changes: 21 additions & 10 deletions codespeed/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def validate_results_request(data):
Validates that a result request dictionary has all needed parameters
and their type is correct.
Throws ValidationError on error
Throws ValidationError on error.
"""
mandatory_data = [
'env',
Expand All @@ -24,12 +24,23 @@ def validate_results_request(data):
raise ValidationError('Value for key "' + key +
'" empty in GET request!')

# Check that 'revs' is the correct format (if it exists)
if 'revs' in data:
try:
rev_value = int(data['revs'])
except ValueError:
raise ValidationError('Value for key "revs" is not an integer!')
if rev_value <= 0:
raise ValidationError('Value for key "revs" should be a'
' strictly positive integer!', True)
integer_data = [
'revs',
'width',
'height'
]

"""
Check that the items in integer_data are the correct format,
if they exist
"""
for key in integer_data:
if key in data:
try:
rev_value = int(data[key])
except ValueError:
raise ValidationError('Value for "' + key +
'" is not an integer!')
if rev_value <= 0:
raise ValidationError('Value for "' + key + '" should be a'
' strictly positive integer!')
69 changes: 8 additions & 61 deletions codespeed/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@
from .results import save_result, create_report_if_enough_data
from . import commits
from .validators import validate_results_request

import cStringIO
from matplotlib.figure import Figure
from matplotlib.ticker import FormatStrFormatter
from matplotlib.backends.backend_agg import FigureCanvasAgg

from .images import gen_image_from_results

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -763,65 +758,17 @@ def makeimage(request):
except ObjectDoesNotExist as err:
return HttpResponseNotFound(str(err))

canvas_width = int(data['width']) if 'width' in data else 600
canvas_height = int(data['height']) if 'height' in data else 500

canvas_width = max(canvas_width, 400)
canvas_height = max(canvas_height, 300)

values = [element.value for element in result_data['results']]

max_value = max(values)
min_value = min(values)
value_range = max_value - min_value
range_increment = 0.05 * abs(value_range)

fig = Figure(figsize=(canvas_width / 100, canvas_height / 100), dpi=100)
ax = fig.add_axes([.1, .15, .85, .75])
ax.set_ylim(min_value - range_increment, max_value + range_increment)

xax = range(0, len(values))
yax = values

ax.set_xticks(xax)
ax.set_xticklabels([element.date.strftime('%d %b') for element in
result_data['results']], rotation=75)
ax.set_title(result_data['benchmark'].name)

if result_data['relative']:
ax.yaxis.set_major_formatter(FormatStrFormatter('%.3f%%'))

font_sizes = [16, 16]
dimensions = [canvas_width, canvas_height]

for idx, value in enumerate(dimensions):
if value < 500:
font_sizes[idx] = 8
elif value < 1000:
font_sizes[idx] = 12

for item in ax.get_yticklabels():
item.set_fontsize(font_sizes[0])

for item in ax.get_xticklabels():
item.set_fontsize(font_sizes[1])

ax.title.set_fontsize(font_sizes[1] + 4)

ax.scatter(xax, yax)
ax.plot(xax, yax)

canvas = FigureCanvasAgg(fig)
buf = cStringIO.StringIO()
canvas.print_png(buf)
buf_data = buf.getvalue()
image_data = gen_image_from_results(
result_data,
int(data['width']) if 'width' in data else None,
int(data['height']) if 'height' in data else None)

if django_has_content_type():
response = HttpResponse(content=buf_data, content_type='image/png')
response = HttpResponse(content=image_data, content_type='image/png')
else:
response = HttpResponse(content=buf_data, mimetype='image/png')
response = HttpResponse(content=image_data, mimetype='image/png')

response['Content-Length'] = len(buf_data)
response['Content-Length'] = len(image_data)
response['Content-Disposition'] = 'attachment; filename=image.png'

return response

0 comments on commit 316517a

Please sign in to comment.