{"id":205,"date":"2012-11-02T10:46:54","date_gmt":"2012-11-02T17:46:54","guid":{"rendered":"http:\/\/androidplot.com\/?page_id=205"},"modified":"2016-01-04T10:28:15","modified_gmt":"2016-01-04T18:28:15","slug":"a-dynamic-xy-plot","status":"publish","type":"page","link":"http:\/\/androidplot.com\/docs\/a-dynamic-xy-plot\/","title":{"rendered":"A Dynamic XY Plot"},"content":{"rendered":"

A Dynamic XY Plot<\/h1>\r\n[doc_header]<\/em>\r\n\r\n[last_updated_for version=0.9.6]\r\n

Overview<\/h2>\r\nThis tutorial shows how to create a dynamic XYPlot consisting of two sine wave series with a phase and amplitude that varies\u00a0at a specified frequency. \u00a0Its taken from the\u00a0DemoApp's DynamicXYPlotActivity<\/a>.\r\n\r\n\r\n\r\n
\"device-2014-09-09-211210\"<\/a><\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n \r\n
\r\n
\r\n
\r\n

layout\/dynamicxyplot_example.xml<\/h3>\r\n
\r\n
<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<LinearLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n              xmlns:ap=\"http:\/\/schemas.android.com\/apk\/res-auto\"\r\n              style=\"@style\/sample_activity\">\r\n\r\n    <com.androidplot.xy.XYPlot\r\n        style=\"@style\/simple_xy\"\r\n        android:id=\"@+id\/dynamicXYPlot\"\r\n        android:layout_width=\"fill_parent\"\r\n        android:layout_height=\"fill_parent\"\r\n        androidplot.renderMode=\"use_background_thread\"\r\n        ap:label=\"A Dynamic XY Plot\"\r\n        ap:domainLabel=\"Domain\"\r\n        ap:rangeLabel=\"Range\"\r\n        ap:legendTextSize=\"15sp\"\r\n        ap:legendIconHeight=\"15dp\"\r\n        ap:legendIconWidth=\"15dp\"\r\n        ap:legendHeight=\"25dp\"\r\n        ap:legendAnchorPosition=\"right_bottom\"\/>\r\n\r\n<\/LinearLayout><\/pre>\r\n<\/div>\r\n

DynamicXYPlotActivity.java<\/h3>\r\n
\r\n
package com.androidplot.demos;\r\nimport android.app.Activity;\r\nimport android.graphics.Color;\r\nimport android.graphics.DashPathEffect;\r\nimport android.graphics.Paint;\r\nimport android.os.Bundle;\r\nimport com.androidplot.Plot;\r\nimport com.androidplot.util.PixelUtils;\r\nimport com.androidplot.xy.XYSeries;\r\nimport com.androidplot.xy.*;\r\n\r\nimport java.text.DecimalFormat;\r\nimport java.util.Observable;\r\nimport java.util.Observer;\r\n\r\npublic class DynamicXYPlotActivity extends Activity {\r\n\r\n    \/\/ redraws a plot whenever an update is received:\r\n    private class MyPlotUpdater implements Observer {\r\n        Plot plot;\r\n\r\n        public MyPlotUpdater(Plot plot) {\r\n            this.plot = plot;\r\n        }\r\n\r\n        @Override\r\n        public void update(Observable o, Object arg) {\r\n            plot.redraw();\r\n        }\r\n    }\r\n\r\n    private XYPlot dynamicPlot;\r\n    private MyPlotUpdater plotUpdater;\r\n    SampleDynamicXYDatasource data;\r\n    private Thread myThread;\r\n\r\n    @Override\r\n    public void onCreate(Bundle savedInstanceState) {\r\n\r\n        \/\/ android boilerplate stuff\r\n        super.onCreate(savedInstanceState);\r\n        setContentView(R.layout.dynamicxyplot_example);\r\n\r\n        \/\/ get handles to our View defined in layout.xml:\r\n        dynamicPlot = (XYPlot) findViewById(R.id.dynamicXYPlot);\r\n\r\n        plotUpdater = new MyPlotUpdater(dynamicPlot);\r\n\r\n        \/\/ only display whole numbers in domain labels\r\n        dynamicPlot.getGraphWidget().setDomainValueFormat(new DecimalFormat(\"0\"));\r\n\r\n        \/\/ getInstance and position datasets:\r\n        data = new SampleDynamicXYDatasource();\r\n        SampleDynamicSeries sine1Series = new SampleDynamicSeries(data, 0, \"Sine 1\");\r\n        SampleDynamicSeries sine2Series = new SampleDynamicSeries(data, 1, \"Sine 2\");\r\n\r\n        LineAndPointFormatter formatter1 = new LineAndPointFormatter(\r\n                                Color.rgb(0, 0, 0), null, null, null);\r\n        formatter1.getLinePaint().setStrokeJoin(Paint.Join.ROUND);\r\n        formatter1.getLinePaint().setStrokeWidth(10);\r\n        dynamicPlot.addSeries(sine1Series,\r\n                formatter1);\r\n\r\n        LineAndPointFormatter formatter2 =\r\n                new LineAndPointFormatter(Color.rgb(0, 0, 200), null, null, null);\r\n        formatter2.getLinePaint().setStrokeWidth(10);\r\n        formatter2.getLinePaint().setStrokeJoin(Paint.Join.ROUND);\r\n\r\n        \/\/formatter2.getFillPaint().setAlpha(220);\r\n        dynamicPlot.addSeries(sine2Series, formatter2);\r\n\r\n        \/\/ hook up the plotUpdater to the data model:\r\n        data.addObserver(plotUpdater);\r\n\r\n        \/\/ thin out domain tick labels so they dont overlap each other:\r\n        dynamicPlot.setDomainStepMode(XYStepMode.INCREMENT_BY_VAL);\r\n        dynamicPlot.setDomainStepValue(5);\r\n\r\n        dynamicPlot.setRangeStepMode(XYStepMode.INCREMENT_BY_VAL);\r\n        dynamicPlot.setRangeStepValue(10);\r\n\r\n        dynamicPlot.setRangeValueFormat(new DecimalFormat(\"###.#\"));\r\n\r\n        \/\/ uncomment this line to freeze the range boundaries:\r\n        dynamicPlot.setRangeBoundaries(-100, 100, BoundaryMode.FIXED);\r\n\r\n        \/\/ create a dash effect for domain and range grid lines:\r\n        DashPathEffect dashFx = new DashPathEffect(\r\n                new float[] {PixelUtils.dpToPix(3), PixelUtils.dpToPix(3)}, 0);\r\n        dynamicPlot.getGraphWidget().getDomainGridLinePaint().setPathEffect(dashFx);\r\n        dynamicPlot.getGraphWidget().getRangeGridLinePaint().setPathEffect(dashFx);\r\n    }\r\n    @Override\r\n    public void onResume() {\r\n        \/\/ kick off the data generating thread:\r\n        myThread = new Thread(data);\r\n        myThread.start();\r\n        super.onResume();\r\n    }\r\n\r\n    @Override\r\n    public void onPause() {\r\n        data.stopThread();\r\n        super.onPause();\r\n    }\r\n\r\n    class SampleDynamicXYDatasource implements Runnable {\r\n\r\n        \/\/ encapsulates management of the observers watching this datasource for update events:\r\n        class MyObservable extends Observable {\r\n            @Override\r\n            public void notifyObservers() {\r\n                setChanged();\r\n                super.notifyObservers();\r\n            }\r\n        }\r\n\r\n        private static final double FREQUENCY = 5; \/\/ larger is lower frequency\r\n        private static final int MAX_AMP_SEED = 100;\r\n        private static final int MIN_AMP_SEED = 10;\r\n        private static final int AMP_STEP = 1;\r\n        public static final int SINE1 = 0;\r\n        public static final int SINE2 = 1;\r\n        private static final int SAMPLE_SIZE = 30;\r\n        private int phase = 0;\r\n        private int sinAmp = 1;\r\n        private MyObservable notifier;\r\n        private boolean keepRunning = false;\r\n\r\n        {\r\n            notifier = new MyObservable();\r\n        }\r\n\r\n        public void stopThread() {\r\n            keepRunning = false;\r\n        }\r\n\r\n        \/\/@Override\r\n        public void run() {\r\n            try {\r\n                keepRunning = true;\r\n                boolean isRising = true;\r\n                while (keepRunning) {\r\n\r\n                    Thread.sleep(10); \/\/ decrease or remove to speed up the refresh rate.\r\n                    phase++;\r\n                    if (sinAmp >= MAX_AMP_SEED) {\r\n                        isRising = false;\r\n                    } else if (sinAmp <= MIN_AMP_SEED) {\r\n                        isRising = true;\r\n                    }\r\n\r\n                    if (isRising) {\r\n                        sinAmp += AMP_STEP;\r\n                    } else {\r\n                        sinAmp -= AMP_STEP;\r\n                    }\r\n                    notifier.notifyObservers();\r\n                }\r\n            } catch (InterruptedException e) {\r\n                e.printStackTrace();\r\n            }\r\n        }\r\n\r\n        public int getItemCount(int series) {\r\n            return SAMPLE_SIZE;\r\n        }\r\n\r\n        public Number getX(int series, int index) {\r\n            if (index >= SAMPLE_SIZE) {\r\n                throw new IllegalArgumentException();\r\n            }\r\n            return index;\r\n        }\r\n\r\n        public Number getY(int series, int index) {\r\n            if (index >= SAMPLE_SIZE) {\r\n                throw new IllegalArgumentException();\r\n            }\r\n            double angle = (index + (phase))\/FREQUENCY;\r\n            double amp = sinAmp * Math.sin(angle);\r\n            switch (series) {\r\n                case SINE1:\r\n                    return amp;\r\n                case SINE2:\r\n                    return -amp;\r\n                default:\r\n                    throw new IllegalArgumentException();\r\n            }\r\n        }\r\n\r\n        public void addObserver(Observer observer) {\r\n            notifier.addObserver(observer);\r\n        }\r\n\r\n        public void removeObserver(Observer observer) {\r\n            notifier.deleteObserver(observer);\r\n        }\r\n\r\n    }\r\n\r\n    class SampleDynamicSeries implements XYSeries {\r\n        private SampleDynamicXYDatasource datasource;\r\n        private int seriesIndex;\r\n        private String title;\r\n\r\n        public SampleDynamicSeries(SampleDynamicXYDatasource datasource, int seriesIndex, String title) {\r\n            this.datasource = datasource;\r\n            this.seriesIndex = seriesIndex;\r\n            this.title = title;\r\n        }\r\n\r\n        @Override\r\n        public String getTitle() {\r\n            return title;\r\n        }\r\n\r\n        @Override\r\n        public int size() {\r\n            return datasource.getItemCount(seriesIndex);\r\n        }\r\n\r\n        @Override\r\n        public Number getX(int index) {\r\n            return datasource.getX(seriesIndex, index);\r\n        }\r\n\r\n        @Override\r\n        public Number getY(int index) {\r\n            return datasource.getY(seriesIndex, index);\r\n        }\r\n    }\r\n}<\/pre>\r\n<\/div>\r\n<\/div>\r\n<\/div>\r\n<\/div>\r\n

What's Next?<\/h1>\r\nLearn how to plot sensor data in realtime<\/a>.","protected":false},"excerpt":{"rendered":"

A Dynamic XY Plot [doc_header] [last_updated_for version=0.9.6] Overview This tutorial shows how to create a dynamic XYPlot consisting of two sine wave series with a phase and amplitude that varies\u00a0at a specified frequency. \u00a0Its taken from the\u00a0DemoApp’s DynamicXYPlotActivity.   layout\/dynamicxyplot_example.xml <?xml version=”1.0″ encoding=”utf-8″?> <LinearLayout xmlns:android=”http:\/\/schemas.android.com\/apk\/res\/android” xmlns:ap=”http:\/\/schemas.android.com\/apk\/res-auto” style=”@style\/sample_activity”> <com.androidplot.xy.XYPlot style=”@style\/simple_xy” android:id=”@+id\/dynamicXYPlot” android:layout_width=”fill_parent” android:layout_height=”fill_parent” androidplot.renderMode=”use_background_thread” ap:label=”A Dynamic […]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":12,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-205","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/pages\/205","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/comments?post=205"}],"version-history":[{"count":10,"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/pages\/205\/revisions"}],"predecessor-version":[{"id":821,"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/pages\/205\/revisions\/821"}],"up":[{"embeddable":true,"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/pages\/12"}],"wp:attachment":[{"href":"http:\/\/androidplot.com\/wp-json\/wp\/v2\/media?parent=205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}