gov.nist.spectrumbrowser.client.SensorDataStream.java Source code

Java tutorial

Introduction

Here is the source code for gov.nist.spectrumbrowser.client.SensorDataStream.java

Source

/*
* Conditions Of Use 
* 
* This software was developed by employees of the National Institute of
* Standards and Technology (NIST), and others. 
* This software has been contributed to the public domain. 
* Pursuant to title 15 Untied States Code Section 105, works of NIST
* employees are not subject to copyright protection in the United States
* and are considered to be in the public domain. 
* As a result, a formal license is not needed to use this software.
* 
* This software is provided "AS IS."  
* NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY.  NIST does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* this software.
*/
package gov.nist.spectrumbrowser.client;

import gov.nist.spectrumbrowser.common.AbstractSpectrumBrowserScreen;
import gov.nist.spectrumbrowser.common.Defines;
import gov.nist.spectrumbrowser.common.SpectrumBrowserCallback;
import gov.nist.spectrumbrowser.common.SpectrumBrowserScreen;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.Context2d.TextAlign;
import com.google.gwt.canvas.dom.client.CssColor;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.googlecode.gwt.charts.client.ChartLoader;
import com.googlecode.gwt.charts.client.ChartPackage;
import com.googlecode.gwt.charts.client.ColumnType;
import com.googlecode.gwt.charts.client.DataTable;
import com.googlecode.gwt.charts.client.DataView;
import com.googlecode.gwt.charts.client.Selection;
import com.googlecode.gwt.charts.client.corechart.ScatterChart;
import com.googlecode.gwt.charts.client.corechart.ScatterChartOptions;
import com.googlecode.gwt.charts.client.event.SelectEvent;
import com.googlecode.gwt.charts.client.event.SelectHandler;
import com.googlecode.gwt.charts.client.options.Gridlines;
import com.googlecode.gwt.charts.client.options.HAxis;
import com.googlecode.gwt.charts.client.options.Legend;
import com.googlecode.gwt.charts.client.options.LegendPosition;
import com.googlecode.gwt.charts.client.options.VAxis;
import com.sksamuel.gwt.websockets.Websocket;
import com.sksamuel.gwt.websockets.WebsocketListenerExt;

public class SensorDataStream implements WebsocketListenerExt, SpectrumBrowserScreen {

    private static final boolean CLOSING = true;
    private static int STATUS_MESSAGE_NOT_SEEN = 1;
    private static int STATUS_MESSAGE_SEEN = 2;
    private static int DATA_MESSAGE_SEEN = 3;
    private boolean closingState = true;
    private String sensorId;
    private Websocket websocket;
    private VerticalPanel verticalPanel;
    private SpectrumBrowser spectrumBrowser;
    private SpectrumBrowserShowDatasets spectrumBrowserShowDatasets;
    private static Logger logger = Logger.getLogger("SpectrumBrowser");
    private JSONValue dataMessage;
    private int state = STATUS_MESSAGE_NOT_SEEN;

    private double minPower = -90.0; // TODO -- make this configurable in admin gui.
    private double maxPower = -20;
    private ColorMap colorMap;
    private Canvas spectrogramCanvas;
    Canvas spectrogramFragment = null;
    int nFrequencyBins = 0;
    double minFreq;
    double maxFreq;
    float cutoff = 0;
    Context2d context2d;
    Canvas frequencyValuesCanvas = null;
    ScatterChart occupancyPlot;
    ScatterChartOptions occupancyPlotOptions;
    DataTable occupancyDataTable;
    DataTable spectrumDataTable;
    ScatterChart spectrumPlot;
    ScatterChartOptions spectrumPlotOptions;
    boolean chartApiLoaded = false;
    long counter = 0;
    private HorizontalPanel occupancyPanel;
    private HorizontalPanel spectrumPanel;
    private TextBox cutoffTextBox;
    private ArrayList<int[]> powerValuesList = new ArrayList<int[]>();
    boolean isFrozen = false;
    HTML html;
    VerticalPanel titlePanel;

    private static final String END_LABEL = "Sensor Data Stream";

    private static final double spectralColors[] = { 0.0, 0.0, 0.0, 0.470205263158, 0.0, 0.536810526316,
            0.477163157895, 0.0, 0.607021052632, 0.0, 0.0, 0.698278947368, 0.0, 0.0982526315789, 0.8667, 0.0,
            0.501778947368, 0.8667, 0.0, 0.621063157895, 0.803542105263, 0.0, 0.6667, 0.617552631579, 0.0,
            0.638615789474, 0.308752631579, 0.0, 0.663142105263, 0.0, 0.0, 0.803510526316, 0.0, 0.0, 0.943873684211,
            0.0, 0.463136842105, 1.0, 0.0, 0.870142105263, 0.954363157895, 0.0, 0.982447368421, 0.835078947368, 0.0,
            1.0, 0.642105263158, 0.0, 1.0, 0.0947368421053, 0.0, 0.880731578947, 0.0, 0.0, 0.803510526316, 0.0, 0.0,
            0.8, 0.8, 0.8 };

    private static final double hotColors[] = { 0.0416, 0.0, 0.0, 0.179767643888, 0.0, 0.0, 0.317935287777, 0.0,
            0.0, 0.456102931665, 0.0, 0.0, 0.594270575554, 0.0, 0.0, 0.732438219442, 0.0, 0.0, 0.870605863331, 0.0,
            0.0, 1.0, 0.00877287390197, 0.0, 1.0, 0.146930544133, 0.0, 1.0, 0.285088214363, 0.0, 1.0,
            0.423245884594, 0.0, 1.0, 0.561403554824, 0.0, 1.0, 0.699561225055, 0.0, 1.0, 0.837718895286, 0.0, 1.0,
            0.975876565516, 0.0, 1.0, 1.0, 0.171051802631, 1.0, 1.0, 0.378288851973, 1.0, 1.0, 0.585525901315, 1.0,
            1.0, 0.792762950658, 1.0, 1.0, 1.0 };

    double[] rainbow = { 0.5, 0.0, 1.0, 0.394736842105, 0.164594590281, 0.996584493007, 0.289473684211,
            0.324699469205, 0.986361303403, 0.184210526316, 0.475947393037, 0.969400265939, 0.0789473684211,
            0.61421271269, 0.945817241701, 0.0263157894737, 0.735723910673, 0.915773326655, 0.131578947368,
            0.837166478263, 0.879473751206, 0.236842105263, 0.915773326655, 0.837166478263, 0.342105263158,
            0.969400265939, 0.789140509396, 0.447368421053, 0.996584493007, 0.735723910673, 0.552631578947,
            0.996584493007, 0.677281571626, 0.657894736842, 0.969400265939, 0.61421271269, 0.763157894737,
            0.915773326655, 0.546948158122, 0.868421052632, 0.837166478263, 0.475947393037, 0.973684210526,
            0.735723910673, 0.401695424653, 1.0, 0.61421271269, 0.324699469205, 1.0, 0.475947393037, 0.245485487141,
            1.0, 0.324699469205, 0.164594590281, 1.0, 0.164594590281, 0.0825793454723, 1.0, 1.22464679915e-16,
            6.12323399574e-17 };

    double[] monochrome = { 0, 0.5, 0, 0, 0.525, 0, 0, 0.55, 0, 0, 0.575, 0, 0, 0.6, 0, 0, 0.625, 0, 0, 0.65, 0, 0,
            0.675, 0, 0, 0.7, 0, 0, 0.725, 0, 0, 0.75, 0, 0, 0.775, 0, 0, 0.8, 0, 0, 0.825, 0, 0, 0.85, 0, 0, 0.875,
            0, 0, 0.9, 0, 0, 0.925, 0, 0, 0.95, 0, 0, 0.975, 0, 0, 1, 0 };
    private float timeResolution;
    private Button freezeButton;
    private Button lastCaptureButton;
    private String sys2detect;
    private long minFreqHz;
    private long maxFreqHz;

    private class ColorStop {
        private double stopValue;
        private CssColor cssColor;

        ColorStop(double stopValue, CssColor cssColor) {
            this.stopValue = stopValue;
            this.cssColor = cssColor;
        }
    }

    private class ColorMap {

        LinkedList<ColorStop> colorList = new LinkedList<ColorStop>();

        double[] myColors = spectralColors;

        ColorMap(int max, int min) {
            int len = myColors.length / 3;
            for (int i = 0; i < len; i++) {
                double stopPosition = min + (double) (max - min) / (double) len * i;
                int red = (int) (255 * myColors[3 * i]);
                int green = (int) (255 * myColors[3 * i + 1]);
                int blue = (int) (255 * myColors[3 * i + 2]);
                addColorStop(stopPosition, CssColor.make(red, green, blue));
            }
        }

        private void addColorStop(double stop, CssColor cssColor) {
            logger.finer("addColorStop " + stop + " color " + cssColor.value());
            ColorStop cstop = new ColorStop(stop, cssColor);
            colorList.add(cstop);
        }

        private CssColor getColor(int value) {
            // Under cutoff gets grey color
            if (value < cutoff) {
                //return CssColor.make("#A9A9A9");
                return CssColor.make("#333300");
            }
            for (ColorStop cs : colorList) {
                if (cs.stopValue > value) {
                    return cs.cssColor;
                }
            }

            // Above the max value.

            return CssColor.make(255, 255, 255);
        }

        List<ColorStop> getColorStops() {
            return colorList;
        }

        int getColorStopCount() {
            return colorList.size();
        }
    }

    native String btoa(String b64) /*-{
                                   return btoa(b64);
                                   }-*/;

    native String atob(String b64) /*-{
                                   return atob(b64);
                                   }-*/;

    private void drawMenuItems() {
        MenuBar menuBar = new MenuBar();
        SafeHtmlBuilder safeHtml = new SafeHtmlBuilder();

        menuBar.addItem(new SafeHtmlBuilder().appendEscaped(SpectrumBrowserShowDatasets.END_LABEL).toSafeHtml(),
                new Scheduler.ScheduledCommand() {

                    @Override
                    public void execute() {
                        state = STATUS_MESSAGE_NOT_SEEN;
                        closingState = true;
                        websocket.close();
                        spectrumBrowserShowDatasets.draw();
                    }
                });
        if (spectrumBrowser.isUserLoggedIn()) {
            menuBar.addItem(safeHtml.appendEscaped(SpectrumBrowser.LOGOFF_LABEL).toSafeHtml(),
                    new Scheduler.ScheduledCommand() {

                        @Override
                        public void execute() {
                            state = STATUS_MESSAGE_NOT_SEEN;
                            closingState = true;
                            websocket.close();
                            spectrumBrowser.logoff();

                        }
                    });
        }

        verticalPanel.add(menuBar);

        titlePanel = new VerticalPanel();

        verticalPanel.add(titlePanel);

        HorizontalPanel cutoffHorizontalPanel = new HorizontalPanel();

        Label cutoffLabel = new Label("Threshold (dBm):");

        cutoffHorizontalPanel.add(cutoffLabel);

        cutoffTextBox = new TextBox();

        cutoffTextBox.setText(Integer.toString((int) cutoff));

        cutoffHorizontalPanel.add(cutoffTextBox);

        Button cutoffButton = new Button("Change");

        cutoffHorizontalPanel.add(cutoffButton);

        cutoffButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                String cutoffString = cutoffTextBox.getValue();
                try {
                    cutoff = Integer.parseInt(cutoffString);
                } catch (NumberFormatException nfe) {
                    Window.alert("Please enter an integer");
                    if (cutoff < 0)
                        cutoffTextBox.setText(Integer.toString((int) (cutoff - 0.5)));
                    else
                        cutoffTextBox.setText(Integer.toString((int) (cutoff + 0.5)));
                }

            }
        });

        freezeButton = new Button("Freeze");

        freezeButton.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {

                isFrozen = !isFrozen;
                if (isFrozen) {
                    freezeButton.setText("Unfreeze");
                } else {
                    freezeButton.setText("Freeze");
                }
            }
        });
        cutoffHorizontalPanel.add(freezeButton);

        lastCaptureButton = new Button("Show Last Acquistion");

        cutoffHorizontalPanel.add(lastCaptureButton);

        lastCaptureButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                websocket.close();
                spectrumBrowser.getSpectrumBrowserService().getLastAcquisitionTime(sensorId,
                        new SpectrumBrowserCallback<String>() {

                            @Override
                            public void onSuccess(String result) {
                                JSONValue jsonValue = JSONParser.parseLenient(result);
                                final long selectionTime = (long) jsonValue.isObject().get("aquisitionTimeStamp")
                                        .isNumber().doubleValue();
                                if (selectionTime != -1) {
                                    chartApiLoaded = false;
                                    occupancyDataTable = null;
                                    websocket.close();
                                    state = STATUS_MESSAGE_NOT_SEEN;
                                    isFrozen = false;
                                    Timer timer = new Timer() {
                                        @Override
                                        public void run() {

                                            ArrayList<SpectrumBrowserScreen> navigation = new ArrayList<SpectrumBrowserScreen>();
                                            navigation.add(spectrumBrowserShowDatasets);
                                            navigation.add(SensorDataStream.this);
                                            new FftPowerOneAcquisitionSpectrogramChart(sensorId, selectionTime,
                                                    sys2detect, minFreqHz, maxFreqHz, verticalPanel,
                                                    spectrumBrowser, navigation);
                                        }
                                    };
                                    // Wait for websocket to close.
                                    timer.schedule(500);
                                } else {
                                    Window.alert("No Capture Found");
                                }
                            }

                            @Override
                            public void onFailure(Throwable throwable) {
                                logger.log(Level.SEVERE, "Problem contacting web server.");
                                Window.alert("Problem contacting web server");
                            }
                        });
            }
        });

        verticalPanel.add(cutoffHorizontalPanel);

    }

    private float round(double val) {
        return (float) ((int) ((val + .05) * 10) / 10.0);
    }

    private float round3(double val) {
        return (float) ((int) ((val + .0005) * 1000) / 1000.0);

    }

    public SensorDataStream(String id, String sys2detect, long minFreq, long maxFreq,
            final VerticalPanel verticalPanel, SpectrumBrowser spectrumBrowser,
            SpectrumBrowserShowDatasets spectrumBrowserShowDatasets) {
        try {
            this.sensorId = id;
            this.sys2detect = sys2detect;
            this.minFreqHz = minFreq;
            this.maxFreqHz = maxFreq;
            this.verticalPanel = verticalPanel;
            this.spectrumBrowser = spectrumBrowser;
            this.spectrumBrowserShowDatasets = spectrumBrowserShowDatasets;

        } catch (Throwable th) {
            logger.log(Level.SEVERE, "ERROR setting up streaming", th);

        }

    }

    @Override
    public void onClose() {
        logger.fine("websocket.onClose");
        websocket.close();
    }

    @Override
    public void onMessage(String msg) {
        // TODO : Make this configurable.
        int nSpectrums = 200; // # of spectrums to show in the spectrogram window.
        double yScale = 0;
        try {
            if (state == STATUS_MESSAGE_NOT_SEEN) {
                JSONValue statusMessage = JSONParser.parseLenient(msg);
                JSONObject jsonObj = statusMessage.isObject();
                if (jsonObj.get("status").isString().stringValue().equals("NO_DATA")) {

                    Window.alert("NO Data Available");
                    websocket.close();
                    spectrumBrowserShowDatasets.draw();
                } else if (jsonObj.get("status").isString().stringValue().equals("OK")) {
                    state = STATUS_MESSAGE_SEEN;
                }
            } else if (state == STATUS_MESSAGE_SEEN) {

                dataMessage = JSONParser.parseLenient(msg);
                logger.finer("msg = " + msg);
                JSONObject mpar = dataMessage.isObject().get("mPar").isObject();
                nFrequencyBins = (int) mpar.get("n").isNumber().doubleValue();
                // The default cutoff value (add 2 to the noise floor).
                cutoff = round(dataMessage.isObject().get("cutoff").isNumber().doubleValue());

                if (cutoff < 0)
                    cutoffTextBox.setText(Integer.toString((int) (cutoff - 0.5)));
                else
                    cutoffTextBox.setText(Integer.toString((int) (cutoff + 0.5)));

                logger.finer("n = " + nFrequencyBins);
                minFreqHz = (long) mpar.get("fStart").isNumber().doubleValue();
                maxFreqHz = (long) mpar.get("fStop").isNumber().doubleValue();
                minFreq = (mpar.get("fStart").isNumber().doubleValue() / 1E6);
                maxFreq = mpar.get("fStop").isNumber().doubleValue() / 1E6;
                sys2detect = dataMessage.isObject().get("Sys2Detect").isString().stringValue();

                // For computing the occupancy, determine the cutoff.

                logger.finer("fStart / fStop = " + Double.toString(minFreq) + " " + Double.toString(maxFreq));
                Context2d ctx = frequencyValuesCanvas.getContext2d();
                ctx.setTextAlign(TextAlign.LEFT);
                ctx.fillText(Double.toString(maxFreq), 0, 10, 100);
                ctx.fillText("Freq (MHz)", 0, SpectrumBrowser.SPEC_HEIGHT / 2 - 4, 100);
                ctx.fillText(Double.toString(minFreq), 0, SpectrumBrowser.SPEC_HEIGHT - 4, 100);
                spectrogramFragment = Canvas.createIfSupported();
                spectrogramFragment.setWidth(SpectrumBrowser.SPEC_WIDTH + "px");
                spectrogramFragment.setHeight(SpectrumBrowser.SPEC_HEIGHT + "px");
                spectrogramFragment.setCoordinateSpaceWidth(SpectrumBrowser.SPEC_WIDTH);
                spectrogramFragment.setCoordinateSpaceHeight(SpectrumBrowser.SPEC_HEIGHT);
                spectrogramFragment.getCanvasElement().setWidth(SpectrumBrowser.SPEC_WIDTH);
                spectrogramFragment.getCanvasElement().setHeight(SpectrumBrowser.SPEC_HEIGHT);
                state = DATA_MESSAGE_SEEN;
                context2d.setFillStyle(CssColor.make("black"));
                context2d.fillRect(0, 0, SpectrumBrowser.SPEC_WIDTH, SpectrumBrowser.SPEC_HEIGHT);
                spectrogramFragment.setVisible(false);
                double timePerMeasurement = (float) mpar.get("tm").isNumber().doubleValue();
                timeResolution = (float) (dataMessage.isObject().get("_spectrumsPerFrame").isNumber().doubleValue()
                        * timePerMeasurement);
                HTML html = new HTML("<h2>Sensor Data Stream for " + sensorId + "</h2>");
                titlePanel.add(html);
                HTML help = new HTML("<p>Click on spectrogram to freeze/unfreze. "
                        + "Click on occupancy point to show spectrum</p>");
                titlePanel.add(help);
                String filter = dataMessage.isObject().get(Defines.STREAMING_FILTER).isString().stringValue();
                float freqResolution = round((float) (maxFreq - minFreq) / nFrequencyBins * 1000);
                html = new HTML("<h3>Resolution Bandwidth = " + freqResolution + " kHz.; Detected System = "
                        + sys2detect + "; Time resoultion = " + AbstractSpectrumBrowserScreen.round2(timeResolution)
                        + " s. Aggregation Filter = " + filter + " </h3>");
                titlePanel.add(html);
            } else if (state == DATA_MESSAGE_SEEN) {
                String[] values = msg.split(",");
                int powerValues[] = new int[values.length];

                int occupancyCount = 0;
                for (int i = 0; i < values.length; i++) {
                    powerValues[i] = Integer.parseInt(values[i].trim());
                    if (powerValues[i] > cutoff) {
                        occupancyCount++;
                    }
                }

                float occupancy = round(((double) occupancyCount / (double) values.length) * 100);
                double xScale = ((double) SpectrumBrowser.SPEC_WIDTH / (double) nSpectrums);

                if (chartApiLoaded && occupancyDataTable == null) {
                    occupancyDataTable = DataTable.create();
                    spectrumDataTable = DataTable.create();
                    occupancyPlotOptions = ScatterChartOptions.create();
                    occupancyPlotOptions.setBackgroundColor("#f0f0f0");
                    occupancyPlotOptions.setPointSize(5);
                    occupancyPlotOptions.setHAxis(HAxis.create("Time (sec)"));
                    VAxis vaxis = VAxis.create("Occupancy %");
                    vaxis.setMaxValue(100.0);
                    vaxis.setMinValue(0);
                    occupancyPlotOptions.setVAxis(vaxis);
                    Legend legend = Legend.create();
                    legend.setPosition(LegendPosition.NONE);
                    occupancyPlotOptions.setLegend(legend);
                    spectrumPlotOptions = ScatterChartOptions.create();
                    spectrumPlotOptions.setBackgroundColor("#f0f0f0");
                    spectrumPlotOptions.setPointSize(5);
                    spectrumPlotOptions.setHAxis(HAxis.create("Frequency (MHz)"));
                    spectrumPlotOptions.setVAxis(VAxis.create("Power (dBm)"));

                    legend = Legend.create();
                    legend.setPosition(LegendPosition.NONE);
                    spectrumPlotOptions.setLegend(legend);
                    occupancyPlot = new ScatterChart();

                    spectrumPlot = new ScatterChart();
                    occupancyPlot.addSelectHandler(new SelectHandler() {

                        @Override
                        public void onSelect(SelectEvent event) {

                            if (!isFrozen) {
                                logger.finer("Please Freeze canvas before clicking");
                                return;
                            } else {
                                double minPower = 10000;
                                double maxPower = -10000;
                                for (int i = 0; i < powerValuesList.size(); i++) {
                                    int[] data = powerValuesList.get(i);
                                    for (int j = 0; j < data.length; j++) {
                                        if (data[j] < minPower) {
                                            minPower = data[j];
                                        }
                                        if (data[j] > maxPower) {
                                            maxPower = data[j];

                                        }
                                    }
                                }
                                JsArray<Selection> selection = occupancyPlot.getSelection();

                                int row = selection.get(0).getRow();
                                logger.finer("Selected row" + row);
                                int[] spectrumData = powerValuesList.get(row);
                                double mhzPerDivision = (maxFreq - minFreq) / spectrumData.length;
                                for (int i = 0; i < spectrumData.length; i++) {
                                    double freq = minFreq + mhzPerDivision * i;
                                    spectrumDataTable.setCell(i, 0, freq, freq + " Mhz");
                                    spectrumDataTable.setCell(i, 1, spectrumData[i], spectrumData[i] + " dBm");
                                }

                                HAxis haxis = HAxis.create("Freq. MHz.");
                                haxis.setMinValue(minFreq);
                                haxis.setMaxValue(maxFreq);

                                VAxis vaxis = VAxis.create("Power (dBm)");
                                vaxis.setMinValue(minPower);
                                vaxis.setMaxValue(maxPower);

                                spectrumPlotOptions.setVAxis(vaxis);
                                spectrumPlotOptions.setHAxis(haxis);

                                spectrumPlot.draw(spectrumDataTable, spectrumPlotOptions);
                            }

                        }
                    });

                    occupancyPlot.setPixelSize(SpectrumBrowser.SPEC_WIDTH + 260, SpectrumBrowser.SPEC_HEIGHT);
                    occupancyPlot.setTitle("Occupancy");
                    spectrumPlot.setPixelSize(SpectrumBrowser.SPEC_WIDTH + 260, SpectrumBrowser.SPEC_HEIGHT);
                    occupancyPanel.add(occupancyPlot);
                    spectrumPanel.add(spectrumPlot);
                    occupancyDataTable.addColumn(ColumnType.NUMBER, "Time (sec)");
                    occupancyDataTable.addColumn(ColumnType.NUMBER, "Occupancy %");
                    spectrumDataTable.addColumn(ColumnType.NUMBER, "Frequency (MHz)");
                    spectrumDataTable.addColumn(ColumnType.NUMBER, "Power (milliwatts)");
                    spectrumDataTable.setColumnLabel(0, "Frequency (MHz)");
                    spectrumDataTable.setColumnLabel(1, "Power (mw)");
                    occupancyDataTable.addRows(nSpectrums);
                    spectrumDataTable.addRows(powerValues.length);

                    DataView dataView = DataView.create(occupancyDataTable);

                    for (int i = 0; i < nSpectrums; i++) {
                        occupancyDataTable.setCell(i, 0, round3(i * timeResolution),
                                round3(i * timeResolution) + " sec");
                        occupancyDataTable.setCell(i, 1, 0, "0 % occupancy");
                        occupancyPlot.draw(dataView, occupancyPlotOptions);

                    }
                    // Initialize the spectrum list
                    for (int i = 0; i < nSpectrums; i++) {
                        int[] dummyValues = new int[values.length];
                        for (int j = 0; j < dummyValues.length; j++) {
                            dummyValues[j] = 0;
                        }
                        powerValuesList.add(dummyValues);
                    }
                    counter = nSpectrums - 1;
                }

                if (!isFrozen) {

                    if (occupancyDataTable != null) {
                        occupancyDataTable.removeRow(0);
                        occupancyDataTable.addRow();
                        int rowCount = occupancyDataTable.getNumberOfRows();
                        counter++;
                        for (int i = 0; i < nSpectrums; i++) {
                            occupancyDataTable.setCell(i, 0, round3(i * timeResolution),
                                    round3(i * timeResolution) + " sec");
                        }
                        occupancyDataTable.setCell(rowCount - 1, 1, occupancy, occupancy + " % occupancy");
                        occupancyPlot.redraw();
                        powerValuesList.remove(0);
                        powerValuesList.add(powerValues);
                        // occupancyPlot.draw(dataTable);
                    }

                    context2d.save();
                    Context2d tempContext = spectrogramFragment.getContext2d();
                    tempContext.drawImage(spectrogramCanvas.getCanvasElement(), 0, 0,
                            (double) SpectrumBrowser.SPEC_WIDTH, (double) SpectrumBrowser.SPEC_HEIGHT);
                    RootPanel.get().add(spectrogramFragment);

                    // nSpectrums = powerValues.length / nFrequencyBins;
                    yScale = (double) SpectrumBrowser.SPEC_HEIGHT / (double) nFrequencyBins;
                    for (int i = 0; i < powerValues.length; i++) {
                        CssColor color = colorMap.getColor(powerValues[i]);
                        int row = (int) ((i % nFrequencyBins) * yScale);
                        int col = (int) ((i / nFrequencyBins) * xScale);

                        context2d.setFillStyle(color);
                        double x = SpectrumBrowser.SPEC_WIDTH - col - xScale;
                        double y = SpectrumBrowser.SPEC_HEIGHT - row - yScale;
                        double w = xScale;
                        double h = yScale;
                        context2d.fillRect(x, y, w, h);

                    }

                    context2d.translate(-xScale, 0);
                    context2d.drawImage(spectrogramFragment.getCanvasElement(), 0, 0,
                            spectrogramFragment.getCanvasElement().getWidth(),
                            spectrogramFragment.getCanvasElement().getHeight(), 0, 0, SpectrumBrowser.SPEC_WIDTH,
                            SpectrumBrowser.SPEC_HEIGHT);
                    // reset the transformation matrix
                    context2d.setTransform(1, 0, 0, 1, 0, 0);
                    RootPanel.get().remove(spectrogramFragment);
                }
            }
        } catch (Throwable ex) {
            logger.log(Level.SEVERE, "ERROR parsing data ", ex);
        }

    }

    @Override
    public void onOpen() {
        logger.finer("onOpen");
        String sid = SpectrumBrowser.getSessionTokenForSensor(sensorId);
        String token = sid + ":" + sensorId + ":" + sys2detect + ":" + minFreqHz + ":" + maxFreqHz;
        websocket.send(token);
    }

    @Override
    public void onError() {
        logger.info("Web Socket Error");
        websocket.close();
        if (!closingState) {
            try {
                openWebSocket();
            } catch (Throwable th) {
                logger.log(Level.SEVERE, "Could not re-open websocket", th);
                spectrumBrowserShowDatasets.draw();

            }
        }

    }

    @Override
    public void draw() {
        try {
            // TODO Auto-generated method stub
            verticalPanel.clear();
            drawMenuItems();

            HorizontalPanel spectrogramPanel = new HorizontalPanel();

            colorMap = new ColorMap((int) maxPower, (int) minPower);

            verticalPanel.add(spectrogramPanel);

            frequencyValuesCanvas = Canvas.createIfSupported();
            frequencyValuesCanvas.setWidth(100 + "px");
            frequencyValuesCanvas.setHeight(SpectrumBrowser.SPEC_HEIGHT + "px");
            frequencyValuesCanvas.setCoordinateSpaceHeight(SpectrumBrowser.SPEC_HEIGHT);
            frequencyValuesCanvas.setCoordinateSpaceWidth(100);

            spectrogramCanvas = Canvas.createIfSupported();
            spectrogramCanvas.setTitle("Click to freeze/unfreeze");
            spectrogramCanvas.setWidth(SpectrumBrowser.SPEC_WIDTH + "px");
            spectrogramCanvas.setHeight(SpectrumBrowser.SPEC_HEIGHT + "px");
            spectrogramCanvas.setCoordinateSpaceWidth(SpectrumBrowser.SPEC_WIDTH);
            spectrogramCanvas.setCoordinateSpaceHeight(SpectrumBrowser.SPEC_HEIGHT);
            spectrogramCanvas.addClickHandler(new ClickHandler() {

                @Override
                public void onClick(ClickEvent event) {
                    isFrozen = !isFrozen;
                    if (isFrozen) {
                        freezeButton.setText("Unfreeze");
                    } else {
                        freezeButton.setText("Freeze");
                    }
                }
            });
            spectrogramPanel.add(frequencyValuesCanvas);
            spectrogramPanel.add(spectrogramCanvas);
            spectrogramPanel.setBorderWidth(3);
            // Draw the colorbar canvas.
            HorizontalPanel colorbarFrame = new HorizontalPanel();
            colorbarFrame.setBorderWidth(3);
            Canvas colorbarCanvas = Canvas.createIfSupported();
            Canvas colorbarTextCanvas = Canvas.createIfSupported();
            colorbarCanvas.setWidth(30 + "px");
            colorbarCanvas.setCoordinateSpaceHeight(SpectrumBrowser.SPEC_HEIGHT);
            colorbarCanvas.setCoordinateSpaceWidth(30);
            colorbarTextCanvas.setWidth(30 + "px");
            colorbarCanvas.setHeight(SpectrumBrowser.SPEC_HEIGHT + "px");
            colorbarTextCanvas.setCoordinateSpaceHeight(SpectrumBrowser.SPEC_HEIGHT);
            colorbarTextCanvas.setHeight(SpectrumBrowser.SPEC_HEIGHT + "px");
            colorbarTextCanvas.setCoordinateSpaceWidth(30);
            int nStops = colorMap.getColorStopCount();
            colorbarFrame.add(colorbarCanvas);
            colorbarFrame.add(colorbarTextCanvas);
            spectrogramPanel.add(colorbarFrame);
            verticalPanel.add(spectrogramPanel);
            double rectHeight = (double) SpectrumBrowser.SPEC_HEIGHT / (double) nStops;
            int i = 0;
            for (ColorStop colorStop : colorMap.getColorStops()) {
                CssColor color = colorStop.cssColor;
                Context2d context = colorbarCanvas.getContext2d();
                context.setFillStyle(color);
                double y = SpectrumBrowser.SPEC_HEIGHT - (i + 1) * rectHeight;
                context.fillRect(0, y, 30, (int) rectHeight);
                Context2d textContext = colorbarTextCanvas.getContext2d();
                textContext.setTextAlign(TextAlign.LEFT);
                textContext.fillText(Integer.toString((int) colorStop.stopValue), 0, (int) (y + rectHeight / 2));
                i++;
            }

            occupancyPanel = new HorizontalPanel();
            VerticalPanel pad = new VerticalPanel();
            pad.setWidth("25px");
            occupancyPanel.add(pad);
            spectrumPanel = new HorizontalPanel();
            ChartLoader chartLoader = new ChartLoader(ChartPackage.CORECHART);

            chartLoader.loadApi(new Runnable() {
                @Override
                public void run() {
                    chartApiLoaded = true;

                }
            });
            verticalPanel.add(occupancyPanel);
            verticalPanel.add(spectrumPanel);

            context2d = spectrogramCanvas.getContext2d();
            openWebSocket();
        } catch (Throwable th) {
            logger.log(Level.SEVERE, "ERROR drawing screen", th);
        }
    }

    private void openWebSocket() {

        String authority = SpectrumBrowser.getBaseUrlAuthority(sensorId);
        String url;
        logger.finer("openWebSocket: sensorId " + sensorId + " authority " + authority);
        if (authority.startsWith("https")) {
            url = authority.replace("https", "wss") + "/sensordata";
        } else {
            url = authority.replace("http", "ws") + "/sensordata";
        }
        logger.fine("Websocket URL " + url);
        websocket = new Websocket(url);
        websocket.addListener(this);
        if (!websocket.isSupported()) {
            Window.alert("Websockets not supported on this browser");
            spectrumBrowserShowDatasets.draw();
        } else {
            websocket.open();
        }

    }

    @Override
    public String getLabel() {
        return END_LABEL + " >>";
    }

    @Override
    public String getEndLabel() {
        return END_LABEL;
    }

}