package org.molgenis.charts; import freemarker.template.TemplateException; import org.molgenis.charts.AbstractChart.MolgenisChartType; import org.molgenis.charts.charttypes.HeatMapChart; import org.molgenis.charts.data.DataMatrix; import org.molgenis.charts.highcharts.basic.Options; import org.molgenis.charts.requests.BoxPlotChartRequest; import org.molgenis.charts.requests.HeatMapRequest; import org.molgenis.charts.requests.XYDataChartRequest; import org.molgenis.data.Entity; import org.molgenis.data.Query; import org.molgenis.data.QueryRule; import org.molgenis.file.FileStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.XMLStreamException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Collections; import java.util.Map; import static org.molgenis.charts.ChartController.URI; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @Controller @RequestMapping(URI) public class ChartController { private static final Logger LOG = LoggerFactory.getLogger(ChartController.class); public static final String URI = "/charts"; private final ChartDataService chartDataService; private final ChartVisualizationServiceFactory chartVisualizationServiceFactory; private final FileStore fileStore; @Autowired public ChartController(ChartDataService chartDataService, ChartVisualizationServiceFactory chartVisualizationServiceFactory, FileStore fileStore) { if (chartDataService == null) throw new IllegalArgumentException("chartDataService is null"); if (chartVisualizationServiceFactory == null) throw new IllegalArgumentException("chartVisualizationServiceFactory is null"); if (fileStore == null) throw new IllegalArgumentException("fileStore is null"); this.chartDataService = chartDataService; this.chartVisualizationServiceFactory = chartVisualizationServiceFactory; this.fileStore = fileStore; } @RequestMapping(value = "/xydatachart", method = RequestMethod.POST, consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @ResponseBody public Options renderXYDataChart(@Valid @RequestBody XYDataChartRequest request, Model model) { Query<Entity> query = request.getQuery(); XYDataChart xYDataChart = chartDataService .getXYDataChart(request.getEntity(), request.getX(), request.getY(), request.getSplit(), query != null ? query.getRules() : Collections.<QueryRule>emptyList()); xYDataChart.setTitle(request.getTitle()); xYDataChart.setHeight(request.getHeight()); xYDataChart.setWidth(request.getWidth()); xYDataChart.setType(MolgenisChartType.valueOf(request.getType())); xYDataChart.setxAxisLabel(request.getxAxisLabel()); xYDataChart.setyAxisLabel(request.getyAxisLabel()); ChartVisualizationService service = chartVisualizationServiceFactory .getVisualizationService(MolgenisChartType.valueOf(request.getType())); return (Options) service.renderChart(xYDataChart, model); } @RequestMapping(value = "/boxplot", method = RequestMethod.POST, consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @ResponseBody public Options renderPlotBoxChart(@Valid @RequestBody BoxPlotChartRequest request, Model model) { Query<Entity> query = request.getQuery(); BoxPlotChart chart = chartDataService.getBoxPlotChart(request.getEntity(), request.getObservableFeature(), query != null ? query.getRules() : Collections.<QueryRule>emptyList(), request.getSplit(), request.getScale()); chart.setHeight(request.getHeight()); chart.setWidth(request.getWidth()); chart.setTitle(request.getTitle()); ChartVisualizationService service = chartVisualizationServiceFactory .getVisualizationService(MolgenisChartType.BOXPLOT_CHART); return (Options) service.renderChart(chart, model); } /** * Gets a file from the filestore. * <p> * User can only view his own files he created with the charts module * * @param out * @param name * @param extension * @param response * @throws IOException */ @RequestMapping("/get/{name}.{extension}") public void getFile(OutputStream out, @PathVariable("name") String name, @PathVariable("extension") String extension, HttpServletResponse response) throws IOException { File f = fileStore.getFile(name + "." + extension); if (!f.exists()) { LOG.warn("Chart file not found [" + name + "]"); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } response.setContentType(MimeTypes.getContentType(extension)); FileCopyUtils.copy(new FileInputStream(f), out); } /** * Renders a heatmap with r * <p> * Returns a piece of javascript that can be retrieved by an html page with an ajax request. * <p> * The page must have an element with id named 'container'. The svg image will be added to this container element. * * @param request * @param model * @return * @throws IOException * @throws TemplateException * @throws FactoryConfigurationError * @throws XMLStreamException */ @RequestMapping(value = "/heatmap", method = RequestMethod.POST, consumes = APPLICATION_JSON_VALUE) @ResponseBody public String renderHeatMap(@Valid @RequestBody HeatMapRequest request, Model model) throws IOException, TemplateException, XMLStreamException, FactoryConfigurationError { DataMatrix matrix = chartDataService .getDataMatrix(request.getEntity(), request.getX(), request.getY(), request.getQueryRules()); HeatMapChart chart = new HeatMapChart(matrix); chart.setTitle(request.getTitle()); chart.setWidth(request.getWidth()); chart.setHeight(request.getHeight()); chart.setxLabel(request.getxLabel()); chart.setyLabel(request.getyLabel()); chart.setScale(request.getScale()); ChartVisualizationService service = chartVisualizationServiceFactory .getVisualizationService(MolgenisChartType.HEAT_MAP); return (String) service.renderChart(chart, model); } @ExceptionHandler(RuntimeException.class) @ResponseBody @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Map<String, String> handleRuntimeException(RuntimeException e) { LOG.error(null, e); return Collections.singletonMap("errorMessage", "An error occurred. Please contact the administrator.<br />Message:" + e.getMessage()); } }