Commit 22a765c1 authored by Flavio TARSETTI's avatar Flavio TARSETTI

Merge branch '71_do_not_fix_exp_plotter_output_on_png' into 'master'

Improve experiment plotter output selection

Closes #71

See merge request !94
parents 80f44b7e 5b144a38
Pipeline #40317 canceled with stages
in 4 minutes and 52 seconds
......@@ -36,8 +36,8 @@
import curses
import glob
import io
import logging
import mimetypes
import os
import queue
import signal
......@@ -587,8 +587,13 @@ def plot_impl(configuration, names, remote, show, output_folder):
if issubclass(type(field_data), SIMPLE_TYPES):
continue
encoded_name = field_data.__class__.__name__
user_name = encoded_name[: encoded_name.find("_")]
name = encoded_name[len(user_name) + 1 : encoded_name.rfind("_")]
version = encoded_name[encoded_name.rfind("_") + 1 :]
plot_data = {
"type": field_data.__class__.__name__.replace("_", "/"),
"type": "/".join([user_name, name, version]),
"primary": True,
"value": field_data,
}
......@@ -633,18 +638,19 @@ def plot_impl(configuration, names, remote, show, output_folder):
"""Return the parameters for the given plotter"""
parameters_path = os.path.join(prefix, "plotterparameters")
with open(
os.path.join(parameters_path, plotter.name + ".json")
) as parameters_file:
declaration = simplejson.load(parameters_file)
return declaration["data"]
try:
with open(
os.path.join(parameters_path, plotter.name + ".json")
) as parameters_file:
declaration = simplejson.load(parameters_file)
return declaration["data"]
except FileNotFoundError:
logger.warning("Default parameters not found")
return {}
mimetypes.init()
for exp_name, results in data_to_plot.items():
for result_name, result_data in results.items():
outputimage_name = "{}_{}.png".format(
exp_name.replace("/", "_"), result_name
)
result_type = result_data["type"]
plotter = _get_plotter_for(result_type)
......@@ -660,7 +666,6 @@ def plot_impl(configuration, names, remote, show, output_folder):
)
default_parameters = _get_parametters_for(plotter)
default_parameters.setdefault("content_type", "image/png")
runner = plotter.runner()
runner.setup(default_parameters)
......@@ -677,18 +682,27 @@ def plot_impl(configuration, names, remote, show, output_folder):
sample_data = result_data["value"]
data_to_plot = [("sample_plot", sample_data)]
fig = runner.process(data_to_plot)
if show:
from PIL import Image
plotter_data = runner.process(data_to_plot)
im = Image.open(io.BytesIO(fig))
im.show()
content_type = getattr(runner.obj, "content_type", "image/png")
extension = mimetypes.guess_extension(content_type)
outputfile_name = "{}_{}{}".format(
exp_name.replace("/", "_"), result_name, extension
)
output_path = os.path.realpath(os.path.join(output_folder, outputfile_name))
if isinstance(plotter_data, str):
mode = "w"
else:
mode = "wb"
output_name = os.path.join(output_folder, outputimage_name)
with open(output_name, "wb") as fh:
fh.write(fig)
with open(output_path, mode) as fh:
fh.write(plotter_data)
indentation = 4
logger.info("%ssaved image `%s'...", indentation * " ", output_name)
logger.info("%ssaved image `%s'...", indentation * " ", output_path)
if show:
click.launch(output_path)
def get_dependencies(ctx, asset_name):
......
{
"schema_version": 2,
"language": "python",
"api_version": 2,
"type": "sequential",
"groups": [
{
"name": "main",
"inputs": {
"in_data": {
"type": "user/single_integer/1"
}
}
}
],
"results": {
"out_data": {
"type": "plot/json_dumper/1",
"display": false
}
}
}
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
###################################################################################
# #
# Copyright (c) 2020 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions are met: #
# #
# 1. Redistributions of source code must retain the above copyright notice, this #
# list of conditions and the following disclaimer. #
# #
# 2. Redistributions in binary form must reproduce the above copyright notice, #
# this list of conditions and the following disclaimer in the documentation #
# and/or other materials provided with the distribution. #
# #
# 3. Neither the name of the copyright holder nor the names of its contributors #
# may be used to endorse or promote products derived from this software without #
# specific prior written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE #
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL #
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER #
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, #
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE #
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #
# #
###################################################################################
import numpy
class Algorithm:
def process(self, inputs, data_loaders, output):
value = inputs["in_data"].data.value
output.write(
{
"out_data": {
"data": [{"x": numpy.uint64(value), "y": numpy.uint64(value * 2)}]
}
}
)
return True
{
"#description": "Some silly data...",
"data": [
0,
{
"x": "uint64",
"y": "uint64"
}
]
}
{
"analyzers": {
"analysis": {
"algorithm": "user/no_image_analyzer/1",
"inputs": {
"in_data": "in"
}
}
},
"blocks": {
"echo": {
"algorithm": "v1/integers_echo/1",
"inputs": {
"in_data": "in"
},
"outputs": {
"out_data": "out"
}
}
},
"datasets": {
"set": {
"database": "simple/1",
"protocol": "protocol",
"set": "set"
}
},
"globals": {
"queue": "queue",
"environment": {
"name": "Python 2.7",
"version": "1.3.0"
}
}
}
{
"dataformat": "plot/json_dumper/1",
"language": "python",
"parameters": {
"content_type": {
"default": "application/json",
"description": "JSON output",
"type": "string",
"choice": [
"application/json"
]
}
}
}
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
###################################################################################
# #
# Copyright (c) 2020 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions are met: #
# #
# 1. Redistributions of source code must retain the above copyright notice, this #
# list of conditions and the following disclaimer. #
# #
# 2. Redistributions in binary form must reproduce the above copyright notice, #
# this list of conditions and the following disclaimer in the documentation #
# and/or other materials provided with the distribution. #
# #
# 3. Neither the name of the copyright holder nor the names of its contributors #
# may be used to endorse or promote products derived from this software without #
# specific prior written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE #
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL #
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR #
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER #
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, #
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE #
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #
# #
###################################################################################
import json
class Plotter:
def setup(self, parameters):
self.content_type = parameters["content_type"]
return True
def process(self, inputs):
data = []
for _, input_ in inputs:
for i in range(len(input_.data)):
result = input_.data[i]
data.append((int(result.x), int(result.y)))
return json.dumps(data)
......@@ -83,6 +83,30 @@ class TestLocal(core.AssetLocalTest):
def test_create(self, obj=None):
nose.SkipTest("Experiment can't be created")
@slow
def test_plot_non_image_local_results(self):
obj = "user/user/single/1/no_image_plotter"
cache_path = os.path.join(tmp_prefix, "cache")
index_experiment_dbs(obj)
exit_code, outputs = self.call("run", obj, prefix=prefix, cache=cache_path)
nose.tools.eq_(exit_code, 0, outputs)
# now push the new object and then delete it remotely
exit_code, outputs = self.call(
"plot",
"--output-folder=%s" % tmp_prefix,
obj,
prefix=prefix,
cache=cache_path,
)
nose.tools.eq_(exit_code, 0, outputs)
generated_files = [
file_ for file_ in os.listdir(tmp_prefix) if file_.endswith(".json")
]
nose.tools.assert_true(generated_files)
class TestOnline(core.OnlineAssetTestCase):
......
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