merged core into project

This commit is contained in:
2016-03-17 08:52:34 +01:00
parent 8c13c1c85d
commit 5f836e7856
24 changed files with 1060 additions and 2 deletions
+1
View File
@@ -5,3 +5,4 @@
.settings
.project
.classpath
/schema/
+4 -2
View File
@@ -25,7 +25,6 @@ repositories {
}
dependencies {
compile 'ch.psi:ch.psi.fda.core:2.3.4'
compile 'ch.psi:jcae:2.4.1'
compile 'com.google.inject:guice:3.0'
compile 'org.glassfish.jersey.containers:jersey-container-grizzly2-http:2.5.1'
@@ -39,6 +38,7 @@ dependencies {
compile 'org.freehep:freehep-xdr:2.0.4'
compile 'ch.psi:plot:2.1-SNAPSHOT'
compile 'com.google.guava:guava:>15.0'
compile 'com.sun.mail:javax.mail:1.5.0'
compile 'javax.inject:javax.inject:1'
@@ -58,14 +58,16 @@ task sourcesJar(type: Jar, dependsOn: classes) {
from sourceSets.main.allSource
}
/*
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
*/
artifacts {
archives sourcesJar
archives javadocJar
//archives javadocJar
}
jaxb{
@@ -0,0 +1,17 @@
package ch.psi.fda;
import java.io.File;
import ch.psi.fda.edescriptor.EDescriptor;
import ch.psi.fda.vdescriptor.VDescriptor;
public interface DescriptorProvider {
public void load(File ... files );
public EDescriptor getEDescriptor();
public VDescriptor getVDescriptor();
public Class<?> getEDescriptorClass();
}
+28
View File
@@ -0,0 +1,28 @@
package ch.psi.fda;
public interface EContainer {
/**
* Initialize execution container like required resources, etc.
*/
public void initialize();
/**
* Executes the logic implemented by the ExecutionContainer
* Execute is a blocking function and must not return before the actual logic is executed
*/
public void execute();
/**
* Try to abort the execution of the logic
*/
public void abort();
public boolean isActive();
/**
* Destroy execution container and free all allocated resources
*/
public void destroy();
}
@@ -0,0 +1,22 @@
package ch.psi.fda;
import ch.psi.fda.edescriptor.EDescriptor;
import com.google.common.eventbus.EventBus;
public interface EContainerFactory {
/**
* Check whether the factory supports
* @param descriptor
* @return
*/
public boolean supportsEDescriptor(EDescriptor descriptor);
/**
* Create the execution container based on the passed descriptor
* @param descriptor
* @return
*/
public EContainer getEContainer(EDescriptor descriptor, EventBus bus);
}
@@ -0,0 +1,15 @@
package ch.psi.fda.edescriptor;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
/**
* Execution container descriptor
*/
@XmlRootElement
@XmlTransient
public interface EDescriptor {
// TODO Need to contain what need to be streamed
}
@@ -0,0 +1,29 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.messages;
/**
* A control message that is not holding any data but
* control information (like end of loop, etc.)
*/
public abstract class ControlMessage extends Message{
private static final long serialVersionUID = 1L;
}
@@ -0,0 +1,105 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.messages;
import java.util.ArrayList;
import java.util.List;
/**
* Message holding data
*/
public class DataMessage extends Message{
private static final long serialVersionUID = 1L;
private final List<Object> data;
private List<Metadata> metadata;
// public DataMessage(){
// this.data = new ArrayList<Object>();
// this.metadata = new ArrayList<>();
// }
//
public DataMessage(List<Metadata> metadata){
this.data = new ArrayList<Object>();
this.metadata = metadata;
}
public List<Object> getData(){
return(data);
}
public List<Metadata> getMetadata(){
return metadata;
}
public void setMetadata(List<Metadata> metadata){
this.metadata = metadata;
}
// Utility functions
@SuppressWarnings("unchecked")
public <T> T getData(String id){
int i=0;
for(Metadata m: metadata){
if(m.getId().equals(id)){
return (T) data.get(i);
}
i++;
}
throw new IllegalArgumentException("No data found for id: "+id);
}
public Metadata getMetadata(String id){
for(Metadata m: metadata){
if(m.getId().equals(id)){
return m;
}
}
throw new IllegalArgumentException("No data found for id: "+id);
}
@Override
public String toString() {
StringBuffer b = new StringBuffer();
b.append("Message [ ");
for (Object o : data) {
if (o.getClass().isArray()) {
// If the array object is of type double[] display its content
if (o instanceof double[]) {
double[] oa = (double[]) o;
b.append("[ ");
for (double o1 : oa) {
b.append(o1);
b.append(" ");
}
b.append("]");
} else {
b.append(o.toString());
}
} else {
b.append(o);
}
b.append(" ");
}
b.append("]");
return b.toString();
}
}
@@ -0,0 +1,52 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.messages;
/**
* Message that is send at the end of the action loop inside an ActionLoop implementation
* of just to indicate that a particular stream has finished
*/
public class EndOfStreamMessage extends ControlMessage {
private static final long serialVersionUID = 1L;
/**
* Intersect flag - flag to indicate that stream should be intersected
* after this message.
*/
private final boolean iflag;
public EndOfStreamMessage(){
this(false);
}
public EndOfStreamMessage(boolean iflag){
this.iflag = iflag;
}
public boolean isIflag(){
return(iflag);
}
@Override
public String toString() {
return "Message[ c message: end of stream ]";
}
}
@@ -0,0 +1,29 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.messages;
import java.io.Serializable;
/**
* Message that can be put to the data queue
*/
public abstract class Message implements Serializable{
private static final long serialVersionUID = 1L;
}
@@ -0,0 +1,58 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.messages;
import java.io.Serializable;
/**
* Metadata of a component of a message. Each component has a global id.
* Optionally the component can also belong to a dimension. However, depending on the
* view the number of the dimension might vary. Therefore the dimension number
* might change during the lifetime of a message (component).
*/
public class Metadata implements Serializable{
private static final long serialVersionUID = 1L;
private final String id;
private int dimension;
public Metadata(String id){
this.id = id;
this.dimension = 0;
}
public Metadata(String id, int dimension){
this.id = id;
this.dimension = dimension;
}
public void setDimension(int dimension){
this.dimension = dimension;
}
public int getDimension() {
return dimension;
}
public String getId() {
return id;
}
}
@@ -0,0 +1,67 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.messages;
/**
* Message that is send at the end of the action loop inside an ActionLoop implementation
*/
public class StreamDelimiterMessage extends ControlMessage{
private static final long serialVersionUID = 1L;
/**
* Number of the dimension this delimiter belongs to.
*/
private final int number;
/**
* Intersect flag - flag to indicate that stream should be intersected
* after this message.
*/
private final boolean iflag;
/**
* @param number Number of the dimension this delimiter belongs to
*/
public StreamDelimiterMessage(int number){
this(number, false);
}
/**
* @param number
* @param iflag Flag to indicate that data is grouped
*/
public StreamDelimiterMessage(int number, boolean iflag){
this.number = number;
this.iflag = iflag;
}
public int getNumber() {
return number;
}
public boolean isIflag(){
return iflag;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Message [ c message: delimiter dimension "+number+" ]";
}
}
@@ -0,0 +1,224 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.serializer;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.common.eventbus.Subscribe;
import ch.psi.fda.messages.DataMessage;
import ch.psi.fda.messages.EndOfStreamMessage;
import ch.psi.fda.messages.Message;
import ch.psi.fda.messages.Metadata;
import ch.psi.fda.messages.StreamDelimiterMessage;
/**
* Serialize data received by a DataQueue
*/
public class SerializerTXT {
private static final Logger logger = Logger.getLogger(SerializerTXT.class.getName());
private File file;
private boolean appendSuffix = true;
private boolean first = true;
private File outfile;
private int icount;
private String basename;
private String extension;
private boolean newfile;
private boolean dataInBetween;
private BufferedWriter writer;
private StringBuffer b;
private StringBuffer b1;
private boolean showDimensionHeader = true;
public SerializerTXT(File file) {
this.file = file;
}
/**
* @param metadata
* @param file
* @param appendSuffix
* Flag whether to append a _0000 suffix after the original file
* name
*/
public SerializerTXT(File file, boolean appendSuffix) {
this.file = file;
this.appendSuffix = appendSuffix;
}
@Subscribe
public void onMessage(Message message) {
try {
if (first) {
first = false;
// Write header
icount = 0;
newfile = true;
dataInBetween = false;
writer = null;
// Get basename of the file
basename = this.file.getAbsolutePath(); // Determine file name
extension = basename.replaceAll("^.*\\.", ""); // Determine
// extension
basename = basename.replaceAll("\\." + extension + "$", "");
}
if (message instanceof DataMessage) {
dataInBetween = true;
if (newfile) {
b = new StringBuffer();
b1 = new StringBuffer();
b.append("#");
b1.append("#");
for (Metadata c : ((DataMessage) message).getMetadata()) {
b.append(c.getId());
b.append("\t");
b1.append(c.getDimension());
b1.append("\t");
}
b.setCharAt(b.length() - 1, '\n');
b1.setCharAt(b1.length() - 1, '\n');
// Open new file and write header
// Construct file name
if (appendSuffix) {
outfile = new File(String.format("%s_%04d.%s", basename, icount, extension));
}
else {
outfile = new File(String.format("%s.%s", basename, extension));
}
// Open file
logger.fine("Open new data file: " + outfile.getAbsolutePath());
writer = new BufferedWriter(new FileWriter(outfile));
// Write header
writer.write(b.toString());
if (showDimensionHeader) {
writer.write(b1.toString());
}
newfile = false;
}
// Write message to file - each message will result in one line
DataMessage m = (DataMessage) message;
StringBuffer buffer = new StringBuffer();
for (Object o : m.getData()) {
if (o.getClass().isArray()) {
// If the array object is of type double[] display its
// content
if (o instanceof double[]) {
double[] oa = (double[]) o;
for (double o1 : oa) {
buffer.append(o1);
buffer.append(" "); // Use space instead of tab
}
buffer.replace(buffer.length() - 1, buffer.length() - 1, "\t"); // Replace
// last
// space
// with
// tab
}
else if (o instanceof Object[]) {
// TODO need to be recursive ...
Object[] oa = (Object[]) o;
for (Object o1 : oa) {
buffer.append(o1);
buffer.append(" "); // Use space instead of tab
}
buffer.replace(buffer.length() - 1, buffer.length() - 1, "\t"); // Replace
// last
// space
// with
// tab
}
else {
buffer.append("-"); // Not supported
}
}
else {
buffer.append(o);
buffer.append("\t");
}
}
if (buffer.length() > 0) {
buffer.deleteCharAt(buffer.length() - 1); // Remove last
// character
// (i.e. \t)
buffer.append("\n"); // Append newline
}
writer.write(buffer.toString());
}
else if (message instanceof StreamDelimiterMessage) {
StreamDelimiterMessage m = (StreamDelimiterMessage) message;
logger.info("Delimiter - number: " + m.getNumber() + " iflag: " + m.isIflag());
if (m.isIflag() && appendSuffix) {
// Only increase iflag counter if there was data in between
// subsequent StreamDelimiterMessages.
if (dataInBetween) {
icount++;
}
dataInBetween = false;
// Set flag to open new file
newfile = true;
// Close file
writer.close();
}
}
else if (message instanceof EndOfStreamMessage) {
if (writer != null) {
// Close file
writer.close(); // If the stream was closed previously this
// has no effect
}
}
} catch (IOException e) {
logger.log(Level.SEVERE, "Data serializer had a problem writing to the specified file", e);
throw new RuntimeException("Data serializer had a problem writing to the specified file", e);
}
}
public boolean isShowDimensionHeader() {
return showDimensionHeader;
}
public void setShowDimensionHeader(boolean showDimensionHeader) {
this.showDimensionHeader = showDimensionHeader;
}
}
@@ -0,0 +1,53 @@
package ch.psi.fda.vdescriptor;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="lineplot")
public class LinePlot extends Plot {
private List<Series> data = new ArrayList<>();
private Double minX;
private Double maxX;
private Integer maxSeries;
public LinePlot(){
}
public LinePlot(String title){
setTitle(title);
}
@XmlElement
public List<Series> getData() {
return data;
}
public void setData(List<Series> data) {
this.data = data;
}
@XmlAttribute
public Double getMinX() {
return minX;
}
public void setMinX(Double minX) {
this.minX = minX;
}
@XmlAttribute
public Double getMaxX() {
return maxX;
}
public void setMaxX(Double maxX) {
this.maxX = maxX;
}
@XmlAttribute
public Integer getMaxSeries() {
return maxSeries;
}
public void setMaxSeries(Integer maxSeries) {
this.maxSeries = maxSeries;
}
}
@@ -0,0 +1,87 @@
package ch.psi.fda.vdescriptor;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
@XmlRootElement(name="matrixplot")
public class MatrixPlot extends Plot {
private List<Series> data = new ArrayList<>();
private Double minX;
private Double maxX;
private Integer nX;
private Double minY;
private Double maxY;
private Integer nY;
private String type;
public MatrixPlot(){
}
public MatrixPlot(String title){
setTitle(title);
}
public List<Series> getData() {
return data;
}
public void setData(List<Series> data) {
this.data = data;
}
@XmlAttribute
@XmlSchemaType(name = "float")
public Double getMinX() {
return minX;
}
public void setMinX(Double minX) {
this.minX = minX;
}
@XmlAttribute
public Double getMaxX() {
return maxX;
}
public void setMaxX(Double maxX) {
this.maxX = maxX;
}
@XmlAttribute
public Integer getnX() {
return nX;
}
public void setnX(Integer nX) {
this.nX = nX;
}
@XmlAttribute
public Double getMinY() {
return minY;
}
public void setMinY(Double minY) {
this.minY = minY;
}
@XmlAttribute
public Double getMaxY() {
return maxY;
}
public void setMaxY(Double maxY) {
this.maxY = maxY;
}
@XmlAttribute
public Integer getnY() {
return nY;
}
public void setnY(Integer nY) {
this.nY = nY;
}
@XmlAttribute
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
@@ -0,0 +1,20 @@
package ch.psi.fda.vdescriptor;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
@XmlSeeAlso({LinePlot.class, MatrixPlot.class})
@XmlTransient
public abstract class Plot {
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
@@ -0,0 +1,12 @@
package ch.psi.fda.vdescriptor;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
@XmlSeeAlso({XYSeries.class, XYZSeries.class})
@XmlTransient
public abstract class Series {
}
@@ -0,0 +1,28 @@
package ch.psi.fda.vdescriptor;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="vdescriptor")
public class VDescriptor {
private List<Plot> plots = new ArrayList<>();
@XmlElementWrapper
@XmlElements({
@XmlElement(name="lineplot",type=LinePlot.class),
@XmlElement(name="matrixplot",type=MatrixPlot.class),
})
public List<Plot> getPlots() {
return plots;
}
public void setPlots(List<Plot> plots) {
this.plots = plots;
}
}
@@ -0,0 +1,42 @@
package ch.psi.fda.vdescriptor;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="xyseries")
public class XYSeries extends Series {
private String x = null;
private String y = null;
private Integer maxItemCount = -1;
public XYSeries(){
}
public XYSeries(String x, String y){
this.x = x;
this.y = y;
}
@XmlAttribute
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
@XmlAttribute
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
@XmlAttribute
public Integer getMaxItemCount() {
return maxItemCount;
}
public void setMaxItemCount(Integer maxCount) {
this.maxItemCount = maxCount;
}
}
@@ -0,0 +1,43 @@
package ch.psi.fda.vdescriptor;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="xyzseries")
public class XYZSeries extends Series {
private String x = null;
private String y = null;
private String z = null;
public XYZSeries(){
}
public XYZSeries(String x, String y, String z){
this.x = x;
this.y = y;
this.z = z;
}
@XmlAttribute
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
@XmlAttribute
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
@XmlAttribute
public String getZ() {
return z;
}
public void setZ(String z) {
this.z = z;
}
}
@@ -0,0 +1,28 @@
package ch.psi.fda.vdescriptor;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
/**
* In a YSeries the Y components hold an data array in which the index i the x and the value the y value.
*/
@XmlRootElement(name="yseries")
public class YSeries extends Series {
private String y = null;
public YSeries(){
}
public YSeries(String y){
this.y = y;
}
@XmlAttribute
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
}
@@ -0,0 +1,38 @@
package ch.psi.fda.vdescriptor;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
/**
* In a YZSeries the Y components hold an data array in which the index i the x and the value the y value.
*/
@XmlRootElement(name="yzseries")
public class YZSeries extends Series {
private String y = null;
private String z = null;
public YZSeries(){
}
public YZSeries(String y, String z){
this.y = y;
this.z = z;
}
@XmlAttribute
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
@XmlAttribute
public String getZ() {
return z;
}
public void setZ(String z) {
this.z = z;
}
}
@@ -0,0 +1,43 @@
package ch.psi.fda.vdescriptor;
import java.io.File;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class VDescriptorTest {
private static final Logger logger = Logger.getLogger(VDescriptorTest.class.getName());
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void test() throws JAXBException {
try {
JAXBContext context = JAXBContext.newInstance(VDescriptor.class);
Unmarshaller u = context.createUnmarshaller();
VDescriptor descriptor = (VDescriptor) u.unmarshal(new File("src/test/resources/vdescriptor.xml"));
for (Plot p : descriptor.getPlots()) {
logger.info(p.getClass().getName());
}
} catch (JAXBException e) {
e.printStackTrace();
throw e;
}
}
}
+15
View File
@@ -0,0 +1,15 @@
<vdescriptor>
<plots>
<lineplot>
<data>
<xyseries x="A" y="B" />
<xyseries x="A" y="C" />
</data>
</lineplot>
<matrixplot>
<data>
<xyzseries x="A" y="B" z="X" />
</data>
</matrixplot>
</plots>
</vdescriptor>