package org.das2.qds.examples; import java.text.ParseException; import java.util.logging.Level; import java.util.logging.Logger; import org.das2.datum.EnumerationUnits; import org.das2.datum.Units; import org.das2.datum.UnitsUtil; import org.das2.qds.ArrayDataSet; import org.das2.qds.DDataSet; import org.das2.qds.DataSetUtil; import org.das2.qds.JoinDataSet; import org.das2.qds.MutablePropertyDataSet; import org.das2.qds.QDataSet; import org.das2.qds.SemanticOps; import org.das2.qds.SparseDataSetBuilder; import org.das2.qds.WritableDataSet; import org.das2.qds.ops.Ops; import static org.das2.qds.ops.Ops.PI; import static org.das2.qds.ops.Ops.linspace; import static org.das2.qds.ops.Ops.ripples; /** * For the various QDataSet schemes, show examples and documentation for * each. This was motivated when trying to describe the output of * org.das2.graph.ContoursRenderer.doAutorange() * * Note all QDataSets are "duck-typed," meaning if they happen to meet the * requirements of an interface then they are an instance of the interface. * * @author jbf */ public class Schemes { private static Logger logger= Logger.getLogger("qdataset.schemes"); /** * return a bounding box for the data. This is a rank 2 dataset where * ds[0,:] shows the bounds for the first dimension and ds[1,:] shows the * bounds for the second dimension. Therefor ds[0,0] is the minumum extent * of the first dimension, and ds[0,1] is the maximum. * Note this can be extended to any number * of dimensions (cube or hypercube). * * Note, *
*from org.das2.qds.examples import Schemes
*ds= Schemes.boundingBox()
*print asDatumRange(ds.slice(0))
*
*
* @return a bounding box for the data.
* @see org.das2.qds.DataSetUtil#asDatumRange(org.das2.qds.QDataSet)
*/
public static QDataSet boundingBox( ) {
try {
QDataSet xx= Ops.timegen( "2015-02-20T00:30", "60 s", 1440 );
QDataSet yy= Ops.linspace( 14., 16., 1440 );
JoinDataSet bds= new JoinDataSet(2);
bds.join( Ops.extent( xx ) );
bds.join( Ops.extent( yy ) );
bds.makeImmutable();
return bds;
} catch (ParseException ex) {
throw new RuntimeException(ex);
}
}
/**
* return true if the data is a boundingBox.
* @param ds a dataset
* @return true if the dataset is a bounding box.
*/
public static boolean isBoundingBox( QDataSet ds ) {
return ds.rank()==2 && ds.length(0)==2 && ds.length()>0;
}
/**
* return a rank 2 waveform, where the waveform is stored in packets.
* DEPEND_0 is the time for each packet, and DEPEND_1 is the difference in
* time for each measurement to the packet time. Note the additional requirement
* that the offsets be uniform, e.g.:
*
*from org.das2.qds.examples import Schemes
*ds= Schemes.rank2Waveform()
*deltaT= ds.property( QDataSet.DEPEND_1 )
*ddeltaT= diffs(dep1)
*print ddeltaT[0], ddeltT[-1] # should be the same
*
*
* @return rank 2 waveform.
*/
public static QDataSet rank2Waveform( ) {
return Ops.ripplesWaveformTimeSeries(20);
}
/**
* return true if the data is a rank 2 waveform.
* @param ds a dataset
* @return true if the data is a rank 2 waveform.
*/
public static boolean isRank2Waveform( QDataSet ds ) {
if ( ds.rank()!=2 ) return false;
QDataSet dep0= (QDataSet)ds.property(QDataSet.DEPEND_0);
if ( dep0==null ) return false;
Units u0= SemanticOps.getUnits(dep0);
if ( u0==Units.dimensionless ) {
return false;
} else {
QDataSet dep1= (QDataSet)ds.property(QDataSet.DEPEND_1);
if ( dep1==null ) return false;
if ( dep1.length()
*from org.das2.qds.examples import Schemes
*ds= Schemes.vectorTimeSeries()
*plot( magnitude( ds ) )
*plot( unbundle( ds, 0 ) )
*
* dataset→rank2bundle→vectorTimeSeries.
* @return rank 2 vector time series.
*/
public static QDataSet vectorTimeSeries( ) {
return Ops.ripplesVectorTimeSeries(1440);
}
/**
* return true if the data is a vector time series.
* @param ds a dataset
* @return true if the data is a vector time series.
*/
public static boolean isVectorTimeSeries( QDataSet ds ) {
return ds.rank()==2 && ( Ops.isLegacyBundle(ds) || Ops.isBundle(ds) ) && isTimeSeries(ds);
}
/**
* return a rank 2 simple spectrogram, which has two indeces.
* @return rank 2 simple spectrogram
*/
public static QDataSet simpleSpectrogram() {
return Ops.ripples(40,30);
}
/**
* return true if the data is a simple spectrogram, which is
* rank 2, and not a small bundle.
* @param ds a dataset
* @return true if the data is a simple spectrogram.
*/
public static boolean isSimpleSpectrogram( QDataSet ds ) {
if ( ds.rank()==2 ) {
return !(ds.length(0)<4 && ( Ops.isBundle(ds) || Ops.isLegacyBundle(ds) ));
} else {
return false;
}
}
/**
* return a rank 1 scalar time series.
* @return a rank 1 scalar time series.
*/
public static QDataSet scalarTimeSeries() {
try {
QDataSet density= Ops.add( Ops.ripples(20), Ops.randomn(0,20) );
density= Ops.putProperty( density, QDataSet.UNITS, Units.pcm3 );
QDataSet t = Ops.timegen("2011-10-24", "20 sec", 20 );
return Ops.link( t, density );
} catch (ParseException ex) {
throw new RuntimeException(ex);
}
}
/**
* return true if the data is a simple time series of scalars.
* @param ds a dataset
* @return true if the data is a simple spectrogram.
*/
public static boolean isScalarTimeSeries( QDataSet ds ) {
return ds.rank()==1 && isTimeSeries(ds);
}
/**
* return a rank 1 scalar series with errors.
* @return a rank 1 scalar series with errors.
*/
public static QDataSet scalarSeriesWithErrors() {
QDataSet x= Ops.add( 1, Ops.divide( Ops.findgen(41),2 ) );
QDataSet y= Ops.exp( Ops.multiply( -1, Ops.pow( Ops.subtract(x,10), 2 ) ) );
MutablePropertyDataSet result= Ops.maybeCopy( Ops.link( x, y ) );
result.putProperty( QDataSet.DELTA_PLUS, Ops.replicate(0.04,41) );
result.putProperty( QDataSet.DELTA_MINUS, Ops.replicate(0.04,41) );
return result;
}
/**
* return true is the data is a simple series of scalars with errors.
* @param ds dataset
* @return true is the data is a simple series of scalars with errors.
*/
public static boolean isScalarSeriesWithErrors( QDataSet ds ) {
return ds.rank()==1
&& ds.property(QDataSet.DELTA_PLUS)!=null
&& ds.property(QDataSet.DELTA_MINUS)!=null;
}
/**
* return a rank 2 simple spectrogram, which has two indeces
* and is a TimeSeries.
* @return simple spectrogram time series
*/
public static QDataSet simpleSpectrogramTimeSeries() {
return Ops.ripplesSpectrogramTimeSeries(1440);
}
/**
* return true if the data is a simple spectrogram.
* @param ds a dataset
* @return true if the data is a simple spectrogram.
*/
public static boolean isSimpleSpectrogramTimeSeries( QDataSet ds ) {
return isSimpleSpectrogram(ds) && isTimeSeries(ds);
}
/**
* returns true if the dataset is a time series. This is either something
* that has DEPEND_0 as a dataset with time location units, or a join of
* other datasets that are time series.
* @param ds a dataset
* @return true if the dataset is a time series.
* @see SemanticOps#isTimeSeries(org.das2.qds.QDataSet)
*/
public static boolean isTimeSeries( QDataSet ds ) {
return SemanticOps.isTimeSeries(ds);
}
/**
* uniform cadence is when each tag is the same distance apart, within a reasonable threshold.
* @return dataset with uniform cadence
*/
public static QDataSet uniformCadence() {
return Ops.linspace( 0., 4., 100 );
}
/**
* return true of the data has a uniform cadence. Note that
* the CADENCE property is ignored.
* @param ds a rank 1 dataset
* @return true if the data has uniform cadence.
*/
public static boolean isUniformCadence( QDataSet ds ) {
if ( ds.rank()!=1 ) return false;
double dv= ds.value(1)-ds.value(0);
double manyDv= ( ds.value(ds.length()-1)-ds.value(0) ) / ( ds.length()-1) ;
return ( ( manyDv - dv ) / dv ) < 0.001;
}
/**
* uniform ratiometric cadence is when the tags are uniform in log space.
* @return dataset with uniform ratiometric cadence.
*/
public static QDataSet uniformRatiometricCadence() {
return Ops.pow( 10, Ops.linspace( 0., 4., 100 ) );
}
/**
* return true of the data has a uniform cadence. Note that
* the CADENCE property is ignored.
* @param ds a rank 1 dataset
* @return true if the data has uniform cadence.
*/
public static boolean isUniformRatiometricCadence( QDataSet ds ) {
if ( ds.rank()!=1 ) return false;
double dv= Math.log( ds.value(1)/ds.value(0) );
double manyDv= Math.log( ds.value(ds.length()-1) / ds.value(0) ) / ( ds.length()-1 );
return ( ( manyDv - dv ) / dv ) < 0.001;
}
/**
* return an example of a compositeImage.
* @return image[320,240,3]
*/
public static QDataSet compositeImage() {
WritableDataSet rgb= Ops.zeros( 320, 240, 3 );
for ( int i=0; i<320; i++ ) {
for ( int j=0; j<240; j++ ) {
if ( ( Math.pow((i-160),2) + Math.pow((j-120),2) ) <2500 ) rgb.putValue( i,j,0, 255 );
if ( i<160 ) rgb.putValue( i,j,1, 255 );
if ( j<120 ) rgb.putValue( i,j,2, 255 );
}
}
rgb.putProperty( QDataSet.DEPEND_0, Ops.linspace(0,4,rgb.length() ) );
rgb.putProperty( QDataSet.DEPEND_1, Ops.pow( 10, Ops.linspace(0,4,rgb.length(0) ) ) );
rgb.putProperty( QDataSet.RENDER_TYPE, QDataSet.VALUE_RENDER_TYPE_COMPOSITE_IMAGE );
return rgb;
}
/**
* return true if the dataset is a composite image, and is plottable
* with the RGBImageRenderer
* @param ds a dataset
* @return true if the dataset is a composite image.
*/
public static boolean isCompositeImage( QDataSet ds ) {
QDataSet dep0= (QDataSet) ds.property(QDataSet.DEPEND_0);
QDataSet dep1= (QDataSet) ds.property(QDataSet.DEPEND_1);
return ds.rank()==3 && DataSetUtil.checkQube(ds)
&& ( dep0==null || isUniformCadence(dep0) || isUniformRatiometricCadence(dep0) )
&& ( dep1==null || isUniformCadence(dep1) || isUniformRatiometricCadence(dep1) );
}
/**
* return example events list. This is a four-column rank 2 dataset with
* start time, end time, RGB color, and ordinal data for the message.
* @return example events list.
*/
public static QDataSet eventsList( ) {
try {
QDataSet xx= Ops.timegen( "2015-01-01", "60s", 1440 );
QDataSet dxx= Ops.putProperty( Ops.replicate( 45, 1440 ), QDataSet.UNITS, Units.seconds );
QDataSet color= Ops.replicate( 0xFFAAAA, 1440 );
for ( int i=100; i<200; i++ ) ((WritableDataSet)color).putValue( i, 0xFFAAFF );
EnumerationUnits eu= EnumerationUnits.create("default");
QDataSet msgs= Ops.putProperty( Ops.replicate( eu.createDatum("on1").doubleValue(eu), 1440 ), QDataSet.UNITS, eu );
QDataSet result= Ops.bundle( xx, Ops.add(xx,dxx), color, msgs );
return result;
} catch (ParseException ex) {
throw new IllegalArgumentException(ex);
}
}
/**
* return true if the data is an events list.
* @param ds a dataset
* @return true if the data is an events list.
*/
public static boolean isEventsList( QDataSet ds ) {
QDataSet bundle1= (QDataSet) ds.property(QDataSet.BUNDLE_1);
if ( bundle1!=null ) {
if ( bundle1.length()==3 || bundle1.length()==4 || bundle1.length()==5 ) {
Units u0= (Units) bundle1.property(QDataSet.UNITS,0);
if ( u0==null ) u0= Units.dimensionless;
Units u1= (Units) bundle1.property(QDataSet.UNITS,1);
if ( u1==null ) u1= Units.dimensionless;
Units u3= (Units) bundle1.property(QDataSet.UNITS,bundle1.length()-1);
if ( u3!=null && UnitsUtil.isOrdinalMeasurement(u3) && u0.getOffsetUnits().isConvertibleTo(u1) ) {
if ( u0.isConvertibleTo(u1) ) {
QDataSet isge= Ops.ge( Ops.slice1( ds, 1 ), Ops.slice1( ds, 0 ) );
return Ops.total(isge) == Ops.total( Ops.valid( Ops.slice1(ds,0) ) );
} else {
QDataSet isge= Ops.ge( Ops.abs( Ops.slice1( ds, 1 ) ), 0. );
return Ops.total(isge) == Ops.total( Ops.valid( Ops.slice1(ds,0) ) );
}
} else if ( u3!=null && UnitsUtil.isOrdinalMeasurement(u3) && u0.isConvertibleTo(u1) ) {
QDataSet isge= Ops.ge( Ops.slice1( ds, 1 ), Ops.slice1( ds, 0 ) );
return Ops.total(isge) == Ops.total( Ops.valid( Ops.slice1(ds,0) ) );
}
} else {
Units u3= (Units) bundle1.property(QDataSet.UNITS,bundle1.length()-1);
if ( u3!=null && UnitsUtil.isOrdinalMeasurement(u3) ) {
return true;
}
}
} else {
if ( SemanticOps.getUnits(ds) instanceof EnumerationUnits ) {
QDataSet dep0= (QDataSet) ds.property(QDataSet.DEPEND_0);
if ( dep0!=null ) {
return true;
}
}
}
return false;
}
/**
* return example angle distribution.
* @return example angle distribution.
*/
public static QDataSet angleDistribution( ) {
ArrayDataSet rip= ArrayDataSet.maybeCopy( ripples( 30, 15 ) );
QDataSet angle= linspace( PI/30/2, PI-PI/30/2, 30 );
angle= Ops.putProperty( angle, QDataSet.UNITS, Units.radians );
QDataSet rad= linspace( 1, 5, 15 );
rip.putProperty( QDataSet.DEPEND_0, angle );
rip.putProperty( QDataSet.DEPEND_1, rad );
rip.putProperty( QDataSet.RENDER_TYPE, "pitchAngleDistribution" );
return rip;
}
/**
* return example angle distribution.
* @param i the example number. 0..n-1.
* @return example angle distribution.
*/
public static QDataSet angleDistribution( int i ) {
if ( i==0 ) {
ArrayDataSet rip= ArrayDataSet.maybeCopy( Ops.randn( 24, 15 ) );
for ( int j= 0; j<15; j++ ) {
rip.putValue( 0, j, 20. );
rip.putValue( 4, j, 20. );
}
QDataSet angle= Ops.multiply( linspace( 0.5, 23.5, 24 ), 15 );
angle= Ops.putProperty( angle, QDataSet.UNITS, Units.degrees );
QDataSet rad= linspace( 1, 5, 15 );
rip.putProperty( QDataSet.DEPEND_0, angle );
rip.putProperty( QDataSet.DEPEND_1, rad );
rip.putProperty( QDataSet.RENDER_TYPE, "pitchAngleDistribution" );
return rip;
} else {
return null;
}
}
/**
* return true if the data is an angle distribution.
* @param ds a dataset
* @return true if the data is an angle distribution.
*/
public static boolean isAngleDistribution( QDataSet ds ) {
if ( ds.rank()!=2 ) return false;
QDataSet ads= (QDataSet)ds.property(QDataSet.DEPEND_0);
//QDataSet rds= (QDataSet)ds.property(QDataSet.DEPEND_1);
Units au= (Units) ads.property(QDataSet.UNITS);
if ( au!=null && !( au==Units.dimensionless || au.isConvertibleTo(Units.degrees) ) ) {
return false;
}
return true;
}
/**
* A complexBundleDataSet is a set of datasets which have different rank. The
* rank 2 datasets take multiple columns of the dataset, and rank 3 and 4 datasets
* are unrolled to make them rank 2 and the property ELEMENT_DIMENSIONS is used
* to re-form them. This returns an example bundle dataset that bundles timetags, density, velocity, and flux.
* Yes, this was coded this twice, not realizing it was already done. This code
* is probably easier to read, so it is left in.
*
* @return an example bundle dataset
* @see #complexBundleDataSet()
*/
public static QDataSet complexBundleDataSet2() {
DDataSet data= DDataSet.createRank2( 12, 9 );
QDataSet ttags= Ops.linspace( "2019-03-07T00:30Z", "2019-03-07T11:30Z", 12 );
QDataSet vel= vectorTimeSeries();
QDataSet dens= scalarTimeSeries();
QDataSet flux= simpleSpectrogram();
for ( int i=0; i