Commit 5cb1972e authored by Jörn Starruß's avatar Jörn Starruß
Browse files

Plotting improvements

- Gnuplotter allows to set a z-slice per Plot and also Arrows and Labels
follow the z-slize filter.
- Gnuplotter cell opacity moved to Plot/Cells
- Logger learned to use discrete colors for integer data

Resolves #96
parent f428104c
......@@ -10,9 +10,14 @@
### MorpheusML
* The space symbol (Space/SpaceSymbol) now always provides the location in orthogonal coordinates, also on hexagonal lattices.
* AddCell accepts Count as the number of cells to be placed.
* AddCell accepts Count instead of Condition as the number of cells to be placed.
* ClusterTracker can cluster cells of multiple cell types.
* Logger gained support for conditional logging using Logger/Restrictions/@condition
* Logger
* gained support for conditional logging using Logger/Restrictions/@condition
* learned to use discrete colors for integer data
* Gnuplotter
* allows to set a z-slice per Plot and also Arrows and Labels follow the z-slize filter.
* cell opacity moved to Plot/Cells/@opacity
* Added Populations InitVectorProperty with optional spherical notation
* Lattice size now can also be specified through expressions
* Contact energies now support expressions with access to symbols of involved cells
......@@ -20,7 +25,7 @@
* XSD parser supports extension of complexTypes
* Plugins are extension of base types
* Registration of plugins as members of <xs:all> groups
* Added **tags** and **Annotation** nodes to all plugins
* Added **@tags** and **Annotation** nodes to all model components
### Simulator
* Performance improvements for Mappers and Reporters using OpenMP parallelization
......
......@@ -358,6 +358,18 @@ QList<MorphModelEdit> MorphModel::applyAutoFixes(QDomDocument document) {
a.match_path ="MorpheusModel/CellTypes/CellType/System/@solver";
a.target_path="MorpheusModel/CellTypes/CellType/System/@solver";
fixes.append(a);
a.match_path ="MorpheusModel/Analysis/Gnuplotter/Plot/Field/@slice";
a.target_path="MorpheusModel/Analysis/Gnuplotter/Plot/@slice";
a.operation = AutoFix::MOVE;
fixes.append(a);
a.match_path ="MorpheusModel/Analysis/Gnuplotter/Plot/Cells/@slice";
a.target_path="MorpheusModel/Analysis/Gnuplotter/Plot/@slice";
a.operation = AutoFix::MOVE;
fixes.append(a);
a.match_path ="MorpheusModel/Analysis/Gnuplotter/Terminal/@opacity";
a.target_path="MorpheusModel/Analysis/Gnuplotter/Plot/Cells/@opacity";
a.operation = AutoFix::MOVE;
fixes.append(a);
}
else if (morpheus_file_version == 3) {
......
#include "gnuplotter.h"
#include "focusrange.h"
using namespace SIM;
......@@ -6,7 +8,7 @@ using namespace SIM;
const float CellPainter::transparency_value = std::numeric_limits<float>::quiet_NaN();
Gnuplotter::PlotSpec::PlotSpec() :
field(false), cells(false), labels(false), arrows(false), vectors(false), title("") {};
field(false), cells(false), labels(false), arrows(false), vectors(false), z_slice(0), title("") {};
VDOUBLE Gnuplotter::PlotSpec::size()
{
......@@ -60,10 +62,11 @@ void ArrowPainter::loadFromXML(const XMLNode node, const Scope * scope)
int ArrowPainter::getStyle() { return style; }
void ArrowPainter::init(const Scope* scope)
void ArrowPainter::init(const Scope* scope, int slice)
{
arrow.init();
centering.init();
z_slice = slice;
}
set< SymbolDependency > ArrowPainter::getInputSymbols() const
......@@ -89,13 +92,15 @@ void ArrowPainter::plotData(ostream& out)
if (ct->isMedium())
continue;
vector<CPM::CELL_ID> cells = ct->getCellIDs();
// vector<CPM::CELL_ID> cells = ct->getCellIDs();
for (uint c=0; c< cells.size(); c++){
SymbolFocus f(cells[c]);
// for (uint c=0; c< cells.size(); c++){
// SymbolFocus f(cells[c]);
FocusRange range(Granularity::Cell, {{FocusRangeAxis::Z, z_slice}, {FocusRangeAxis::CellType, ct->getID()}});
for (const SymbolFocus& focus : range){
try {
VDOUBLE a = arrow(f);
VDOUBLE center = f.cell().getCenter();
VDOUBLE a = arrow(focus);
VDOUBLE center = focus.cell().getCenter();
lattice.orth_resolve (center);
if (! (a.x == 0 && a.y==0) ) {
......@@ -131,11 +136,11 @@ void FieldPainter::loadFromXML(const XMLNode node, const Scope * scope)
surface.setXMLPath("surface");
surface.loadFromXML(node, scope);
z_slice.setXMLPath("slice");
z_slice.setDefault("0");
z_slice.loadFromXML(node, scope);
if (z_slice()<0 || z_slice() >= SIM::lattice().size().z)
throw MorpheusException("Invalid z_slice.", node);
// z_slice.setXMLPath("slice");
// z_slice.setDefault("0");
// z_slice.loadFromXML(node, scope);
// if (z_slice()<0 || z_slice() >= SIM::lattice().size().z)
// throw MorpheusException("Invalid z_slice.", node);
// getXMLAttribute(xPlotChild, "data-cropping", plot.pde_data_cropping);
......@@ -154,8 +159,9 @@ void FieldPainter::loadFromXML(const XMLNode node, const Scope * scope)
}
}
void FieldPainter::init(const Scope* scope)
void FieldPainter::init(const Scope* scope, int slice)
{
z_slice = slice;
field_value.init();
if( min_value.isDefined() )
min_value.init();
......@@ -228,7 +234,7 @@ void FieldPainter::plotData(ostream& out)
string xsep(" "), ysep("\n");
VINT out_pos;
VINT pos(0,0,z_slice.get());
VINT pos(0,0, z_slice);
valarray<float> out_data(out_size.x), out_data2(out_size.x);
valarray<float> out_data_count(out_size.x);
......@@ -324,16 +330,13 @@ void VectorFieldPainter::loadFromXML(const XMLNode node, const Scope* scope)
getXMLAttribute(node, "color", color);
coarsening = 1;
getXMLAttribute(node, "coarsening",coarsening);
// scaling=1.0;
// getXMLAttribute(node,"scaling",scaling);
slice = 0;
getXMLAttribute(node,"slice",slice);
}
void VectorFieldPainter::init(const Scope* scope)
void VectorFieldPainter::init(const Scope* scope, int slice)
{
value.init();
centering.init();
z_slice = slice;
}
set< SymbolDependency > VectorFieldPainter::getInputSymbols() const
......@@ -345,7 +348,7 @@ set< SymbolDependency > VectorFieldPainter::getInputSymbols() const
void VectorFieldPainter::plotData(ostream& out)
{
auto& lattice = SIM::lattice();
VINT pos(0, 0, slice);
VINT pos(0, 0, z_slice);
VINT size = lattice.size();
for (pos.y=coarsening/2; pos.y<size.y; pos.y+=coarsening) {
for (pos.x=coarsening/2; pos.x<size.x; pos.x+=coarsening) {
......@@ -380,6 +383,7 @@ LabelPainter::LabelPainter()
{
_fontcolor="black";
_fontsize=12;
z_slice = -1;
value.setXMLPath("value");
value.setUndefVal("");
}
......@@ -409,9 +413,10 @@ void LabelPainter::loadFromXML(const XMLNode node, const Scope* scope)
void LabelPainter::init(const Scope* scope)
void LabelPainter::init(const Scope* scope, int slice)
{
value.init();
this->z_slice = slice;
}
......@@ -439,11 +444,10 @@ void LabelPainter::plotData(ostream& out)
auto ct = celltypes[i].lock();
if ( ct->isMedium() )
continue;
vector<CPM::CELL_ID> cells = ct->getCellIDs();
for (uint c=0; c< cells.size(); c++){
SymbolFocus focus(cells[c]);
// vector<CPM::CELL_ID> cells = ct->getCellIDs();
FocusRange range(Granularity::Cell, {{FocusRangeAxis::Z, z_slice}, {FocusRangeAxis::CellType, ct->getID()}});
for (const SymbolFocus& focus : range){
string val = value.get(focus);
if ( ! val.empty() ) {
......@@ -464,6 +468,7 @@ CellPainter::CellPainter()
external_range = false;
min_val = 1e12;
max_val = -1e12;
fill_opacity = 1.0;
z_level = 0;
symbol.setXMLPath("value");
symbol.setDefault("cell.type");
......@@ -489,10 +494,13 @@ void CellPainter::loadFromXML(const XMLNode node, const Scope* scope)
if (getXMLAttribute(node,"max",range_max) )
external_range_max = true;
external_range = external_range_min && external_range_max;
getXMLAttribute(node,"opacity", fill_opacity);
fill_opacity = cpp17::clamp(fill_opacity, 0.0, 1.0);
if (string(node.getName()) == "Cells") {
getXMLAttribute(node,"slice",z_level);
// getXMLAttribute(node,"slice",z_level);
getXMLAttribute(node,"flooding",flooding);
getXMLAttribute(node,"per-frame-range", reset_range_per_frame);
......@@ -533,12 +541,12 @@ void CellPainter::loadPalette(const XMLNode node)
}
}
void CellPainter::init(const Scope* scope) {
void CellPainter::init(const Scope* scope, int slice) {
symbol.init();
z_level = slice;
cpm_layer = CPM::getLayer();
if(z_level > cpm_layer->size().z){
if(z_level > cpm_layer->size().z || z_level < 0 ){
throw string("CellPainter: z-slice to be plotted lies outside of lattice range = ") + to_str(cpm_layer->size()) + ".";
}
......@@ -979,8 +987,8 @@ Gnuplotter::Gnuplotter(): AnalysisPlugin(), gnuplot(NULL) {
// pointsize.setDefault("0.5");
// registerPluginParameter(pointsize);
cell_opacity.setXMLPath("Terminal/opacity");
registerPluginParameter(cell_opacity);
// cell_opacity.setXMLPath("Terminal/opacity");
// registerPluginParameter(cell_opacity);
......@@ -1052,6 +1060,10 @@ void Gnuplotter::loadFromXML(const XMLNode xNode, Scope* scope)
XMLNode xPlot = xNode.getChildNode(plot_tag.c_str(),i);
PlotSpec plot;
getXMLAttribute(xPlot, "title", plot.title);
getXMLAttribute(xPlot, "slice", plot.z_slice);
if (plot.z_slice<0 || plot.z_slice >= SIM::lattice().size().z)
throw MorpheusException("Invalid z_slice.", xPlot);
for (int j=0; j<xPlot.nChildNode(); j++) {
XMLNode xPlotChild = xPlot.getChildNode(j);
string node_name = xPlotChild.getName();
......@@ -1126,23 +1138,23 @@ void Gnuplotter::init(const Scope* scope) {
for (uint i=0;i<plots.size();i++) {
if (plots[i].cells) {
plots[i].cell_painter->init(scope);
plots[i].cell_painter->init(scope, plots[i].z_slice);
registerInputSymbols( plots[i].cell_painter->getInputSymbols() );
}
if (plots[i].label_painter) {
plots[i].label_painter->init(scope);
plots[i].label_painter->init(scope, plots[i].z_slice);
registerInputSymbols( plots[i].label_painter->getInputSymbols() );
}
if (plots[i].arrow_painter) {
plots[i].arrow_painter->init(scope);
plots[i].arrow_painter->init(scope, plots[i].z_slice);
registerInputSymbols( plots[i].arrow_painter->getInputSymbols() );
}
if (plots[i].vector_field_painter) {
plots[i].vector_field_painter->init(scope);
plots[i].vector_field_painter->init(scope, plots[i].z_slice);
registerInputSymbols( plots[i].vector_field_painter->getInputSymbols() );
}
if (plots[i].field) {
plots[i].field_painter->init(scope);
plots[i].field_painter->init(scope, plots[i].z_slice);
registerInputSymbols( plots[i].field_painter->getInputSymbols() );
}
}
......@@ -1498,8 +1510,8 @@ void Gnuplotter::analyse(double time) {
command << plots[i].cell_painter->getPaletteCmd() << endl;
command << "unset contour;\n";
if (cell_opacity.isDefined() && cell_opacity() < 1.0 && cell_opacity() >= 0)
command << "set style fill transparent solid " << cell_opacity() << " noborder;\n";
if (plots[i].cell_painter->getOpacity() < 1.0)
command << "set style fill transparent solid " << plots[i].cell_painter->getOpacity() << " noborder;\n";
//command << "set cbrange ["<< plots[i].cell_painter->getMinVal() << ":"<< plots[i].cell_painter->getMaxVal() << "]" << endl;
command << "set style line 40 lc rgb \"black\" lw " << cell_contour_width << "\n";
if ( ! decorate)
......@@ -1518,8 +1530,8 @@ void Gnuplotter::analyse(double time) {
else
command << "set xlabel '" << time << " " /*<< SIM::getTimeScaleUnit() */ << "' offset 0," << (using_splot ? "0.1" : "2") << ";\n";
if (plots[i].cell_painter->getSlice() > 0)
command << "set title '" << plot_title << " (z-slice: " << plots[i].cell_painter->getSlice() << ")' offset 0,-0.5;\n";
if (plots[i].z_slice > 0)
command << "set title '" << plot_title << " (z-slice: " << plots[i].z_slice << ")' offset 0,-0.5;\n";
else
command << "set title '" << plot_title << "' offset 0,-0.5;\n";
}
......
......@@ -8,6 +8,8 @@
// Copyright 2009-2016, Technische Universität Dresden, Germany
//
//////
#ifndef GNUPLOTTER_H
#define GNUPLOTTER_H
#include "core/simulation.h"
#include "core/interfaces.h"
......@@ -19,12 +21,12 @@
#include "gnuplot_i/gnuplot_i.h"
#include <fstream>
#include <sstream>
/**
* \defgroup Gnuplotter Gnuplotter
* \ingroup ML_Analysis
* \ingroup AnalysisPlugins
* \brief Visualisation of spatial simulation states (cells, fields) using GnuPlot.
*
/**
\defgroup Gnuplotter Gnuplotter
\ingroup ML_Analysis
\ingroup AnalysisPlugins
\brief Visualisation of spatial simulation states (cells, fields) using GnuPlot.
\section Description
Gnuplotter plots the Cell configurations (and optionally Fields) to screen or to file during simulation.
......@@ -47,6 +49,8 @@ Organized in Plots, several artistic representations can be selected:
- \b name: Specifies the output format (e.g. wxt, x11, aqua, png, postscript). Default is Gnuplot default.
\subsection Plot
- \b title: Title of the plot.
- \b slice: Z-slice of 3D lattice to plot.
- \b Cells: Plot the spatial cell pattern restricted to a 2d scenario. Cell coloring is determined by the \b value attribute.
- \b CellLabels: Put labels at the cell center according to the expression provided with the \b value attribute.
- \b CellArrows: Put arrows at the cell center according to the expression provided with the \b value attribute.
......@@ -56,74 +60,55 @@ Organized in Plots, several artistic representations can be selected:
\section Examples
Plot CPM state (showing cell types) to screen using WxWidgets terminal
\verbatim
~~~~~~~~~~~~~~~~~~~~~{.xml}
<Analysis>
<Gnuplotter interval="100">
<Terminal name="wxt"/>
<Gnuplotter time-step="100">
<Terminal name="png"/>
<Plot>
<Cells value="cell.id" />
</Plot>
</Gnuplotter>
<\Analysis>
\endverbatim
~~~~~~~~~~~~~~~~~~~~~
Example: Plot CPM state showing two cell properties to PNG files
\verbatim
~~~~~~~~~~~~~~~~~~~~~{.xml}
<Analysis>
<Gnuplotter interval="100">
<Gnuplotter time-step="100">
<Terminal name="png"/>
<CellProperty name="target volume" type="integer"/>
<CellProperty name="divisions" type="integer"/>
<Plot>
<Cells value="cell.volume.target" />
</Plot>
<Plot>
<Cells value="cell.divisions">
<ColorMap>
<Color value="1" name="black" />
<Color value="25" name="red" />
<Color value="50" name="yellow"/>
</ColorMap>
</Cells>
</Plot>
</Gnuplotter>
<\Analysis>
\endverbatim
~~~~~~~~~~~~~~~~~~~~~
Example: Plot CPM state showing a cell property (no cell membrane), and with custom color map
\verbatim
<Analysis>
<Gnuplotter interval="500">
<Terminal name="wxt"/>
<Membrane value="false"/>
<CellProperty name="target volume" type="integer">
<ColorMap>
<Color value="1" name="black" />
<Color value="25" name="red" />
<Color value="50" name="yellow"/>
</ColorMap>decorate
</CellProperty>
</Gnuplotter>
</Analysis>
\endverbatim
Example: Plot multiple panels to screen (CPM, PDE with surface, PDE with isolines)
\verbatim
Example: Plot multiple panels to screen (CPM cell outlines, PDE with surface, PDE with isolines), reducing the plot resolution for speed
~~~~~~~~~~~~~~~~~~~~~{.xml}
<Analysis>
<Gnuplotter interval="500">
<Terminal name="wxt"/>
<Layer name="chemoattractant" surface="false" />
<Layer name="chemoattractant" isolines="true"/>
<Plot>
<Cells />
<Field symbol-ref="chemoattractant" surface="false" coarsening="2"/>
</Plot
<Plot>
<Cells />
<Field symbol-ref="chemoattractant" isolines="true" coarsening="2"/>
</Plot
</Gnuplotter>
<\Analysis>
\endverbatim
Example: Plot multiple superimposed panels to postscript files (CPM, PDE surface and PDE isolines)
\verbatim
<Analysis>
<Gnuplotter interval="500">
<Terminal name="postscript"/>
<Layer name="chemoattractant" superimpose="true" isolines="true" surface="false" />
</Gnuplotter>
<\Analysis>
\endverbatim
Example: To gain plotting speed, plot PDE layer using binary files, with a resolution smaller than the world size (gradients will be interpolated)
\verbatim
<Analysis>
<Gnuplotter interval="25">
<Terminal name="wxt"/>
<Layer name="chemoattractant" surface="true" binary="true" resolution="50" />
</Gnuplotter>
<\Analysis>
\endverbatim
~~~~~~~~~~~~~~~~~~~~~
*/
......@@ -131,7 +116,7 @@ class LabelPainter {
public:
LabelPainter();
void loadFromXML(const XMLNode node, const Scope * scope);
void init(const Scope* scope);
void init(const Scope* scope, int slice);
set<SymbolDependency> getInputSymbols() const;
const string& getDescription() const;
void plotData(ostream& );
......@@ -143,13 +128,14 @@ private:
vector<shared_ptr< const CellType> > celltypes;
string _fontcolor;
uint _fontsize;
int z_slice;
};
class ArrowPainter {
public:
ArrowPainter();
void loadFromXML(const XMLNode, const Scope * scope);
void init(const Scope* scope);
void init(const Scope* scope, int slice);
set<SymbolDependency> getInputSymbols() const;
void plotData(ostream& );
int getStyle();
......@@ -159,6 +145,7 @@ private:
PluginParameter2<VDOUBLE, XMLEvaluator, DefaultValPolicy > arrow;
PluginParameter2<bool, XMLNamedValueReader, DefaultValPolicy > centering;
int style;
int z_slice;
};
/** @brief Visualiser for a spatial field in GnuPlot
......@@ -167,7 +154,7 @@ private:
class FieldPainter {
public:
void loadFromXML(const XMLNode node, const Scope * scope);
void init(const Scope* scope);
void init(const Scope* scope, int slice);
set<SymbolDependency> getInputSymbols() const;
void plotData(ostream& out );
bool getSurface() { if( surface.isDefined() ) return surface.get(); else return true;}
......@@ -185,8 +172,9 @@ private:
PluginParameter2<float,XMLEvaluator,OptionalPolicy> min_value, max_value;
PluginParameter2<int,XMLValueReader,OptionalPolicy> isolines;
PluginParameter2<bool,XMLValueReader,OptionalPolicy> surface;
PluginParameter2<int,XMLValueReader,DefaultValPolicy> z_slice;
// PluginParameter2<int,XMLValueReader,DefaultValPolicy> z_slice;
map<double,string> color_map;
int z_slice;
// int style;
......@@ -201,7 +189,7 @@ private:
class VectorFieldPainter {
public:
void loadFromXML(const XMLNode node, const Scope * scope );
void init(const Scope* scope);
void init(const Scope* scope, int slice);
set<SymbolDependency> getInputSymbols() const;
void plotData(ostream& out_ );
int getStyle();
......@@ -216,7 +204,7 @@ private:
int style;
string color;
int coarsening;
int slice;
int z_slice;
};
class CellPainter {
......@@ -252,6 +240,7 @@ class CellPainter {
bool external_palette;
bool external_range, external_range_min, external_range_max;
double range_min, range_max;
double fill_opacity;
void updateDataLayout();
void loadPalette(const XMLNode node);
XMLNode savePalette() const;
......@@ -261,12 +250,12 @@ class CellPainter {
CellPainter();
~CellPainter();
virtual void loadFromXML(const XMLNode, const Scope* scope );
void init(const Scope* scope);
void loadFromXML(const XMLNode, const Scope* scope );
void init(const Scope* scope, int slice);
set<SymbolDependency> getInputSymbols() const;
float getMaxVal() { return max_val;}
float getMinVal() { return min_val;}
uint getSlice() { return z_level;}
double getOpacity() { return fill_opacity; }
const string& getDescription() const;
void writeCellLayer(ostream& out);
DataLayout getDataLayout();
......@@ -296,6 +285,7 @@ class Gnuplotter : public AnalysisPlugin
static VDOUBLE size();
static VDOUBLE view_oversize();
bool field, cells, labels, arrows, vectors;
int z_slice;
shared_ptr<CellPainter> cell_painter;
shared_ptr<LabelPainter> label_painter;
shared_ptr<FieldPainter> field_painter;
......@@ -325,7 +315,7 @@ class Gnuplotter : public AnalysisPlugin
enum class Terminal{ PNG, PDF, JPG, GIF, SVG, EPS, SCREEN };
PluginParameter2<Terminal,XMLNamedValueReader,DefaultValPolicy> terminal;
PluginParameter2<VINT,XMLValueReader,OptionalPolicy> terminal_size;
PluginParameter2<double,XMLValueReader,OptionalPolicy> cell_opacity;
// PluginParameter2<double,XMLValueReader,OptionalPolicy> cell_opacity;
// PluginParameter2<double,XMLValueReader,DefaultValPolicy> pointsize;
struct TerminalSpec {
......@@ -368,3 +358,5 @@ class Gnuplotter : public AnalysisPlugin
virtual void finish() override {};
};
#endif
......@@ -38,6 +38,11 @@
<xs:element name="Field" type="cpmFieldPlotRef" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute name="title" use="optional" type="cpmString" />
<xs:attribute name="slice" type="cpmUnsignedInteger" use="optional">
<xs:annotation>
<xs:documentation>Z-slice of 3D lattice to plot (for z-stack plots).</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="cpmCellPlotRef">
......@@ -68,13 +73,6 @@
<xs:documentation>Maximum of colorbox.</xs:documentation>
</xs:annotation>
</xs:attribute>
<!--<xs:attribute name="mode" type="cpmcpmCellPlotModeEnum" use="required">
<xs:annotation>
<xs:documentation>Mode of plotting cells: cell type (default), cell id, property, membrane property.
Note: when (membrane) property has been selected, you MUST provide a symbol-ref to this property.</xs:documentation>
</xs:annotation>
</xs:attribute>-->
<xs:attribute name="flooding" type="cpmBoolean" use="optional" >
<xs:annotation>
<xs:documentation>Default is True. If true the inner of the cell is flooded with a color, if False individual points of the cell are drawn with the given pointsize. Membrane properties can only be plotted with flooding set to False.</xs:documentation>
......@@ -85,21 +83,25 @@ Note: when (membrane) property has been selected, you MUST provide a symbol-ref
<xs:documentation>Default is False. Per frame reset of the value range of the referred symbol .</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="slice" type="cpmUnsignedInteger" use="optional">
<xs:annotation>
<xs:documentation>Z-slice of 3D lattice to plot (for z-stack plots).</xs:documentation>
<xs:attribute name="opacity" type="cpmDouble" use="optional" default="1.0">
<xs:annotation>
<xs:documentation>Make cells gradually transparant, useful for superimposed frames.
((NOTE WdB)) I don't think this works at the moment. Gnuplot support transparency in filled curves, but not in points. Currently, however, cells are not not floodfilled but filled using points.
((NOTE JS)) That feature is exclusively working with the flooding option in cell plots.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attribute>
</xs:complexType>
<xs:simpleType name="cpmcpmCellPlotModeEnum">
<!-- <xs:simpleType name="cpmcpmCellPlotModeEnum">
<xs:restriction base="cpmString">
<xs:enumeration value="cell type"/>
<xs:enumeration value="cell id"/>
<xs:enumeration value="property"/>
<xs:enumeration value="membrane property"/>
</xs:restriction>
</xs:simpleType>
</xs:simpleType>-->
<xs:complexType name="cpmGnuplotCellLabels">