Skip to content

Commit

Permalink
Merge pull request #20 from sboschman/master
Browse files Browse the repository at this point in the history
loess interpolatie voor de grafieken
  • Loading branch information
dashorst committed Mar 20, 2012
2 parents 14b079b + f8e92a5 commit 2afe924
Show file tree
Hide file tree
Showing 14 changed files with 308 additions and 55 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@
<artifactId>svnkit</artifactId> <artifactId>svnkit</artifactId>
<version>1.3.5</version> <version>1.3.5</version>
</dependency> </dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math</artifactId>
<version>2.2</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<resources> <resources>
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,10 @@
package nl.topicus.onderwijs.dashboard.datasources;

import java.util.Date;

import nl.topicus.onderwijs.dashboard.modules.DataSource;
import nl.topicus.onderwijs.dashboard.modules.DataSourceSettings;

@DataSourceSettings(label = "Last servercheck", htmlClass = "date", type = Date.class)
public interface LastServerCheckTime extends DataSource<Date> {
}
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ public Object invoke(Object proxy, Method method, Object[] args)
.milliseconds(Math.round(Math.random() * 100000000)); .milliseconds(Math.round(Math.random() * 100000000));
else if (settings.type().equals(String.class)) else if (settings.type().equals(String.class))
value = "random"; value = "random";
else if (settings.type().equals(WeatherReport.class)) { else if (settings.type().equals(Date.class)) {
value = new Date();
} else if (settings.type().equals(WeatherReport.class)) {
value = createRandomWeather(); value = createRandomWeather();
} else if (settings.type().equals(Dot.class) } else if (settings.type().equals(Dot.class)
&& settings.list()) { && settings.list()) {
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@


import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.Iterator;


import nl.topicus.onderwijs.dashboard.keys.Key; import nl.topicus.onderwijs.dashboard.keys.Key;
import nl.topicus.onderwijs.dashboard.modules.DashboardRepository;
import nl.topicus.onderwijs.dashboard.modules.DataSource; import nl.topicus.onderwijs.dashboard.modules.DataSource;
import nl.topicus.wqplot.data.AbstractSeries; import nl.topicus.wqplot.data.AbstractSeries;


Expand All @@ -14,18 +12,14 @@ public class DataSourcePlotSeries<T extends Number, D extends DataSource<T>>
Serializable { Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private Key key; private Key key;
private Class<D> dataSource;
private T minValue; private T minValue;
private T maxValue; private T maxValue;


public DataSourcePlotSeries(Key key, Class<D> dataSource) { public DataSourcePlotSeries(Key key) {
this.key = key; this.key = key;
this.dataSource = dataSource;
} }


public void addEntry(DashboardRepository repository) { public void addEntry(Date time, T value) {
D source = repository.getData(dataSource).get(key);
T value = source == null ? null : source.getValue();
if (value != null) { if (value != null) {
if (minValue == null if (minValue == null
|| minValue.doubleValue() > value.doubleValue()) || minValue.doubleValue() > value.doubleValue())
Expand All @@ -34,7 +28,7 @@ public void addEntry(DashboardRepository repository) {
|| maxValue.doubleValue() < value.doubleValue()) || maxValue.doubleValue() < value.doubleValue())
maxValue = value; maxValue = value;
} }
addEntry(new DataSourcePlotSeriesEntry<T>(new Date(), value)); addEntry(new DataSourcePlotSeriesEntry<T>(time, value));
} }


public Key getKey() { public Key getKey() {
Expand All @@ -49,19 +43,9 @@ public T getMaxValue() {
return maxValue; return maxValue;
} }


/** public void clear() {
* Removes any data with date older than ttlDate. minValue = null;
* maxValue = null;
* @param ttlDate getData().clear();
*/
public void cleanupEntries(Date ttlDate) {
Iterator<DataSourcePlotSeriesEntry<T>> iter = getData().iterator();
while (iter.hasNext()) {
DataSourcePlotSeriesEntry<T> entry = iter.next();
if (entry.getKey().before(ttlDate))
iter.remove();
else
return; //stop if date is after ttlDate, the series is ordered chronologically.
}
} }
} }
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,78 @@
package nl.topicus.onderwijs.dashboard.modules.plots;

import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import nl.topicus.onderwijs.dashboard.datasources.LastServerCheckTime;
import nl.topicus.onderwijs.dashboard.keys.Key;
import nl.topicus.onderwijs.dashboard.modules.DashboardRepository;
import nl.topicus.onderwijs.dashboard.modules.DataSource;

public class DataSourceSeries<T extends Number, D extends DataSource<T>>
implements Serializable {
private static final long serialVersionUID = 1L;
private Key key;
private Class<D> dataSource;
private LinkedList<DataSourceSeriesEntry<T>> data = new LinkedList<DataSourceSeriesEntry<T>>();

public DataSourceSeries(Key key, Class<D> dataSource) {
this.key = key;
this.dataSource = dataSource;
}

public Key getKey() {
return key;
}

public Class<D> getDataSource() {
return dataSource;
}

public List<DataSourceSeriesEntry<T>> getData() {
return Collections.unmodifiableList(data);
}

public DataSourceSeriesEntry<T> getFirstEntry() {
return data.getFirst();
}

public DataSourceSeriesEntry<T> getLastEntry() {
return data.isEmpty() ? null : data.getLast();
}

public void addEntry(DashboardRepository repository) {
LastServerCheckTime time = repository
.getData(LastServerCheckTime.class).get(key);
Date timeValue = time == null ? null : time.getValue();
if (timeValue == null)
return;

D source = repository.getData(dataSource).get(key);
T value = source == null ? null : source.getValue();

if ((data.isEmpty() || data.getLast().getKey().before(timeValue))
&& value != null)
data.add(new DataSourceSeriesEntry<T>(timeValue, value));
}

/**
* Removes any data with date older than ttlDate.
*
* @param ttlDate
*/
public void cleanupEntries(Date ttlDate) {
Iterator<DataSourceSeriesEntry<T>> iter = data.iterator();
while (iter.hasNext()) {
DataSourceSeriesEntry<T> entry = iter.next();
if (entry.getKey().before(ttlDate))
iter.remove();
else
return; // stop if date is after ttlDate, the series is ordered
// chronologically.
}
}
}
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,33 @@
package nl.topicus.onderwijs.dashboard.modules.plots;

import java.io.Serializable;
import java.util.Date;

public class DataSourceSeriesEntry<T extends Number> implements Serializable {
private static final long serialVersionUID = 1L;

private Date key;

private T value;

public DataSourceSeriesEntry(Date key, T value) {
this.key = key;
this.value = value;
}

public Date getKey() {
return key;
}

public void setKey(Date key) {
this.key = key;
}

public T getValue() {
return value;
}

public void setValue(T value) {
this.value = value;
}
}
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
Expand All @@ -19,16 +20,23 @@
import nl.topicus.onderwijs.dashboard.modules.ServiceConfiguration; import nl.topicus.onderwijs.dashboard.modules.ServiceConfiguration;
import nl.topicus.onderwijs.dashboard.web.WicketApplication; import nl.topicus.onderwijs.dashboard.web.WicketApplication;


import org.apache.commons.math.ArgumentOutsideDomainException;
import org.apache.commons.math.MathException;
import org.apache.commons.math.analysis.interpolation.LoessInterpolator;
import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;


@Service @Service
@ServiceConfiguration(interval = 1, unit = TimeUnit.MINUTES, runInRandomMode = true) @ServiceConfiguration(interval = 1, unit = TimeUnit.MINUTES, runInRandomMode = true)
public class PlotService extends AbstractService { public class PlotService extends AbstractService {
private Map<PlotKey, DataSourceSeries<?, ?>> data = new HashMap<PlotKey, DataSourceSeries<?, ?>>();
private Map<PlotKey, DataSourcePlotSeries<?, ?>> series = new HashMap<PlotKey, DataSourcePlotSeries<?, ?>>(); private Map<PlotKey, DataSourcePlotSeries<?, ?>> series = new HashMap<PlotKey, DataSourcePlotSeries<?, ?>>();


private WicketApplication application; private WicketApplication application;


private LoessInterpolator loessInterpolator;

@Autowired @Autowired
public PlotService(ISettings settings) { public PlotService(ISettings settings) {
super(settings); super(settings);
Expand All @@ -41,6 +49,7 @@ public void setApplication(WicketApplication application) {


@Override @Override
public void onConfigure(DashboardRepository repository) { public void onConfigure(DashboardRepository repository) {
loessInterpolator = new LoessInterpolator();
for (Project curProject : repository.getKeys(Project.class)) { for (Project curProject : repository.getKeys(Project.class)) {
if (repository.getData(AverageRequestTime.class).containsKey( if (repository.getData(AverageRequestTime.class).containsKey(
curProject)) curProject))
Expand All @@ -55,39 +64,121 @@ public void onConfigure(DashboardRepository repository) {


private <T extends Number, D extends DataSource<T>> void addSeries( private <T extends Number, D extends DataSource<T>> void addSeries(
Project project, Class<D> dataSource) { Project project, Class<D> dataSource) {
series.put(new PlotKey(project, dataSource), PlotKey key = new PlotKey(project, dataSource);
new DataSourcePlotSeries<T, D>(project, dataSource)); data.put(key, new DataSourceSeries<T, D>(project, dataSource));
series.put(key, new DataSourcePlotSeries<T, D>(project));
}

@SuppressWarnings("unchecked")
public <T extends Number, D extends DataSource<T>> List<DataSourcePlotSeries<T, D>> getSeries(
Class<D> dataSource) {
List<DataSourcePlotSeries<T, D>> ret = new ArrayList<DataSourcePlotSeries<T, D>>();
for (Project curProject : application.getRepository().getKeys(
Project.class)) {
ret.add((DataSourcePlotSeries<T, D>) series.get(new PlotKey(
curProject, dataSource)));
}
return ret;
} }


@Override @Override
public void refreshData() { public void refreshData() {
cleanupDataEntries();

updateDataEntries();

updateAllPlotSeries();
}

private void cleanupDataEntries() {
Map<Key, Map<String, ?>> serviceSettings = getSettings() Map<Key, Map<String, ?>> serviceSettings = getSettings()
.getServiceSettings(PlotService.class); .getServiceSettings(PlotService.class);

for (DataSourceSeries<?, ?> curData : data.values()) {
for (DataSourcePlotSeries<?, ?> curSeries : series.values()) { if (serviceSettings.containsKey(curData.getKey())
if (serviceSettings.containsKey(curSeries.getKey()) && serviceSettings.get(curData.getKey()).containsKey(
&& serviceSettings.get(curSeries.getKey()).containsKey(
"timeToLive")) { "timeToLive")) {
int dataTTL = Integer.parseInt(serviceSettings int dataTTL = Integer.parseInt(serviceSettings
.get(curSeries.getKey()).get("timeToLive").toString()); .get(curData.getKey()).get("timeToLive").toString());
Calendar ttlDate = Calendar.getInstance(); Calendar ttlDate = Calendar.getInstance();
ttlDate.add(Calendar.SECOND, 0 - dataTTL); ttlDate.add(Calendar.SECOND, 0 - dataTTL);

curData.cleanupEntries(ttlDate.getTime());
curSeries.cleanupEntries(ttlDate.getTime());
} }
curSeries.addEntry(application.getRepository());
} }
} }


@SuppressWarnings("unchecked") private void updateDataEntries() {
public <T extends Number, D extends DataSource<T>> List<DataSourcePlotSeries<T, D>> getSeries( for (DataSourceSeries<?, ?> curData : data.values()) {
Class<D> dataSource) { curData.addEntry(application.getRepository());
List<DataSourcePlotSeries<T, D>> ret = new ArrayList<DataSourcePlotSeries<T, D>>();
for (Project curProject : application.getRepository().getKeys(
Project.class)) {
ret.add((DataSourcePlotSeries<T, D>) series.get(new PlotKey(
curProject, dataSource)));
} }
return ret; }

private void updateAllPlotSeries() {
for (DataSourceSeries<?, ?> curData : data.values()) {
DataSourcePlotSeries<Integer, ?> curSeries = (DataSourcePlotSeries<Integer, ?>) series
.get(new PlotKey(curData.getKey(), curData.getDataSource()));
updatePlotSeries(curSeries, curData);
}
}

private void updatePlotSeries(DataSourcePlotSeries<Integer, ?> curSeries,
DataSourceSeries<?, ?> curData) {
if (!updatePlotSeriesWithLoessInterpolatorData(curSeries, curData)) {
updatePlotSeriesWithOriginalData(curSeries, curData);
}
}

private void updatePlotSeriesWithOriginalData(
DataSourcePlotSeries<Integer, ?> curSeries,
DataSourceSeries<?, ?> curData) {
curSeries.clear();
for (DataSourceSeriesEntry<?> entry : curData.getData()) {
curSeries.addEntry(entry.getKey(), (Integer) entry.getValue());
}
}

private boolean updatePlotSeriesWithLoessInterpolatorData(
DataSourcePlotSeries<Integer, ?> curSeries,
DataSourceSeries<?, ?> curData) {
if (curData.getData().size() < 10) {
return false;
}

Date last = curData.getLastEntry().getKey();
double[] xvals = new double[curData.getData().size()];
double[] yvals = new double[curData.getData().size()];
for (int i = 0; i < curData.getData().size(); i++) {
xvals[i] = new Long(curData.getData().get(i).getKey().getTime());
if (curData.getData().get(i).getValue() != null) {
yvals[i] = curData.getData().get(i).getValue().doubleValue();
}
}

PolynomialSplineFunction psf = null;
try {
psf = loessInterpolator.interpolate(xvals, yvals);
} catch (MathException e) {
e.printStackTrace();
return false;
}
if (psf != null) {
curSeries.clear();
Date time = curData.getFirstEntry().getKey();
do {
try {
double v = psf.value(time.getTime());
curSeries.addEntry(time, Double.valueOf(v).intValue());

} catch (ArgumentOutsideDomainException e) {
e.printStackTrace();
return false;
}
Calendar c = Calendar.getInstance();
c.setTime(time);
c.add(Calendar.SECOND, 10);
time = c.getTime();
} while (time.before(last));
return true;
}
return false;
} }
} }
Loading

0 comments on commit 2afe924

Please sign in to comment.