package external;
import java.util.Arrays;
import java.util.logging.Logger;
import org.python.core.Py;
import org.python.core.PyInteger;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.autoplot.ScriptContext;
import org.autoplot.dom.Annotation;
import org.autoplot.dom.Application;
import org.autoplot.dom.DomNode;
import org.autoplot.jythonsupport.JythonOps;
import org.das2.graph.AnchorPosition;
import org.das2.graph.AnchorType;
import org.das2.graph.BorderType;
import org.das2.qds.ops.Ops;
import org.python.core.PyJavaInstance;
import org.python.core.PyList;
/**
* new implementation of the plot command allows for keywords in the
* Jython environment.
*
{@code
* annotation( 0, 'Anno1' )
* annotation( 1, 'Anno2', textColor='darkBlue', anchorPosition='NW' )
* plot( 'vap+cdaweb:ds=OMNI2_H0_MRG1HR&id=DST1800&timerange=Oct+2016' )
* annotation( 2, 'Anno3', anchorType='DATA',pointAt='2016-10-14T07:51Z,-100', xrange='2016-10-20T00:00/PT30S', yrange='-150 to -100',
* anchorPosition='OutsideNE', anchorOffset='' )
*}
* @see http://autoplot.org/help.annotationCommand
* @author jbf
*/
public class AnnotationCommand extends PyObject {
private static final Logger logger= org.das2.util.LoggerManager.getLogger("autoplot");
public static final PyString __doc__ =
new PyString(""
+ "text | The message, allowing Granny codes |
"
+ " textColor | text color\n |
"
+ " background | background color\n |
"
+ " foreground | foreground color\n |
"
+ " fontSize | size relative to parent (1.2em) or in pts (8pt)\n |
"
+ " borderType | draw a border around the annotation text none,rectangle,roundedRectangle . |
"
+ " anchorBorderType | draw a border around the anchor box. |
"
+ " anchorPosition | One of NE,NW,SE,SW, N,E,W,S, outsideN,outsideNNW |
"
+ " anchorOffset | position relative to the anchor, like '1em,1em' |
"
+ " anchorType | PLOT means relative to the plot. DATA means relative to xrange and yrange |
"
+ " xrange, yrange | anchor box when using data anchor |
"
+ " plotId | ID of the plot containing axes. |
"
+ " pointAt | comma separated X and Y to point the annotation arrow at. |
"
+ " rowId | ID of the row containing for positioning this annotation (See dom.plots[0].rowId) |
"
+ " columnId | ID of the column containing for positioning this annotation |
"
+ "
");
private static AnchorPosition anchorPosition( PyObject val ) {
AnchorPosition c=null;
if (val.__tojava__(AnchorPosition.class) != Py.NoConversion) {
c = (AnchorPosition) val.__tojava__(AnchorPosition.class);
} else if (val instanceof PyString) {
String sval = (String) val.__str__().__tojava__(String.class);
c = (AnchorPosition) lookupEnum( AnchorPosition.values(), sval );
} else {
throw new IllegalArgumentException("anchorPosition must be a string or AnchorPosition");
}
return c;
}
private static Object lookupEnum( Object[] vs, String s ) {
s= s.toLowerCase();
for ( Object v: vs ) {
if ( v.toString().toLowerCase().equals(s) ) return v;
}
throw new IllegalArgumentException("unable to find enumerated value for "+s);
}
private static AnchorType anchorType( PyObject val ) {
AnchorType c=null;
if (val.__tojava__(AnchorType.class) != Py.NoConversion) {
c = (AnchorType) val.__tojava__(AnchorType.class);
} else if (val instanceof PyString) {
String sval = (String) val.__str__().__tojava__(String.class);
c = (AnchorType) lookupEnum( AnchorType.values(), sval );
} else {
throw new IllegalArgumentException("anchorType must be a string or AnchorType");
}
return c;
}
private static BorderType borderType( PyObject val ) {
BorderType c=null;
if ( val==Py.None ) {
return BorderType.NONE;
} else if (val.__tojava__(BorderType.class) != Py.NoConversion) {
c = (BorderType) val.__tojava__(BorderType.class);
} else if (val instanceof PyString) {
String sval = (String) val.__str__().__tojava__(String.class);
c = (BorderType) lookupEnum( BorderType.values(), sval );
} else {
throw new IllegalArgumentException("borderType must be a string or BorderType");
}
return c;
}
private static boolean booleanValue( PyObject arg0 ) {
if ( arg0.isNumberType() ) {
return arg0.__nonzero__();
} else {
String s= String.valueOf(arg0);
return s.equals("True") || s.equals("T") || s.equals("1");
}
}
/**
* implement the python call.
* @param args the "rightmost" elements are the keyword values.
* @param keywords the names for the keywords.
* @return the annotation
*/
@Override
public PyObject __call__(PyObject[] args, String[] keywords) {
FunctionSupport fs= new FunctionSupport( "annotation",
new String[] { "index",
"text", "textColor", "background", "foreground",
"anchorPosition", "anchorOffset", "anchorType", "borderType", "anchorBorderType",
"fontSize",
"pointAtX", "pointAtY", "pointAt",
"xrange", "yrange", "plotId",
"rowId", "columnId"
},
new PyObject[] { new PyInteger(0),
Py.None, Py.None, Py.None, Py.None,
Py.None, Py.None, Py.None, Py.None, Py.None,
Py.None,
Py.None, Py.None, Py.None,
Py.None, Py.None, Py.None,
Py.None, Py.None,
} );
fs.args( args, keywords );
int nparm= args.length - keywords.length;
int index=0;
int nargs= nparm;
// If the first (zeroth) argument is an int, than this is the data source where the value should be inserted. Additional
// data sources and plots will be added until there are enough.
// this is an alias for the index argument.
if ( args.length>0 ) {
PyObject po0= args[0];
if ( po0 instanceof PyInteger ) {
index= ((PyInteger)po0).getValue();
PyObject[] newArgs= new PyObject[args.length-1];
for ( int i=0; i