From f73796f93733dc5494866f75a49d18a5b9ba9876 Mon Sep 17 00:00:00 2001 From: alaskowski <alaskowski@ethz.ch> Date: Thu, 9 Nov 2023 17:12:22 +0100 Subject: [PATCH] BIS-713: Amended value objects to reflect new specification, minor improvements --- .../imaging/lib/openBIS-premise-imaging.jar | Bin 19763 -> 31381 bytes .../v3/dto/imaging/ImagingDataSetConfig.java | 0 .../v3/dto/imaging/ImagingDataSetControl.java | 48 ++++- .../ImagingDataSetControlVisibility.java | 88 +++++++++ .../v3/dto/imaging/ImagingDataSetExport.java | 0 .../v3/dto/imaging/ImagingDataSetImage.java | 0 .../v3/dto/imaging/ImagingDataSetPreview.java | 0 .../imaging/ImagingDataSetPropertyConfig.java | 62 +++++++ .../dss/plugins/imaging/ImagingService.java | 64 +++---- .../adaptor/IImagingDataSetAdaptor.java | 3 +- .../adaptor/ImagingDataSetExampleAdaptor.java | 3 +- .../adaptor/ImagingDataSetJythonAdaptor.java | 3 +- .../adaptor/ImagingDataSetPythonAdaptor.java | 7 +- .../custom-services/imaging/nanonis_dat.py | 61 ++++--- .../custom-services/imaging/nanonis_sxm.py | 83 ++++++++- .../custom-services/imaging/spmpy_terry.py | 170 +++++++++++++++--- 16 files changed, 481 insertions(+), 111 deletions(-) rename {api-openbis-java => core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources}/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java (100%) rename {api-openbis-java => core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources}/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java (76%) create mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControlVisibility.java rename {api-openbis-java => core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources}/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java (100%) rename {api-openbis-java => core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources}/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java (100%) rename {api-openbis-java => core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources}/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java (100%) create mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPropertyConfig.java diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/openBIS-premise-imaging.jar b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/openBIS-premise-imaging.jar index 45ead497c522efa717bddc73cad091ebc4377b20..9ce77c0ca4a5774a6b963fd3a2988ff084089a31 100644 GIT binary patch literal 31381 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 a=MD1GFyLmtw{B5@zn+30-097(fBQe_y|HTm delta 14948 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 JOXQ!o{{!Yt)GGi0 diff --git a/api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java similarity index 100% rename from api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java rename to core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java diff --git a/api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java similarity index 76% rename from api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java rename to core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java index 676549859dc..7d5c27fe9ce 100644 --- a/api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java @@ -33,6 +33,9 @@ public class ImagingDataSetControl implements Serializable @JsonProperty private String label; + @JsonProperty + private String section; + @JsonProperty private String type; @@ -40,7 +43,10 @@ public class ImagingDataSetControl implements Serializable private List<String> values; @JsonProperty - private List<Integer> range; + private String unit; + + @JsonProperty + private List<String> range; @JsonProperty private boolean multiselect; @@ -50,6 +56,8 @@ public class ImagingDataSetControl implements Serializable @JsonProperty private List<Integer> speeds; + @JsonProperty + private List<ImagingDataSetControlVisibility> visibility; @JsonProperty private Map<String, String> metaData; @@ -65,6 +73,28 @@ public class ImagingDataSetControl implements Serializable this.label = label; } + @JsonIgnore + public String getSection() + { + return section; + } + + public void setSection(String section) + { + this.section = section; + } + + @JsonIgnore + public String getUnit() + { + return unit; + } + + public void setUnit(String unit) + { + this.unit = unit; + } + @JsonIgnore public String getType() { @@ -121,16 +151,28 @@ public class ImagingDataSetControl implements Serializable } @JsonIgnore - public List<Integer> getRange() + public List<String> getRange() { return range; } - public void setRange(List<Integer> range) + public void setRange(List<String> range) { this.range = range; } + @JsonIgnore + public List<ImagingDataSetControlVisibility> getVisibility() + { + return visibility; + } + + public void setVisibility( + List<ImagingDataSetControlVisibility> visibility) + { + this.visibility = visibility; + } + @JsonIgnore public Map<String, String> getMetaData() { diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControlVisibility.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControlVisibility.java new file mode 100644 index 00000000000..2a364ad0745 --- /dev/null +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControlVisibility.java @@ -0,0 +1,88 @@ +/* + * Copyright ETH 2023 Zürich, Scientific IT Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging; + +import ch.systemsx.cisd.base.annotation.JsonObject; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.io.Serializable; +import java.util.List; + +@JsonObject("dss.dto.imaging.ImagingDataSetControlVisibility") +public class ImagingDataSetControlVisibility implements Serializable +{ + private static final long serialVersionUID = 1L; + + @JsonProperty + private String label; + @JsonProperty + private List<String> values; + @JsonProperty + private List<String> range; + @JsonProperty + private String unit; + + @JsonIgnore + public String getLabel() + { + return label; + } + + public void setLabel(String label) + { + this.label = label; + } + @JsonIgnore + public List<String> getValues() + { + return values; + } + + public void setValues(List<String> values) + { + this.values = values; + } + @JsonIgnore + public List<String> getRange() + { + return range; + } + + public void setRange(List<String> range) + { + this.range = range; + } + + @JsonIgnore + public String getUnit() + { + return unit; + } + + public void setUnit(String unit) + { + this.unit = unit; + } + + @Override + public String toString() + { + return "ImagingDataSetControlVisibility: " + label; + } +} diff --git a/api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java similarity index 100% rename from api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java rename to core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java diff --git a/api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java similarity index 100% rename from api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java rename to core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java diff --git a/api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java similarity index 100% rename from api-openbis-java/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java rename to core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPropertyConfig.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPropertyConfig.java new file mode 100644 index 00000000000..7b9d9b71eb0 --- /dev/null +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPropertyConfig.java @@ -0,0 +1,62 @@ +/* + * Copyright ETH 2023 Zürich, Scientific IT Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging; + +import ch.systemsx.cisd.base.annotation.JsonObject; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.io.Serializable; +import java.util.List; + +@JsonObject("dss.dto.imaging.ImagingDataSetPropertyConfig") +public class ImagingDataSetPropertyConfig implements Serializable +{ + private static final long serialVersionUID = 1L; + + @JsonProperty + ImagingDataSetConfig config; + + @JsonProperty + List<ImagingDataSetImage> images; + + @JsonIgnore + public ImagingDataSetConfig getConfig() + { + return config; + } + + public void setConfig(ImagingDataSetConfig config) + { + this.config = config; + } + + @JsonIgnore + public List<ImagingDataSetImage> getImages() + { + return images; + } + + public void setImages( + List<ImagingDataSetImage> images) + { + this.images = images; + } + + +} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java index b0cdb230c58..0beb0960aee 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java @@ -25,6 +25,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId; import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetConfig; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetImage; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetPropertyConfig; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.CustomDSSServiceExecutionOptions; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.id.ICustomDSSServiceId; import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.adaptor.IImagingDataSetAdaptor; @@ -44,6 +45,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; import ch.systemsx.cisd.openbis.generic.shared.dto.OpenBISSessionHolder; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import ch.systemsx.cisd.common.logging.LogFactory; import org.apache.log4j.Logger; @@ -63,21 +65,17 @@ public class ImagingService implements ICustomDSSServiceExecutor private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, ImagingService.class); - private static final String SCRIPT_PATH = "script-path"; - - private String scriptPath; public ImagingService(Properties properties) { this.properties = properties; - this.scriptPath = PropertyUtils.getProperty(properties, SCRIPT_PATH); } @Override public Serializable executeService(String sessionToken, ICustomDSSServiceId serviceId, CustomDSSServiceExecutionOptions options) { - operationLog.info("Executing service:" + serviceId); + operationLog.info("Executing imaging service:" + serviceId); ImagingDataContainer data = getDataFromParams(options.getParameters()); try { @@ -100,14 +98,21 @@ public class ImagingService implements ICustomDSSServiceExecutor { DataSet dataSet = getDataSet(sessionToken, data); - Config config = - readConfig(dataSet.getJsonProperty("$IMAGING_DATA_CONFIG"), Config.class); - final String adaptorName = config.config.getAdaptor(); + ImagingDataSetPropertyConfig config = + readConfig(dataSet.getJsonProperty("$IMAGING_DATA_CONFIG"), ImagingDataSetPropertyConfig.class); + final String adaptorName = config.getConfig().getAdaptor(); - IImagingDataSetAdaptor - adaptor = - ClassUtils.create(IImagingDataSetAdaptor.class, adaptorName, properties); + if(adaptorName == null || adaptorName.isBlank()) { + throw new UserFailureException("Adaptor name is missing from the config!"); + } + IImagingDataSetAdaptor adaptor = null; + try + { + adaptor = ClassUtils.create(IImagingDataSetAdaptor.class, adaptorName, properties); + } catch(Exception e) { + throw new UserFailureException("Could not load adapter: " + adaptorName, e); + } IHierarchicalContent content = getHierarchicalContentProvider(sessionToken).asContent( dataSet.getPermId().getPermId()); @@ -116,12 +121,13 @@ public class ImagingService implements ICustomDSSServiceExecutor File rootFile = root.getFile(); Map<String, Serializable> previewParams = data.getPreview().getConfig(); Map<String, String> meta = data.getPreview().getMetaData(); + String format = data.getPreview().getFormat(); ImagingServiceContext context = new ImagingServiceContext(sessionToken, getApplicationServerApi(), getDataStoreServerApi()); data.getPreview().setBytes( adaptor.process(context, - rootFile, previewParams, meta).toString()); + rootFile, previewParams, meta, format).toString()); return data; } @@ -175,6 +181,8 @@ public class ImagingService implements ICustomDSSServiceExecutor ObjectMapper objectMapper = getObjectMapper(); return objectMapper.readValue(new ByteArrayInputStream(val.getBytes()), clazz); + } catch (JsonMappingException mappingException) { + throw new UserFailureException(mappingException.toString(), mappingException); } catch (Exception e) { throw new UserFailureException("Could not read the parameters!", e); @@ -210,38 +218,6 @@ public class ImagingService implements ICustomDSSServiceExecutor return result.get(new DataSetPermId(data.getPermId())); } - public static final class Config - { - @JsonProperty - ImagingDataSetConfig config; - - @JsonProperty - List<ImagingDataSetImage> images; - - @JsonIgnore - public ImagingDataSetConfig getConfig() - { - return config; - } - - public void setConfig(ImagingDataSetConfig config) - { - this.config = config; - } - - @JsonIgnore - public List<ImagingDataSetImage> getImages() - { - return images; - } - - public void setImages( - List<ImagingDataSetImage> images) - { - this.images = images; - } - } - private void validateInputParams(Map<String, Object> params) { if (!params.containsKey("permId")) diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/IImagingDataSetAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/IImagingDataSetAdaptor.java index 2208100f550..ea3b5ad6e14 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/IImagingDataSetAdaptor.java +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/IImagingDataSetAdaptor.java @@ -25,6 +25,7 @@ import java.util.Map; public interface IImagingDataSetAdaptor { - Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> previewConfig, Map<String, String> metaData); + Serializable process(ImagingServiceContext context, File rootFile, + Map<String, Serializable> previewConfig, Map<String, String> metaData, String format); } diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java index c9385c3da83..e553d1382d0 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java @@ -38,7 +38,8 @@ public final class ImagingDataSetExampleAdaptor implements IImagingDataSetAdapto } @Override - public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> previewConfig, Map<String, String> metaData) + public Serializable process(ImagingServiceContext context, File rootFile, + Map<String, Serializable> previewConfig, Map<String, String> metaData, String format) { BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB); for(int y=0;y<HEIGHT; y++) diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java index 60476537ca1..51e5043ba32 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java @@ -40,7 +40,8 @@ public class ImagingDataSetJythonAdaptor implements IImagingDataSetAdaptor } } @Override - public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> previewConfig, Map<String, String> metaData) + public Serializable process(ImagingServiceContext context, File rootFile, + Map<String, Serializable> previewConfig, Map<String, String> metaData, String format) { CustomDSSServiceExecutionOptions options = new CustomDSSServiceExecutionOptions(); options.withParameter("sessionToken", context.getSessionToken()); diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java index 2720f7fc6a2..8c720261064 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java @@ -38,11 +38,11 @@ public abstract class ImagingDataSetPythonAdaptor implements IImagingDataSetAdap @Override public Serializable process(ImagingServiceContext context, File rootFile, - Map<String, Serializable> previewConfig, Map<String, String> metaData) + Map<String, Serializable> previewConfig, Map<String, String> metaData, String format) { ProcessBuilder processBuilder = new ProcessBuilder(pythonPath, - scriptPath, rootFile.getAbsolutePath(), convertMapToJson(previewConfig), convertMapToJson(metaData)); + scriptPath, rootFile.getAbsolutePath(), convertMapToJson(previewConfig), convertMapToJson(metaData), format); processBuilder.redirectErrorStream(false); String fullOutput; @@ -63,9 +63,6 @@ public abstract class ImagingDataSetPythonAdaptor implements IImagingDataSetAdap } String[] resultSplit = fullOutput.split("\n"); -// for(int i=0;i< resultSplit.length;i++) { -// System.out.println("||> " + resultSplit[i].substring(0, Math.min(resultSplit[i].length(), 1000))); -// } return resultSplit[resultSplit.length-1]; } diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py index d30b24bca91..ef2acb90966 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py @@ -8,6 +8,7 @@ import os import sys from spmpy_terry import spm # <--- class spm defines objects of type spm with their attributes and class functions import spmpy_terry as spmpy # <--- spmpy has other methods +from datetime import datetime import matplotlib.pyplot as plt # %matplotlib inline @@ -32,6 +33,7 @@ def get_channel(img, channel_name = 'z'): file = sys.argv[1] params = json.loads(sys.argv[2]) meta_data = json.loads(sys.argv[3]) +format = sys.argv[4] folder_dir = os.path.join(file, 'original') @@ -43,43 +45,56 @@ def generate_random_image(height, width): imarray = numpy.random.rand(height,width,3) * 255 im = Image.fromarray(imarray.astype('uint8')).convert('RGBA') img_byte_arr = io.BytesIO() - im.save(img_byte_arr, format='PNG') + im.save(img_byte_arr, format=format) img_byte_arr = img_byte_arr.getvalue() encoded = base64.b64encode(img_byte_arr) return encoded -def get_sxm_image(): - img = load_image(file_path) - channel = get_channel(img, 'z') - img_byte_arr = io.BytesIO() - plt.imshow(channel[0]) - plt.savefig(img_byte_arr, format="png") - # print(img.header) - img_byte_arr = img_byte_arr.getvalue() - encoded = base64.b64encode(img_byte_arr) - return encoded +def get_dat_image(channel_x, channel_y, x_axis, y_axis, colormap, scaling, grouping, print_legend): + specs = spmpy.importall(folder_dir, '', 'spec') + for spec in specs: + date_time = spec.get_param('Saved Date') + spec.date_time = datetime.strptime(date_time, "%d.%m.%Y %H:%M:%S") -def get_sxm_image2(): - img = load_image(file_path) - channel = get_channel(img, 'z')[0] + # sort measurements according to date + specs.sort(key=lambda d: d.date_time) + specs_sub = list(filter(lambda spec:spec.name in grouping, specs)) - min_val = numpy.min(channel) - max_val = numpy.max(channel) - scaled_data = (channel - min_val) / (max_val - min_val) - img = Image.fromarray(numpy.uint8(scaled_data * 255), 'L') + print_legend = print_legend + show = False + fig = spmpy.specs_plot(specs_sub, channelx=channel_x, channely=channel_y, direction='forward', + print_legend=print_legend, show=show, colormap=colormap, scaling=scaling, + x_axis=x_axis, y_axis=y_axis) img_byte_arr = io.BytesIO() - img.save(img_byte_arr, format='PNG') + plt.savefig(img_byte_arr, format=format) img_byte_arr = img_byte_arr.getvalue() encoded = base64.b64encode(img_byte_arr) return encoded + + + + print(params) if params['mode'] == '1': - print(get_sxm_image()) + print(generate_random_image(640, 640)) elif params['mode'] == '2': - print(get_sxm_image2()) -elif params['mode'] == '3': - print(generate_random_image(640, 640)) \ No newline at end of file + parameters = dict( + channel_x=params['channel x'], + channel_y=params['channel y'], + x_axis=[float(x) for x in params['x-axis']], + y_axis=[float(x) for x in params['y-axis']], + colormap=params['colormap'], + scaling=params['scaling'], + grouping=params['grouping'] + ) + if "color" in params: + parameters['color'] = params['color'] + if "print_legend" in params: + parameters['print_legend'] = params['print_legend'].upper() == "TRUE" + else: + parameters['print_legend'] = True + print(get_dat_image(**parameters)) diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py index f8e912b6018..0863f13fbd4 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py @@ -34,10 +34,11 @@ def get_channel(img, channel_name = 'z'): channel = img.get_channel(channel_name) return channel - +print("SYS.ARGV:" + str(sys.argv)) file = sys.argv[1] params = json.loads(sys.argv[2]) meta_data = json.loads(sys.argv[3]) +format = sys.argv[4] folder_dir = os.path.join(file, 'original') @@ -65,8 +66,8 @@ def get_sxm_image(): fig = img.plot(show=False, show_params=False) fig.frameon=False # plt.title(None) - plt.axis('off') - plt.savefig(img_byte_arr, format="png", bbox_inches='tight') + # plt.axis('off') + plt.savefig(img_byte_arr, format=format) # print(img.header) img_byte_arr = img_byte_arr.getvalue() @@ -91,7 +92,7 @@ def get_sxm_image2(): img = Image.fromarray(numpy.uint8(scaled_data * 255), 'L') img_byte_arr = io.BytesIO() - img.save(img_byte_arr, format='PNG') + img.save(img_byte_arr, format=format) img_byte_arr = img_byte_arr.getvalue() encoded = base64.b64encode(img_byte_arr) @@ -104,6 +105,62 @@ def get_sxm_image2(): return encoded + +def get_sxm_image3(channel_name, scaling, color_scale): + img = load_image(file_path) + # channel = get_channel(img, channel_name) + img_byte_arr = io.BytesIO() + + log = False + if scaling == 'logarithmic': + log = True + fig = img.plot(show=False, show_params=False, hide=True, channel=channel_name, log=log) + fig.frameon=False + # plt.title('None') + plt.axis('off') + plt.savefig(img_byte_arr, format="png", bbox_inches='tight') + + pilImg = Image.open(img_byte_arr) + print(f"SIZE={pilImg.size}") + im2 = pilImg.crop(pilImg.getbbox()) + print(f"SIZE={im2.size}") + img_byte_arr = io.BytesIO() + im2.save(img_byte_arr, format='PNG') + + # print(img.header) + img_byte_arr = img_byte_arr.getvalue() + encoded = base64.b64encode(img_byte_arr) + print_params = img.print_params(show=False).split('\n') + print_params = {x: y for x, y in (s.split(':') for s in print_params)} + print_params = json.dumps(print_params) + print(f'PARAMS={print_params}') + header = json.dumps(img.header, cls=NumpyEncoder) + print(f'HEADER={header}') + + return encoded + +def get_sxm_image4(channel_name, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling): + img = load_image(file_path) + img_byte_arr = io.BytesIO() + + log = False + if scaling == 'logarithmic': + log = True + fig = img.plot(show=False, show_params=False, channel=channel_name, log=log, cmap=colormap, + color_scale=color_scale, x_axis=x_axis, y_axis=y_axis, colormap_scaling=colormap_scaling) + plt.savefig(img_byte_arr, format=format) + + img_byte_arr = img_byte_arr.getvalue() + encoded = base64.b64encode(img_byte_arr) + print_params = img.print_params(show=False).split('\n') + print_params = {x: y for x, y in (s.split(':') for s in print_params)} + print_params = json.dumps(print_params) + print(f'PARAMS={print_params}') + header = json.dumps(img.header, cls=NumpyEncoder) + print(f'HEADER={header}') + + return encoded + print(params) if params['mode'] == '1': # print(f'IMG={get_sxm_image()}') @@ -113,4 +170,20 @@ elif params['mode'] == '2': print(f'{get_sxm_image2()}') elif params['mode'] == '3': # print(f'IMG={generate_random_image(320, 320)}') - print(f'{generate_random_image(256, 256)}') \ No newline at end of file + print(f'{generate_random_image(256, 256)}') +elif params['mode'] == '4': + channel = params['channel'] + scaling = params['scaling'] + color_scale = [float(x) for x in params['color-scale']] + print(f'{get_sxm_image3(channel, scaling, color_scale)}') +elif params['mode'] == '5': + channel = params['channel'] + x_axis = [float(x) for x in params['x-axis']] + y_axis = [float(x) for x in params['y-axis']] + color_scale = [float(x) for x in params['color-scale']] + colormap = params['colormap'] + scaling = params['scaling'] + colormap_scaling = False + if "colormap_scaling" in params: + colormap_scaling = params['colormap_scaling'].upper() == "TRUE" + print(f'{get_sxm_image4(channel, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling)}') \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/spmpy_terry.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/spmpy_terry.py index 937ca5fc277..57702f4aef4 100644 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/spmpy_terry.py +++ b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/spmpy_terry.py @@ -332,11 +332,38 @@ class spm: show_params = params['show_params'] else: show_params = False - + if 'show' in params: show = params['show'] else: show = True + + # PREMISE - specific params + + if 'hide' in params: + hide = params['hide'] + else: + hide = False + + if 'color_scale' in params: + color_scale = params['color_scale'] + else: + color_scale = False + + if 'x_axis' in params: + x_axis = params['x_axis'] + else: + x_axis = False + + if 'y_axis' in params: + y_axis = params['y_axis'] + else: + y_axis = False + + if 'colormap_scaling' in params: + colormap_scaling = params['colormap_scaling'] + else: + colormap_scaling = False @@ -348,41 +375,83 @@ class spm: width = self.get_param('width') height = self.get_param('height') pix_y,pix_x = np.shape(chData) - + + # fig = plt.figure(figsize=(6, 4)) fig = plt.figure()#figsize=(6,4)) - + ImgOrigin = 'lower' if self.get_param('scan_dir') == 'down': ImgOrigin = 'upper' - - + + if color_scale: + chData = np.clip(chData, color_scale[0], color_scale[1]) + + if x_axis and y_axis: + plt.ylim(y_axis[0], y_axis[1]) + plt.xlim(x_axis[0], x_axis[1]) + # plt.axis([x_axis[0], x_axis[1], y_axis[0], y_axis[1]]) + + plot_params = dict( + X = np.abs(chData) if log else chData, + aspect = 'equal', + extent = [0,width[0],0,height[0]], + cmap = cmap, + origin = ImgOrigin, + interpolation = 'none' + ) if log: - im = plt.imshow(np.abs(chData), aspect = 'equal', extent = [0,width[0],0,height[0]], cmap = cmap, norm=LogNorm(), origin = ImgOrigin) - else: - im = plt.imshow(chData, aspect = 'equal',extent = [0,width[0],0,height[0]], cmap = cmap, origin = ImgOrigin) + plot_params['norm'] = LogNorm() + + if colormap_scaling: + min_x = x_axis[0] + max_x = x_axis[1] + min_y = y_axis[0] + max_y = y_axis[1] + + shape = chData.shape + minx = int(np.floor(shape[0] * min_x / width[0])) + maxx = int(np.ceil(shape[0] * max_x / width[0])) + miny = int(np.floor(shape[1] * min_y / height[0])) + maxy = int(np.ceil(shape[1] * max_y / height[0])) + + mini = np.min(chData[minx:maxx, miny:maxy]) + maxi = np.max(chData[minx:maxx, miny:maxy]) + + mini = int(mini*100)/100 + maxi = int(maxi*100)/100 + plot_params['vmin'] = mini + plot_params['vmax'] = maxi + + im = plt.imshow(**plot_params) + + # if log: + # im = plt.imshow(np.abs(chData), aspect = 'equal', extent = [0,width[0],0,height[0]], cmap = cmap, norm=LogNorm(), origin = ImgOrigin) + # else: + # im = plt.imshow(chData, aspect = 'equal',extent = [0,width[0],0,height[0]], cmap = cmap, origin = ImgOrigin) if clim: plt.clim(clim) - im.axes.set_xticks([0,width[0]]) - im.axes.set_xticklabels([0,np.round(width[0],2)]) - im.axes.set_yticks([0,height[0]]) - im.axes.set_yticklabels([0,np.round(height[0],2)]) + # im.axes.set_xticks([0,width[0]]) + # im.axes.set_xticklabels([0,np.round(width[0],2)]) + # im.axes.set_yticks([0,height[0]]) + # im.axes.set_yticklabels([0,np.round(height[0],2)]) if show_params: title = self.print_params(show = False); else: title = self.path - - # plt.title(title + '\n', loc='left') - # plt.xlabel('x (%s)' % width[1]) - # plt.ylabel('y (%s)' % height[1]) - - # cbar = plt.colorbar(im,fraction=0.046, pad=0.02, format='%.2g',shrink = 0.5,aspect=10) - # cbar.set_label('%s (%s)' % (channel,chUnit)) + + if not hide: + # plt.title(title + '\n', loc='left') + plt.xlabel('x (%s)' % width[1]) + plt.ylabel('y (%s)' % height[1]) + print(f'AXES={im.axes}') + cbar = plt.colorbar(im)#,fraction=0.046, pad=0.02, format='%.2g',shrink = 0.5,aspect=10) + cbar.set_label('channel:%s (%s)' % (channel,chUnit)) if show: plt.show() @@ -561,17 +630,61 @@ def specs_plot(specs,**params): else: offset = 0 - + # PREMISE specific + if 'show' in params: + show = params['show'] + else: + show = True + + if 'colormap' in params: + colormap = params['colormap'] + cmap = plt.get_cmap(colormap) + color = cmap(np.linspace(0,1,len(specs))) + else: + colormap = False + + if 'scaling' in params: + scaling = params['scaling'] + else: + scaling = False + + if 'x_axis' in params: + x_axis = params['x_axis'] + else: + x_axis = False + + if 'y_axis' in params: + y_axis = params['y_axis'] + else: + y_axis = False + ####### + fig = plt.figure(figsize=(6,4)) counter = 0 - for (s,c) in zip(specs,color): - - (x_data,x_unit) = s.get_channel(channelx,direction=direction) - (y_data,y_unit) = s.get_channel(channely,direction=direction) + for (s, c) in zip(specs, color): - - plt.plot(x_data,y_data+counter*offset,color = c,label = s.name) + (x_data, x_unit) = s.get_channel(channelx, direction=direction) + if x_axis: + x_data = np.clip(x_data, x_axis[0], x_axis[1]) + + (y_data, y_unit) = s.get_channel(channely, direction=direction) + if y_axis: + y_data = np.clip(y_data, y_axis[0], y_axis[1]) + + if scaling: + if scaling == 'lin-lin': + plt.plot(x_data, y_data, color=c, label=s.name) + elif scaling == "lin-log": + plt.semilogy(x_data, np.abs(y_data), color=c, label=s.name) + elif scaling == 'log-lin': + plt.semilogx(np.abs(x_data), y_data, color=c, label=s.name) + elif scaling == 'log-log': + plt.loglog(np.abs(x_data), np.abs(y_data), color=c, label=s.name) + else: + plt.plot(x_data, y_data, color=c, label=s.name) + else: + plt.plot(x_data,y_data+counter*offset,color = c,label = s.name) counter = counter + 1 plt.xlabel('%s (%s)' % (channelx,x_unit)) @@ -579,8 +692,9 @@ def specs_plot(specs,**params): if print_legend: plt.legend() - - plt.show() + + if show: + plt.show() return fig -- GitLab