Commit cfd497d6 authored by ba yaye-awa's avatar ba yaye-awa
Browse files

correct bug related to the merge

parents 85b3d359 dbc4596b
......@@ -30,6 +30,7 @@ from matplotlib import pyplot as pp
import yt
from spectral_cube import SpectralCube
import cv2
def cmap2palette (palette_name):
x = pp.get_cmap(palette_name)
......@@ -534,7 +535,7 @@ class DataBlock:
img_f_flat_N[mid_mask] = n_low_steps + n_mid_steps * (img_f_flat[mid_mask] - p_low) / ( p_high - p_low)
high_mask = img_f_flat >= p_high
img_f_flat_N[high_mask] = n_low_steps + n_mid_steps + n_high_steps * (img_f_flat[high_mask] - p_high) / (data_max - p_high)
img_f_flat_N[high_mask] = n_low_steps + n_mid_steps + n_high_steps * (img_f_flat[high_mask] - p_high) / (data_max - p_high) - 1
img_f = img_f_flat_N.reshape(shape)
......@@ -698,24 +699,8 @@ class DataBlock:
def getDimensions(self):
return {"status": True, "message": "", "result": self.__data.shape}
def getSlice(self, iFREQ, step=1):
self.__logger.debug("getSlice: entering")
x = None
numDimensions = len(self.__data.shape)
if numDimensions == 2:
x = self.__data[0:self.__data.shape[0]:step, 0:self.__data.shape[1]:step]
elif numDimensions == 3:
if iFREQ == None:
iFREQ = self.__data.shape[0] / 2
x = self.__data[iFREQ, 0:self.__data.shape[1]:step, 0:self.__data.shape[2]:step]
self.__logger.debug("getSlice: exiting")
return x
def __getSlice(self, iFREQ, step=1):
self.__logger.debug("getSlice: entering")
self.__logger.debug("__getSlice: entering")
x = None
numDimensions = len(self.__data.shape)
......@@ -726,10 +711,10 @@ class DataBlock:
if iFREQ == None:
iFREQ = self.__data.shape[0] / 2
x = self.__data[iFREQ, 0:self.__data.shape[1]:step, 0:self.__data.shape[2]:step]
self.__logger.debug("getSlice: exiting")
self.__logger.debug("__getSlice: exiting")
return x
def getSlice(self, iFREQ, step=1):
self.__logger.debug("getSlice: entering")
result = dict()
......@@ -1121,35 +1106,38 @@ class DataBlock:
iRA0 = iRA0 if iRA0 else 0
iRA1 = iRA1 if iRA1 else (self.__data.shape[2] if numDims > 2 else self.__data.shape[1])
levels = None
quantiles = [0.99]
for key, value in kwargs.items():
if key == 'levels':
levels = value
elif key == 'quantiles':
quantiles = value
self.__logger.debug("levels = %r, quantiles = %r" % (levels, quantiles))
# Get the data to be contoured
slice = self.__getSlice(iFREQ)[iDEC0:iDEC1, iRA0:iRA1]
self.__logger.debug("slice shape %r", slice.shape)
#self.__logger.debug("%r,%r" % (da.min(slice[!da.isnan(slice)]).compute(), da.max(slice[!da.isnan(slice)]).compute()))
# Determine the contours levels.
if not levels:
levels = [np.quantile(slice[~da.isnan(slice)].compute(), quantiles[0])]
self.__logger.debug('levels %r' % levels)
levels = None
quantiles = None
numberOfBins = None
for key, value in kwargs.items():
if key == 'levels':
levels = value
elif key == 'quantiles':
levels = [np.quantile(slice[~da.isnan(slice)].compute(), quantile) for quantile in value]
elif key == 'numberOfBins':
levels = np.histogram_bin_edges(slice[~da.isnan(slice)].compute(), value)
elif key == 'histBinsMethod':
levels = np.histogram_bin_edges(slice[~da.isnan(slice)].compute(), value)
levels = levels [-10:]
self.__logger.debug("levels = %r" % (levels))
# Produce the contours.
features = []
fig, ax = pp.subplots()
CS = ax.contour(np.arange(slice.shape[1]), np.arange(slice.shape[0]), slice, levels)
features = []
for set in CS.allsegs:
for level, set in zip(CS.levels, CS.allsegs):
for c in set :
feature = {"type":"LineString", "coordinates": [[round(x[0]), round(x[1])] for x in c.tolist()]}
feature = {"type":"LineString", \
"coordinates": [[round(x[0]), round(x[1])] for x in c.tolist()],\
"properties": {"level" : level}}
features.append(feature)
contours_geojson = { "type": "FeatureCollection", "features" : features }
......@@ -1158,7 +1146,36 @@ class DataBlock:
self.__logger.debug("getContours: exiting")
return result
def measureContour(self, iFREQ, contour, level):
self.__logger.debug("measureContour : entering")
slice = self.__getSlice(iFREQ).compute()
shape = slice.shape
theMask = np.empty(shape, dtype=bool)
numpix = 0
x,y,w,h = cv2.boundingRect(contour)
for j in np.arange(y, y+h):
for i in np.arange(x, x+w):
theMask[j][i] = cv2.pointPolygonTest(contour, (i, j), False) == 1 and slice[j][i] > level
if theMask[j][i] :
numpix += 1
self.__logger.debug("numpix = %d" % numpix)
result = {}
result["sum"] = np.nansum(slice[theMask]).item()
result["min"] = np.nanmin(slice[theMask]).item()
result["max"] = np.nanmax(slice[theMask]).item()
result["mean"] = np.nanmean(slice[theMask]).item()
result["var"] = np.nanvar(slice[theMask]).item()
result["numpix"] = numpix
result["percent"] = numpix / (shape[0]*shape[1]) * 100
result["boundingRect"] = cv2.boundingRect(contour)
self.__logger.debug(cv2.boundingRect(contour))
result = {"status":True, "message":"", "result":result}
self.__logger.debug("measureContour : exiting")
return result
#
# End of DataBlock class definition.
#
......@@ -255,12 +255,20 @@ class DataManagerImpl :
def getContours(self, relFITSFilePath, iFREQ, iDEC0, iDEC1, iRA0, iRA1, **kwargs):
self.__logger.debug("getContours : entering.")
result = self.__checkPresence(relFITSFilePath)
self.__logger.debug("kwargs = %r" % kwargs)
if result :
if result["status"] :
result = self.__dataBlocks[relFITSFilePath].getContours(iFREQ, iDEC0, iDEC1, iRA0, iRA1, **kwargs)
self.__logger.debug("getContours : exiting.")
return result
def measureContour(self, relFITSFilePath, iFREQ, contour, level):
self.__logger.debug("measureContour - dispatcher : entering")
result = self.__checkPresence(relFITSFilePath)
if result["status"] :
result = self.__dataBlocks[relFITSFilePath].measureContour(iFREQ, contour, level)
self.__logger.debug("measureContour - dispatcher : exiting")
return result
#
# create fits file containing a spectrum at iRA, iDEC
# The use case is interoperability via SAMP
......
......@@ -3,3 +3,4 @@ matplotlib
pillow
pypng
Autologging
opencv-python
......@@ -70,6 +70,7 @@ import os
import traceback
import collections
import numpy as np
import cv2
import json
import errno
......@@ -837,6 +838,13 @@ def getContours():
quantiles = [getFloatValue(level) for level in optParams['quantiles']]
kwargs['quantiles'] = quantiles
if 'numberOfBins' in optParams:
numberOfBins = getIntValue(optParams['numberOfBins'])
kwargs['numberOfBins'] = numberOfBins
if 'histBinsMethod' in optParams:
kwargs['histBinsMethod'] = optParams['histBinsMethod']
logger.debug("kwargs = %r" % kwargs)
result = dm.getContours(relFITSFilePath, iFREQ, iDEC0, iDEC1, iRA0, iRA1, **kwargs)
......@@ -851,6 +859,29 @@ def getContours():
return json.dumps(result)
@route( baseUrl+'/measureContour', name='measureContour', method='POST')
@enable_cors
def measureContour():
logger.debug("measureContour - wrapper : entering")
try:
body = byteify(json.loads(request.body.read()))
relFITSFilePath = rebuildFilename(body['relFITSFilePath'])
iFREQ = getIntValue(body['iFREQ'])
contour = np.asarray(json.loads(body['contour']))
level = getFloatValue(body['level'])
result = dm.measureContour(relFITSFilePath, iFREQ, contour, level)
except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
message = "%s ! %s" % (type(e), "".join(traceback.format_list(traceback.extract_tb(exc_traceback))))
logger.debug(message)
result = {"status": False, "message": message}
response.content_type = "application/json; charset=utf-8"
logger.debug("measureContour - wrapper : exiting")
return json.dumps(result)
"""
Given the values of a spectrum 'ydata' passed with the corresponding frequency values 'xdata'
at an (x,y) given position ( integer indexes ) in the RAxDEC plan of a cube, generate a FITS file containing that
......
......@@ -36,6 +36,7 @@ var renderingCapabilities = null;
var clienthttp = {
server : "http://"+yafitssHost+":"+yafitssPort+"/artemix",
setData : function(relFITSFilePath, sessionID, callback){
request(this.server+"/setData?relFITSFilePath="+relFITSFilePath, { json: true }, function(error, response, body){
callback(error, response, body);
......@@ -154,9 +155,7 @@ var clienthttp = {
},
getContours: function(relFITSFilePath, optParams, callback) {
console.log(JSON.stringify(optParams, 0, 4));
let input = {"optParams" : optParams, "blabla": "blibli", "relFITSFilePath": relFITSFilePath};
console.log("POST with " + JSON.stringify(input, 0, 4));
let input = {"relFITSFilePath": relFITSFilePath, "optParams" : optParams};
request.post(this.server+"/getContours", {json: true, body:input}, function(error, response, body){
callback(error, response, body);
});
......@@ -171,6 +170,13 @@ var clienthttp = {
});
},
measureContour: function(relFITSFilePath, iFREQ, contour, level, callback) {
let input = {"relFITSFilePath": relFITSFilePath, "iFREQ": iFREQ, "contour" : contour, "level" : level};
request.post(this.server+"/measureContour", {json: true, body:input}, function(error, response, body){
callback(error, response, body);
});
},
renderingCapabilities: function(callback) {
request(this.server+"/renderingCapabilities", {json: true}, function (error, response, body){
callback(error, response, body);
......@@ -733,8 +739,23 @@ router.post('/getContours', function(req, res, next) {
console.log("router.post('/getContours', function(req, res, next) {: exiting");
});
router.post('/measureContour', function(req, res, next){
console.log("router.post('/measureContour', function(req, res, next){: entering");
clienthttp.measureContour(req.body.relFITSFilePath, req.body.iFREQ, req.body.contour, req.body.level, (error, response, body) => {
console.log("measureContour callback entering");
if (error) {
console.log(error);
}
else {
res.send(body);
}
console.log("measureContour callback exiting");
});
console.log("router.post('/measureContour', function(req, res, next){: exiting");
});
router.get("/getYtObj", function(req, res, next) {
console.log('router.get("/", function(req, res, next) { : entering '+ req.query.relFITSFilePath );
console.log('router.get("/", function(req, res, next) { : entering ');
clienthttp.getYtObj(req.query.relFITSFilePath,(error, response, body) => {
console.log("getYtObj callback : entering");
if (error) {
......
......@@ -115,61 +115,11 @@ th, td {
</head>
<body>
<% include olqv_markers %>
<div id="loading"></div>
<div id="loading"></div>
<div id="FITSHDR" class="overlay" style="overflow:scroll"></div>
<div class="pos-f-t">
<div class="collapse" id="sampRegistry"></div>
<div class="collapse" id="navbarToggleExternalContent">
<div class="bg-dark p-4">
<% if (renderingCapabilities) { %>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<ul class="list-group list-group-horizontal">
<li class="list-group-item ">
<label for="LUTSelector">LUTs</label>
<select name="LUTs" class="form-control" id="LUTSelector">
<% renderingCapabilities["luts"].forEach(function(lut) { %>
<option> <%=lut%></option>
<% }) %>
</select>
</li>
<li class="list-group-item ">
<label for="ITTSelector">ITTs</label>
<select class="form-control" id="ITTSelector">
<% renderingCapabilities["itts"].forEach(function(itt) { %>
<option> <%=itt%></option>
<% }) %>
</select>
</li>
<li class="list-group-item ">
<label for="VideoModeSelector">Video mode</label>
<select class="form-control" id="VideoModeSelector">
<% renderingCapabilities["vmodes"].forEach(function(vmode) { %>
<option> <%=vmode%></option>
<% }) %>
</select>
</li>
<li class="list-group-item">
<a class="form-control" id="rccap" class="btn btn-primary" href="#" role="button">Apply</a>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#ModalMarkersForm">
Markers
</button>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#ModalContoursForm">
Contours
</button>
</li>
</ul>
</nav>
</div>
<% } %>
</div>
</div>
<% include olqv_infosblock %>
<% include olqv_navbar_external_content %>
<nav class="navbar navbar-dark bg-dark">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggleExternalContent" aria-controls="navbarToggleExternalContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
......@@ -190,7 +140,7 @@ th, td {
<div id="external_mouse_position_1" style="width=384; background-color: lightgray"></div>
</td>
<td align='center'>
<div id="integrated_flux" style="width=384; background-color: lightgray"> Integrated flux : ... </div>
<div id="infos-line" style="width=384; background-color: lightgray"> Integrated flux : ... </div>
</td>
</tr>
<tr>
......@@ -210,10 +160,6 @@ th, td {
</div>
</body>
<script>
<% include olqv_markers %>
<% include olqv_contours %>
<script>
......@@ -271,6 +217,8 @@ var _imageLoadFunction_1 = function(image, src) {
** one image built from the content of a 2D FITS file
*/
var _canvasContext = null;
var yAFITSContoursViewer;
var yaFITSContoursGUI;
function SliceViewer ( relFITSFilePath, width, height, RADECRangeInDegrees, FITSHeader, divSlice) {
console.log("SliceViewer : entering");
......@@ -584,19 +532,72 @@ var _marker_styles_f = function(feature) {
_selected_features_1 = event.target.getFeatures();
_deselected_features_1 = event.deselected;
let infos_line = document.getElementById('infos-line');
let infos_block = document.getElementById('ModalInfosBlockBody');
// Update the displayed integrated flux accordingly with the selected box.
if ((_selected_features_1.getLength() == 1) && (_selected_features_1.item(0).getGeometry().getType() == 'Polygon')){
document.getElementById('integrated_flux').innerHTML = 'Integrated flux : ' + _box_infos_1[_selected_features_1.item(0).getId()]["flux"].toExponential(3) + ' Jy';
}
if (_selected_features_1.getLength() == 1) {
let selectedFeature = _selected_features_1.item(0);
let featureType = selectedFeature.getGeometry().getType();
let populateInfosBlock = function(title, collection) {
infos_block.innerHTML = "<b>"+title+" <br><br>";
for (var k in collection) {
infos_block.innerHTML += k + ":" + collection[k] + "<br>";
}
}
switch (featureType) {
case 'Polygon':
infos_line.innerHTML = 'Integrated flux : ' + _box_infos_1[_selected_features_1.item(0).getId()]["flux"].toExponential(3) + ' Jy';
break;
case 'LineString':
var coordinates = selectedFeature.getGeometry().getCoordinates();
let properties = selectedFeature.get("properties");
let level = properties["level"]
infos_line.innerHTML = 'Contour level :'+level.toExponential(3);
if ("measurements" in properties) {
populateInfosBlock("Contour at level "+level, properties["measurements"]);
infos_line.innerHTML += ' <button type="button" class="btn btn-outline-link btn-sm" data-toggle="modal" data-target="#ModalInfosBlock">etc.</button>';
yAFITSContoursViewer.highlight(selectedFeature);
}
else {
document.getElementById('loading').style.display="block";
$.post('measureContour', {'relFITSFilePath': relFITSFilePath, 'iFREQ': 0, 'contour' :JSON.stringify(coordinates), 'level': level},
(resp) => {
console.log('measureContour callback : entering');
document.getElementById('loading').style.display="none";
if ( resp["status"] == false ){
alert ("Something went wrong with the measurements of contour. The message was '" + resp["message"]+"'");
}
else {
console.log(resp["result"]);
properties["measurements"]=resp["result"];
selectedFeature.set("properties",properties);
populateInfosBlock("Contour at level "+level, properties["measurements"]);
infos_line.innerHTML += ' <button type="button" class="btn btn-outline-link btn-sm" data-toggle="modal" data-target="#ModalInfosBlock">etc.</button>';
yAFITSContoursViewer.highlight(selectedFeature);
}
console.log('measureContour callback : exiting');
});
}
break;
default:
}
}
// We accept to translate anything but the full box.
console.log(_selected_features_1.getLength() + ', ' + _selected_features_1.item(0).getId());
if ((_selected_features_1.getLength() == 1) && (_selected_features_1.item(0).getId() > 0 || _selected_features_1.item(0).getId() === undefined)) {
console.log("Added translate interaction");
//_translate_1 = new ol.interaction.Translate(_selected_features_1);
_map_1.addInteraction(_translate_1);
}
// console.log(_selected_features_1.getLength() + ', ' + _selected_features_1.item(0).getId());
// if (_selected_features_1.item(0).getGeometry().getType() != "LineString") {
// if ((_selected_features_1.getLength() == 1) &&
// ((_selected_features_1.item(0).getId() > 0)
// || (_selected_features_1.item(0).getId() === undefined))) {
// console.log("Added translate interaction");
// //_translate_1 = new ol.interaction.Translate(_selected_features_1);
// _map_1.addInteraction(_translate_1);
// }
// }
});
/*
......@@ -662,7 +663,6 @@ var _marker_styles_f = function(feature) {
$.post('png', {'si': _sliceIndex, 'relFITSFilePath': _relFITSFilePath, 'ittName': ittName, 'lutName': lutName , 'vmName' : vmName}).done(
function(resp) {
console.log("$.post('/png', {'si': _sliceIndex, 'relFITSFilePath': _relFITSFilePath}).done(: entering");
console.log("resp = " + JSON.stringify(resp, 0, 4));
if (resp["status"] == false) {
alert ("Something went wrong during the generation of the image. The message was '" + resp["message"] +"'");
}
......@@ -746,7 +746,7 @@ var _marker_styles_f = function(feature) {
alert(x["message"]);
}
else {
document.getElementById('integrated_flux').innerHTML = 'Integrated flux : ' + x['result'].toExponential(4) + ' Jy';
document.getElementById('infos-line').innerHTML = 'Integrated flux : ' + x['result'].toExponential(4) + ' Jy';
if ( box_index ) {
_box_infos_1[box_index] = {extent:extent, flux: x['result']}
}
......@@ -1106,9 +1106,9 @@ $( document ).ready(function() {
document.addEventListener('keydown', sliceViewer.processKeyCode, false);
var yAFITSContoursViewer = new ContoursViewer(relFITSFilePath, sliceViewer.getMap());
var yaFITSContoursGUI = new ContoursGUI();
yaFITSContoursGUI.connect(yAFITSContoursViewer);
yAFITSContoursViewer = new ContoursViewer(relFITSFilePath, sliceViewer.getMap());
yAFITSContoursGUI = new ContoursGUI();
yAFITSContoursGUI.connect(yAFITSContoursViewer);
$('a#rccap').click(function () {sliceViewer.refresh()});
console.log('$.post("", {"method": "RADECRangeInDegrees", "fileName": relFITSFilePath}).done(function (resp) { : exiting');
......
......@@ -8,6 +8,16 @@ class ContoursViewer {
this.relFITSFilePath = relFITSFilePath;
this.map = map;
this.highlightStyle = new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255,255,255,0.7)'
}),
stroke: new ol.style.Stroke({
color: '#3399CC',
width: 3
})
});
this.style = {
'LineString': new ol.style.Style({
stroke: new ol.style.Stroke({
......@@ -18,6 +28,16 @@ class ContoursViewer {
fill: new ol.style.Fill({
color: 'rgba(0, 0, 255, 0.1)'
})
}),
'Polygon': new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'green',
lineDash: [2],
width: 1
}),
fill: new ol.style.Fill({
color: 'rgba(0, 0, 255, 0.1)'
})
})
};
......@@ -31,19 +51,57 @@ class ContoursViewer {
this.layer.setZIndex(10);
this.visible = true;
this.overlay = null;
this.container = document.getElementById('popup');
this.content = document.getElementById('popup-content');
this.closer = document.getElementById('popup-closer');
this.yAFITSContoursControl = new YAFITSContoursControl();
this.yAFITSContoursControl.setHandler(this.onoff.bind(this));
this.map.addControl(this.yAFITSContoursControl);
this.lastSelectedContour = null;
this.lastBox = null;
console.log("ContoursViewer ctor: exiting");console.trace();
}
highlight(feature) {
console.log("highlight : entering");
if (this.lastSelectedContour !== null) {
this.lastSelectedContour.setStyle(undefined);
if (this.lastBox !== null) {
this.source.removeFeature(this.lastBox);
this.lastBox = null;
}
}
feature.setStyle(this.highlightStyle);
this.box(feature);
this.lastSelectedContour = feature;
console.log("highlight : exiting");
}
box(feature) {
console.log("box : entering");
let br = feature.get("properties")["measurements"]["boundingRect"];
let corners=[[br[0], br[1]],
[br[0]+br[2]-1, br[1]],
[br[0]+br[2]-1, br[1]+br[3]-1],
[br[0], br[1]+br[3]-1],
[br[0], br[1]]];
this.lastBox = new ol.Feature({geometry: new ol.geom.Polygon([corners])});
this.source.addFeature(this.lastBox);
console.log("box : exiting");
}
importYAFITSContours(yAFITSContours) {
console.log("importYAFITSContours: entering"); console.trace();
this.clear();
var features = new Array();
yAFITSContours.forEach((contour) => {
features.push(new ol.Feature( { geometry : new ol.geom.LineString(contour["coordinates"])}))});
features.push(new ol.Feature( { geometry : new ol.geom.LineString(contour["coordinates"]),
properties : contour["properties"]}))});
console.log("Number of features " + features.length);
this.source.addFeatures(features);
this.show();
......@@ -64,6 +122,8 @@ class ContoursViewer {
clear() {
console.log("clear : entering");
if (this.lastSelectedContour) this.lastSelectedContour.setStyle(undefined);
this.lastSelectedContour = null;
this.source.clear();
console.log("clear : exiting");
}
......@@ -73,20 +133,40 @@ class ContoursViewer {
if (this.visible) this.show(); else this.hide();
this.yAFITSContoursControl.onoff();
}
}; // End of class ContoursViewer
class ContoursGUI {
constructor () {
this.update_btn = $("#update_contours");
this.text_of_quantiles = $("#text_of_quantiles");
this.number_of_bins = $("#number_of_bins");