Script Library: 1213 scripts
 

ez-plot.r

REBOL [ Title: "Easy Quick Plot" Date: 20-Feb-2002 Version: 0.1.1 File: %ez-plot.r Author: "Matt Licholai" Purpose: "Simple tutorial for using the quick plot dialect." History: [0.1.0 [21-Jan-2002 {Documentation for quick-plot (%q-plot.r) initial release (version 0.8)}] [0.1.1 [30-Jan-2002 {Changes to reflect updated plot dialect (version 0.1.1}]] ] Email: %m--s--licholai--ieee--org Requires: %q-plot.r Comments: { Uses easy-vid 1.1.2 by Carl Sassenrath. Modified by Brett Handley to add sliders and then hacked in a very ugly way by me to allow arbitrary REBOL code before 'view in the examples. Provides basic documentation for my quick-plot dialect. } library: [ level: [intermediate] platform: none type: 'tutorial domain: [GUI x-file] tested-under: none support: none license: none see-also: none ] ] CVS-id: {$Id: ez-plot.r,v 1.24 2002/02/19 15:30:18 matt Exp $ } ; load q-plot before starting the tutorial ; use 'require if it is available, if not fall back to using 'do if error? try [require %q-plot.r] [ if error? try [do %q-plot.r] [ throw make error! "You need %q-plot.r in your working directory to run this tutorial" ] ] content: {Easy 'Quick-Plot' -- A REBOL Plotting Dialect ===Introduction to Quick-Plot Quick-Plot (quick-plot) is intended as an easy to use dialect to simplify displaying 2D plots within REBOL/View. Plots can be created from a REBOL block containing data or a function which generates a block of data. The quick-plot dialect returns a face object that can then be used for immediate display, as part of a multi-pane user interface or for further manipulation by REBOL. The quick-plot dialect was written to address a common request of some new programmers learning REBOL. Quick-plot should also be fast and flexible enough that it is beneficial for experienced REBOL users by providing an additional level of abstraction when working with 2 dimensional output. Quick-plot is built on top of the draw and layout dialects of REBOL/View. As such it relies heavily on the well tested and efficient display routines provided by those two dialects. !Note: Quick-plot requires that %q-plot.r be loaded before using the dialect, since quick-plot is not part of the standard REBOL environment. ===Creating Plots Plots are created by calling the quick-plot dialect with a block of plot commands and options. The quick-plot dialect returns a face object containing a single pane that can then be immediately displayed, associated with a word, or further processed with standard REBOL. Here is a rather convoluted sample of what is possible. view quick-plot [ 600x600 title "Quick Plot Dialect" style vh1 x-data [(now/date - 200) (now/date)] pen blue fill-pen 100.100.90 y-min 0 y-max 10 bars [ (b-data: copy [] for i 1 9 1 [ append b-data (i) ] )] label "Bar graph" y-max 1.0 y-min -1.0 line [ (y-data: copy [] for i -200 200 .5 [ append y-data sine i ] )] color yellow label "A sine curve" line-pattern 1 4 4 4 line [ (y-data2: copy [] for i -200 200 .5 [ append y-data2 (- abs i / 200.0) ] )] color green label "A Useless function" pen forest text "Quick-plot makes plotting easy!" up 73 over 20 text "Give it a try ..." up 70 over 20 pen black x-grid 5 y-grid 5 x-axis 5 border y-axis 5 border ] Here is a simple example of a multi-plot. y-data1: copy [] y-data2: copy [] b-data: copy [] for i -200 200 .5 [ append y-data1 (- abs i / 200.0) append y-data2 (sine i) ] for i 1 9 1 [ append b-data (i) ] plots: multi-plot/ratio 350x600 [ [ ; top most plot title "On Top" style vh2 line [(y-data1)] x-grid 5 y-grid 5 x-axis 5 y-axis 5 ] ; top [ ; 2nd down plot fill-pen 100.100.90 y-min 0 bars [(b-data)] title "Bars" x-grid 5 y-grid 5 x-axis 5 y-axis 5 ] ; 2nd [ ; bottom plot title "Biggest" style vh1 line [(y-data2)] x-grid 5 y-grid 5 x-axis 5 y-axis 5 ] ; bottom ] [0.75 1 1.75] ; specify the relative sizes of the plots view plots !Click on the example above to see how it will appear on your screen. Click on the close box to remove it. All of the examples that follow can be viewed this way. ===Simple Examples Here is a minimal plotting example. This is the absolute minimum required to produce output (although it does nothing useful). view quick-plot [ 100x100 ] Here is a slightly more interesting example. It creates a very simple plot consisting of a title and a piecewise curve that resembles a big "W". view quick-plot [ 300x200 title "Quick Plots" line [2 0 1 0 2] ] The line plot type can even be used with a block of data generated by REBOL code embedded within the quick-plot block. view quick-plot [ 400x400 line [ (y-data: copy [] for i -200 200 .5 [ append y-data sine 2 * i ] )] label "Sine curve" title "Easy REBOL Plotting" ] ===Plot Types There are three basic types of plots elements available using the quick-plot dialect. ---Plot elements * line * bar-graph * stock market type (showing open, high, low and close prices for one x-value) !A singe plot pane can contain more than one plot element. The plot element can be modified by any of the effects possible using the draw dialect. ---Element Effects * pen color * line-pattern * fill-pen * arbitrary text Additional options are available to enhance the readability of a plot. Options can be added or modified at anytime when describing a plot. ---Options * title * x-grid line * y-grid lines * x-axis labels * y-axis labels * plot element label * minimum and maximum x values * minimum and maximum y values ---Multi-plots Combining multiple plots into one pane can be accomplished by using the multi-plot function. Please see the appropriate section for details. ===Data Requirements The data required for quick-plot to create panes for display are a pair specifying the size of the plot and a block of y-values. If there is more than one plot element to be plotted on a pane then a block of y-values for each element is required. The minimum and maximum values for the x and y coordinates are derived from the first y-data block provided (unless explicitly given using x-min, x-max and y-min, y-max keywords). Since most data sources generate a series of y-values with implied x-values, quick-plot does not need the x values for a sequence to be plotted. In other words, the y-values are taken to correspond to a regular sequence of x-values. If there is a gap between successive plotted points, a 'none should be inserted in the y-value block at that point to mark a skipped y value. The line plot element will use linear interpolation to join the points on either side of the skipped value. ---Automatic x incrementing As described above there is no need to provide a series of x-values corresponding the the y-value sequence, although it is an option if desired. The correct values for x will be supplied by providing the minimum and maximum x values, quick-plot will automatically generate a correct sequence to match the supplied y-values. The one case where this does not happen is when x represents a series of dates. When x is a date series, the only way to display the dates correctly (they are, however, properly handled internally to produce the plot element), is to explicitly provide them using the x-data option. There is a shortcut available, please see the 'Special Rules for Dates' topic. ---Block values Data for use by quick-plot must be in the form of a block. If using REBOL code embedded in the quick-plot block, it is automatically composed (all code within parenthetical marks is evaluated). The data remaining must be in the form of a block. If using parentheses to substitute for a word, the parenthesis must be enclosed in a surrounding set of brackets, eg. looks like this [(word-holding-data)]. ===Line Line plots are the most basic plot element processed by quick-plot. It is very easy to generate a line element, simply use the keyword 'line followed by a block of y values. There is no need to explicitly provide corresponding x values (see the Data Requirements topic for more details). Here is a simple example using explicit data values. view quick-plot [ 250x250 line [1 2 4 8 16 32 64 128] ] Here is an example of generating the data with an embedded (and anonymous) function. view quick-plot [ 300x300 line [(data: copy [2] loop 10 [append data (2 * last data)]) ] ] ===Bar Graph Bar graphs are produce by using the keyword 'bars followed by a data block. Options for fill-pen to change the color of the interior of the bars, pen to change the color of the bar outline and bar-width to change the width of the bars, must precede the 'bars keyword if they are desired. !Note that unless a y-minimum is specified, the bottom of the bar plot is the smallest y value (not zero). Use "y-min 0" to specify that the floor of the plot should be zero and not the minimum of the y-data. A simple example (using all the defaults) view quick-plot [ 300x300 bars [5 3 8 2 10 3 4 9 5 7] ] Adding options, here is the example again. view quick-plot [ 300x300 fill-pen blue pen red bar-width 15 bars [5 3 8 2 10 3 4 9 5 7] label "Meaningless bars" y-axis 9 ] Here is the same data with a y-min of zero specified and fat overlapping bars. view quick-plot [ 600x300 y-min 0 fill-pen blue pen red bar-width 80 bars [5 3 8 2 10 3 4 9 5 7] label "Fat Meaningless bars" y-axis 11 x-axis 10 ] ===Stock (OHLC) Stock charts can also be easily plotted using quick-plot. A stock plot element attempts to comprehensively show the price movement of an asset during a day's trading by showing the opening, high, low and close prices. This type of plot is also know as an OHLC chart. A stock element contains a left tick to represent the opening price of a stock, a vertical bar representing the prices between the day's high and low and a right tick representing the closing price of the day. !Note that all the examples in this section rely on %get-stock.r to fetch real stock prices from www.yahoo.com. Please ensure get-stock.r is in your working directory before trying these examples. If needed, get-stock.r can be down loaded via the reb or the web from the www.rebol.com script library. do %get-stock.r fl: flash "Downloading IBM stock data" set [dt op hi lo cl vo] get-stock/data "IBM" (now/date - 50) now/date unview/only fl prices: reduce [op hi lo cl] view quick-plot [ 600x600 title "IBM" x-data [(dt)] stock [(prices)] x-axis 5 y-axis 7 x-grid 5 y-grid 7 ] To create a stock element, the keyword stock is used, followed by a block holding four blocks containing the price data. The four data blocks must be in the following order; open, low, high and close. All four blocks should then be wrapped in a singe block before being used by quick-plot. Anyone interested in technical or graphic analysis of a shock can use quick-plot to overlay various studies on the stock data. The next example shows a simple moving average and an exponential moving average (EMA) along with the OHLC data (Also see the Additional Examples section). do %get-stock.r either exists? %IBM.csv [ set [dt op hi lo cl vo] get-stock/data/retrieve "IBM" (now/date - 250) now/date %IBM.csv ][ fl: flash "Downloading IBM stock data" set [dt op hi lo cl vo] get-stock/data/store "IBM" (now/date - 250) now/date %IBM.csv unview/only fl ] prices: reduce [op hi lo cl] ma: copy [] ema: copy [] hold-blk: copy [] ma-length: 10 ;length of the moving average ma-str: rejoin ["Simple Moving Avg (" ma-length " day)"] ema-val: 2 / ( ma-length + 1) ; ema multiplier ; corresponding to a time constant of ma-length ema-carry: 1.0 - ema-val loop (ma-length - 1) [ append ma none ; val: first cl append ema val: first cl ; val append hold-blk val cl: next cl ; cl going to ma-length + 1 ] sum: func [bk [block!]][ total: 0 foreach val bk [ total: total + val ] return total ] until [ ; simple ma calculation append hold-blk today: first cl append ma ((sum hold-blk ) / ma-length) remove hold-blk ; ema calculations append ema (today * ema-val + (ema-carry * last ema)) ; advance one day tail? cl: next cl ] head cl view quick-plot [ 600x600 title "IBM" x-data [(dt)] stock [(prices)] x-axis 5 border y-axis 7 border x-grid 5 y-grid 7 line [(ema)] color yellow label "EMA" line [(ma)] color green label (ma-str) ] ===Stock (Candlestick) Candlestick charting is now included in the quick-plot dialect. Candlestick charts are created in the same way as OHLC stock charts, but the keyword 'candles is used to produce the plot. do %get-stock.r ticker: "IBM" either exists? (t-file: to-file join ticker ".csv") [ set [dt op hi lo cl vo] get-stock/data/retrieve ticker (now/date - 250) now/date t-file ][ fl: flash join join "Downloading " ticker " stock data" set [dt op hi lo cl vo] get-stock/data/store ticker (now/date - 250) now/date t-file unview/only fl ] prices: reduce [op hi lo cl] view quick-plot [ 600x600 scale log title (ticker) x-data [(dt)] candles [(prices)] x-axis 5 y-axis 7 x-grid 5 y-grid 7 ] Changing the color of the up and down candlesticks is easily done by following the 'candles keyword with the 'up or 'down keyword followed by a color or tuple. The order of keywords and data does not matter (e.g., "down pink [(prices)] up gold" would be an acceptable, but rather ugly input). do %get-stock.r ticker: "MSFT" either exists? (t-file: to-file join ticker ".csv") [ set [dt op hi lo cl vo] get-stock/data/retrieve ticker (now/date - 250) now/date t-file ][ fl: flash join join "Downloading " ticker " stock data" set [dt op hi lo cl vo] get-stock/data/store ticker (now/date - 250) now/date t-file unview/only fl ] prices: reduce [op hi lo cl] view quick-plot [ 600x600 scale dynamic 50 title (ticker) style vh1 x-data [(dt)] candles [(prices)] up navy down brick ; candles down pink [(prices)] up gold ; order doesn't matter x-axis 5 border y-axis 7 border x-grid 5 y-grid 7 ] Also note the use of dynamic scale selection, title style and border axis labels in the example above. ===Expanded Stock System Model Here is a more developed stock charting and analysis example. This section uses the %get-stock.r and %condense.r function scripts to develop a REBOL implementation of Dr. Alexander Elder's "Triple Screen System." The "Triple Screen System" is described in Dr Elder's book "Trading for a Living." Since the system can be used for visually analyzing stock opportunities and is relatively straight forward to implement it is presented here. For this demonstration we will construct only the first two parts of the "Triple Screen" and avoid all the issues surrounding day-trading and use of intra-day prices. First we need to create a Moving Average Convergence Divergence (MACD) indicator. For this project we will use 12 and 26 day exponential moving averages, and a 9 day EMA to make the slow signal line. The time constant (K) for computing EMA is K = 2 / (N + 1) where N is the number of days. The values we need are (N, K): (12, 0.153846), (26, 0.074074) and (9, 0.2). Although we will (and should for more precision) use REBOL to compute these constants. The first model is the Weekly MACD Histogram. We need to use the %condense.r package to create weekly market data from the daily data downloaded by get-stock. The Fast MACD line (f-macd) is the 12 day EMA minus the 26 day EMA. The signal line (signal) is the 9 day EMA of f-macd. The MACD Histogram (macd-hist) is the difference between f-macd and the signal line. When the histogram is positive it is supposed to indicate that 'bulls' dominate the market and it is better to trade to the long side (buy). We will use the sign of histogram slope to create a gross buy/sell indicator. On our chart the indicator will be shown as a greater than 0 (buy) or a less than 0 (sell) bar. Here it is... do %get-stock.r do %condense.r ticker: copy "IBM" either exists? (stock-file: to-file join ticker ".csv") [ daily-prices: get-stock/data/retrieve ticker (now/date - 250) now/date stock-file ][ fl: flash join join "Downloading " ticker " stock data" daily-prices: get-stock/data/store ticker (now/date - 250) (now/date) stock-file unview/only fl ] set [dt op hi lo cl vo] aggregate-weeks daily-prices prices: reduce [op hi lo cl] ema12: copy [] ema26: copy [] f-macd: copy [] signal: copy [] macd-hist: copy [] hist-slope: copy [] ema9-length: 9 ;length of the moving average ema9-val: 2 / ( ema9-length + 1) ; ema multiplier (K) ema9-carry: 1.0 - ema9-val ema12-length: 12 ema12-val: 2 / ( ema12-length + 1) ema12-carry: 1.0 - ema12-val ema26-length: 26 ema26-val: 2 / ( ema26-length + 1) ema26-carry: 1.0 - ema26-val append ema12 first cl append ema26 first cl append f-macd 0.0 append signal 0.0 append macd-hist 0.0 append hist-slope 0.0 cl: next cl until [ today: first cl ; calculations append ema12 this-12: (today * ema12-val + (ema12-carry * last ema12)) append ema26 this-26: (today * ema26-val + (ema26-carry * last ema26)) append f-macd this-macd: (this-12 - this-26) append signal this-sig: (this-macd * ema9-val + (ema9-carry * last signal)) prior-hist: last macd-hist append macd-hist this-hist: (this-macd - this-sig) append hist-slope either ((this-hist - prior-hist) < 0) [ -1][1] ; advance one day tail? cl: next cl ] cl: head cl macd-plot: multi-plot/ratio 600x600 [ [ title (rejoin [ticker " Weekly data"]) style vh2 scale dynamic 50 stock [(prices)] ; x-axis 5 y-axis 7 border x-grid 5 y-grid 7 ] [ scale linear title "MACD Histogram" style h3 x-data [(dt)] pen blue bars [(macd-hist)] rescale line [(f-macd)] color yellow label "Fast MACD" line [(signal)] color red label "Signal" pen black y-axis 2 border x-grid 5 y-grid 2 ] [ scale linear title "Buy/Sell Signal" style h3 x-data [(dt)] y-max 1.1 y-min -1.1 pen oldrab bars [(hist-slope)] fill leaf pen black text "BUY" up 85 over 30 text "SELL" up 35 y-axis 3 border x-grid 5 y-grid 2 ] [ pen coal fill-pen 110.110.110 bars [(vo)] x-data [(dt)] rescale y-axis 3 border pen black text "Daily Volume" over 10 up 85 x-axis 5 border x-grid 5] ][4 2 1 2] view macd-plot For the second part of the "Triple Screen" we use daily data to construct a "Force Index" showing the market sentiment. According to Dr. Elder the "Force Index" should be used as a contrarian indicator for timing moves based on the weekly MACD signal. The force index (f-index) is calculated as today's volume * (today's close - yesterday's close). We start out by calculating the weekly MACD as before and then computing the daily f-index. do %get-stock.r do %condense.r ticker: copy "IBM" either exists? (stock-file: to-file join ticker ".csv") [ daily-prices: get-stock/data/retrieve ticker (now/date - 250) now/date stock-file ][ fl: flash join join "Downloading " ticker " stock data" daily-prices: get-stock/data/store ticker (now/date - 250) (now/date) stock-file unview/only fl ] ;; weekly MACD calculations set [dt op hi lo cl vo] aggregate-weeks daily-prices weekly-dt: dt prices: reduce [op hi lo cl] ema12: copy [] ema26: copy [] f-macd: copy [] signal: copy [] macd-hist: copy [] hist-slope: copy [] ema2-length: 2 ema2-val: 2 / ( ema2-length + 1) ema2-carry: 1.0 - ema2-val ema9-length: 9 ema9-val: 2 / ( ema9-length + 1) ema9-carry: 1.0 - ema9-val ema12-length: 12 ema12-val: 2 / ( ema12-length + 1) ema12-carry: 1.0 - ema12-val ema26-length: 26 ema26-val: 2 / ( ema26-length + 1) ema26-carry: 1.0 - ema26-val append ema12 first cl append ema26 first cl append f-macd 0.0 append signal 0.0 append macd-hist 0.0 append hist-slope 0.0 cl: next cl until [ today: first cl ; calculations append ema12 this-12: (today * ema12-val + (ema12-carry * last ema12)) append ema26 this-26: (today * ema26-val + (ema26-carry * last ema26)) append f-macd this-macd: (this-12 - this-26) append signal this-sig: (this-macd * ema9-val + (ema9-carry * last signal)) prior-hist: last macd-hist append macd-hist this-hist: (this-macd - this-sig) append hist-slope either ((this-hist - prior-hist) < 0) [ -1][1] ; advance one day tail? cl: next cl ] cl: head cl ;; reset to daily prices set [dt op hi lo cl vo] daily-prices prices: reduce [op hi lo cl] f-index: copy [] smooth-fi: copy [] today first cl cl: next cl vo: next vo append f-index vo append smooth-fi 0.0 until [ yesterday: today today: first cl volume: first vo ; calculations append f-index this-f: (volume * (today - yesterday)) append smooth-fi (this-f * ema2-val + (ema2-carry * last f-index)) ; advance one day vo: next vo tail? cl: next cl ] cl: head cl vo: head vo force-plot: multi-plot/ratio 600x600 [ [ title (rejoin [ticker " Daily Data"]) style vh2 scale dynamic 50 stock [(prices)] ; x-axis 5 y-axis 7 border x-grid 5 y-grid 7 ] [ scale linear title "Buy/Sell Signal" style h3 x-data [(weekly-dt)] y-max 1.1 y-min -1.1 pen oldrab bars [(hist-slope)] fill leaf pen black text "BUY" up 85 over 30 text "SELL" up 35 y-axis 3 border x-grid 5 y-grid 2 ] [ scale linear x-data [(dt)] pen violet bars [(smooth-fi)] fill crimson pen black text "SELL" up 85 over 30 text "BUY" up 35 text "Force Index Histogram" over 40 up 20 y-axis 2 border x-grid 5 y-grid 2 ] [ pen coal fill-pen 110.110.110 bars [(vo)] x-data [(dt)] rescale y-axis 3 border pen black text "Daily Volume" over 10 up 85 x-axis 5 border x-grid 5] ][3 1 1 1] view force-plot Some aspects of this model worth noting are the multiple time scales, volume information in an indicator, and contraian use of an indicator. Now that a simple starting model has been developed, feel free to incorporate your own trading ideas into a REBOL stock system. Please let me know if you find a system that makes consistent or significant profits (email me at %m--s--licholai--ieee--org). Thank you and good luck. Here are the above charts with a simple GUI to switch between them. Since we only have two parts to this model I call the "Double Screen." do %get-stock.r do %condense.r ticker: copy "IBM" either exists? (stock-file: to-file join ticker ".csv") [ daily-prices: get-stock/data/retrieve ticker (now/date - 250) now/date stock-file ][ fl: flash join join "Downloading " ticker " stock data" daily-prices: get-stock/data/store ticker (now/date - 250) (now/date) stock-file unview/only fl ] ;; weekly MACD calculations set [dt op hi lo cl vo] aggregate-weeks daily-prices weekly-dt: dt prices: reduce [op hi lo cl] ema12: copy [] ema26: copy [] f-macd: copy [] signal: copy [] macd-hist: copy [] hist-slope: copy [] ema2-length: 2 ema2-val: 2 / ( ema2-length + 1) ema2-carry: 1.0 - ema2-val ema9-length: 9 ema9-val: 2 / ( ema9-length + 1) ema9-carry: 1.0 - ema9-val ema12-length: 12 ema12-val: 2 / ( ema12-length + 1) ema12-carry: 1.0 - ema12-val ema26-length: 26 ema26-val: 2 / ( ema26-length + 1) ema26-carry: 1.0 - ema26-val append ema12 first cl append ema26 first cl append f-macd 0.0 append signal 0.0 append macd-hist 0.0 append hist-slope 0.0 cl: next cl until [ today: first cl ; calculations append ema12 this-12: (today * ema12-val + (ema12-carry * last ema12)) append ema26 this-26: (today * ema26-val + (ema26-carry * last ema26)) append f-macd this-macd: (this-12 - this-26) append signal this-sig: (this-macd * ema9-val + (ema9-carry * last signal)) prior-hist: last macd-hist append macd-hist this-hist: (this-macd - this-sig) append hist-slope either ((this-hist - prior-hist) < 0) [ -1][1] ; advance one day tail? cl: next cl ] cl: head cl macd-plot: multi-plot/ratio 500x500 [ [ title (rejoin [ticker " Weekly data"]) style vh2 scale dynamic 50 stock [(prices)] ; x-axis 5 y-axis 7 border x-grid 5 y-grid 7 ] [ scale linear title "MACD Histogram" style h3 x-data [(dt)] pen blue bars [(macd-hist)] rescale line [(f-macd)] color yellow label "Fast MACD" line [(signal)] color red label "Signal" pen black y-axis 2 border x-grid 5 y-grid 2 ] [ scale linear title "Buy/Sell Signal" style h3 x-data [(dt)] y-max 1.1 y-min -1.1 pen oldrab bars [(hist-slope)] fill leaf pen black text "BUY" up 85 over 30 text "SELL" up 35 y-axis 3 border x-grid 5 y-grid 2 ] [ pen coal fill-pen 110.110.110 bars [(vo)] x-data [(dt)] rescale y-axis 3 border pen black text "Daily Volume" over 10 up 85 x-axis 5 border x-grid 5] ][4 2 1 2] ;; reset to daily prices set [dt op hi lo cl vo] daily-prices prices: reduce [op hi lo cl] f-index: copy [] smooth-fi: copy [] today first cl cl: next cl vo: next vo append f-index vo append smooth-fi 0.0 until [ yesterday: today today: first cl volume: first vo ; calculations append f-index this-f: (volume * (today - yesterday)) append smooth-fi (this-f * ema2-val + (ema2-carry * last f-index)) ; advance one day vo: next vo tail? cl: next cl ] cl: head cl vo: head vo force-plot: multi-plot/ratio 500x500 [ [ title (rejoin [ticker " Daily Data"]) style vh2 scale dynamic 50 stock [(prices)] ; x-axis 5 y-axis 7 border x-grid 5 y-grid 7 ] [ scale linear title "Buy/Sell Signal" style h3 x-data [(weekly-dt)] y-max 1.1 y-min -1.1 pen oldrab bars [(hist-slope)] fill leaf pen black text "BUY" up 85 over 30 text "SELL" up 35 y-axis 3 border x-grid 5 y-grid 2 ] [ scale linear x-data [(dt)] pen violet bars [(smooth-fi)] fill crimson pen black text "SELL" up 85 over 30 text "BUY" up 35 text "Force Index Histogram" over 40 up 20 y-axis 2 border x-grid 5 y-grid 2 ] [ pen coal fill-pen 110.110.110 bars [(vo)] x-data [(dt)] rescale y-axis 3 border pen black text "Daily Volume" over 10 up 85 x-axis 5 border x-grid 5] ][3 1 1 1] window: layout [ vh3 "Double Screen Model" h3 "Implemented in Rebol; The easy way!" guide pad 20 button "Weekly" [graph/pane: macd-plot show graph] button "Daily" [graph/pane: force-plot show graph] ; button "Cubic Curve" [graph/pane: plot3 show graph] return ; box 2x502 blue return graph: box 504x504 coal ] macd-plot/offset: 2x2 force-plot/offset: 2x2 ; plot3/offset: 2x2 graph/pane: macd-plot view window ===Pie Charts Simple pie charts can be constructed with the keyword 'pie. view quick-plot [ 400x400 pie [2 3 4 2 5] title "A Pie Chart" style vh1 ] Colors will be given to each wedge in sequence ensuring that no adjacent wedges have the same color. There can be an unlimited number of wedges, although the pie chart get less readable as the number of slices increases. n: 24 ones: copy [] loop n [ append ones 1 ] view quick-plot [ 400x400 pie [(ones)] title "A Crowded Pie Chart" style vh2 ] Adding labels is accomplished by using the keyword 'labels followed by a block with the data labels. view quick-plot [ 400x400 pie [2 3 4 2 5] labels [First two 3 "4th" fifth] title "A Labeled Pie Chart" style vh2 ] Sections of the pie chart can be emphasized by 'exploding' them. This is done by adding the keyword 'explode followed by a block with the number of each section to be exploded. This is shown in the following example. view quick-plot [ 400x400 pie [2 3 4 2 5] labels [A B C D E] explode [3] title "An Exploded Section" style vh2 ] More than one section can be exploded in a pie chart. Also notice that the number of labels can be different then the number of sections (if it makes sense). view quick-plot [ 400x400 pie [2 3 4 2 5] explode [3 5] labels [A B C D] title "An Exploded Pie Chart" style vh2 ] The relative size of the pie chart as a percentage of the plot can be set using the 'size keyword. The default is 80% of the face. view quick-plot [ 400x400 pie [2 3 4 2 5] size 45 title "A Sized Pie Chart" style vh1 ] All of the options for a pie chart can be used in any combination or order. Have fun. ===Scatter Plot Scatter plots are designed for plotting points that are not generated by a series. In a scatter plot the x and y values change independently, and therefore must both be specified. Scatter plots are created using the 'scatter keyword, followed by a block holding the x,y data values. The x and y data can be in the form of blocks, tuples, or pairs. Here is an example using blocks (the most REBOLish data structure). random/seed now/time vals: copy [] loop 500 [ append/only vals reduce [random 100 random 100] ] view quick-plot [ 450x450 x-min 0 x-max 101 y-min 0 y-max 101 title "Randomness" style vh1 scatter [(vals)] ] Here is the same plot, but using tuples. The plotting symbol is also changed to a diamond for this example. random/seed now/time vals: copy [] loop 500 [ append vals to-tuple compose [(random 100) (random 100)] ] view quick-plot [ 450x450 x-min 0 x-max 101 y-min 0 y-max 101 title "Randomness 2" style vh1 scatter [(vals)] symbol diamond fill green ] Options for scatter plots include the symbol, color, fill and symbol size. They are specified using the keywords 'symbol, 'color, 'fill, and 'size respectively. Symbol recognized are: circle, box, diamond, cross, X-mark (the default), and point. The size is the size of the symbol in pixels. Here are some examples random/seed now/time vals: copy [] loop 100 [ append vals to-pair compose [(random 100) (random 100)] ] view quick-plot [ 450x450 x-min 0 x-max 101 y-min 0 y-max 101 title "Randomness 3" style vh1 scatter [(vals)] symbol diamond fill red size 5 ] Note that the diamond does not draw a border, only the filled interior of the symbol. Another random/seed now/time vals: copy [] loop 500 [ append/only vals reduce [random 100 random 100] ] view quick-plot [ 450x450 x-min 0 x-max 101 y-min 0 y-max 101 title "Randomness 4" style vh1 scatter [(vals)] symbol circle ] Again random/seed now/time vals: copy [] loop 500 [ append/only vals reduce [random 100 random 100] ] view quick-plot [ 450x450 x-min 0 x-max 101 y-min 0 y-max 101 title "Randomness 5" style vh1 scatter color purple [(vals)] symbol cross ] ===Plot Options Various options can be added to the plot elements to enhance the usability and presentation of the generated plots. The following options are available. plot scale (logarithmic or linear) plot title element label x-axis labels y-axis labels x-dimension grid line y-dimension grid line text at an arbitrary location on the plot Additional effects can be added to the plot elements themselves. Some effects are; line color fill color line pattern All are covered in more detail in the following sections. ===Scales There are 3 options for selecting the scale of the plot. They are linear, log (or log-linear) and log-log. A linear scale plots the chart with both axis using conventional linear scales. Linear scales are the default and will be used if no scale is specified. view quick-plot [ 300x300 scale linear ; this is the default line [(data: copy [2] loop 10 [append data (2 * last data)]) ] title style vh1 "Linear scale" x-axis 7 border y-axis 7 border x-grid 7 y-grid 7 ] A log or log-linear scale plot the chart with logarithmic y values and linear x values. view quick-plot [ 300x300 scale log-linear ; this can be shortened to log line [(data: copy [2] loop 10 [append data (2 * last data)]) ] title style vh1 "Log scale" x-axis 7 border y-axis 7 border x-grid 7 y-grid 7 ] A log-log scale plots the chart with logarithmic x and y values. The x axis plots in true logarithmic manner, however the x-axis labels are only approximately correct. If anyone needs this fixed now, let me know and I will work on it. view quick-plot [ 300x300 scale log-log ; both axis logarithmic line [(data: copy [2] loop 10 [append data (2 * last data)]) ] title style vh1 "Log-log scale" x-axis 7 border y-axis 7 border x-grid 7 y-grid 7 ] Finally the scales can be set to 'dynamic and quick-plot will determine when to use a logarithmic y-axis. Dynamic mode will use a log y-axis when the range of y-data is large compared to the max y value. When using dynamic scale mode the criteria for switching between log and linear scales can optionally be specified. view quick-plot [ 300x300 scale dynamic ; this will use a linear scale line [(data: copy [2] loop 10 [append data (2 * last data)]) ] title style vh1 "Dynamic scale (linear)" x-axis 7 border y-axis 7 border x-grid 7 y-grid 7 ] The switchover value if specified is a percentage of the max y value. When the range of y values exceeds the switchover point then a log scale will be used if the y range is less than the percentage specified then a linear scale is used. The percentage tested against the specified value is: (y-max - y-min) / y-max x 100. The default is 100 pct. view quick-plot [ 300x300 scale dynamic 50 ; this will use a log scale line [(data: copy [2] loop 10 [append data (2 * last data)]) ] title style vh1 "Dynamic scale (log)" x-axis 7 border y-axis 7 border x-grid 7 y-grid 7 ] ===Title To enter a title in a quick-plot pane simply use the keyword 'title followed by a string. Note that quick-plot will do a fair approximation of horizontally centering the title within the pane. Here is a very simple example. view quick-plot [ 200x100 title "Title Sample" ] The style of the title can be changed by using the keyword 'style after the 'title keyword. The 'style keyword can either precede or follow the title string. view quick-plot [ 300x100 title style vh3 "Style Sample" ] The order of inputs to 'title doesn't matter as shown in this example. view quick-plot [ 300x100 title "Reverse Keywords" style code ] The usable words for style are any of the predefined View styles. They include: h1, h2, h3, h4, h5, banner, vh1, vh2, vh3, txt, text, vtext, tt, and code. ===Element Labels Labels are attached to plot elements by following them with the keyword 'label and a string to use as the label. Note that unless changed, the label will appear in the same color as the plot element it follows. data1: copy [] data2: copy [] for i 1 500 .5 [ append data1 sine i append data2 cosine i ] view quick-plot [ 400x400 pen red line [(data1)] label "Sine curve" pen green line [(data2)] label "Cosine curve" ] Notice that the labels are plotted close to the element they follow. The text for each label is indented from the preceding label for legibility. Quick-plot will display 25 labels moving across the pane (left to right) before the label text location resets to the left edge of the pane. ===Axis Axis labels are added to any plot by using the keyword x-axis or y-axis followed by the number of labels to be drawn. The x-axis and y-axis do not need to be the same number. Here is an example view quick-plot [ 300x200 line [4 5 6 7 8 9 10] x-axis 7 y-axis 4 ] Note that the last x-axis label is inset from the right edge so that the entire label can be displayed. ---Borders for Axis labels Each axis can also be drawn in a border area around the plot by using the 'border keyword. The size of the plot elements will be reduced to accommodate the border into the given plot size. The x and y axis are independently specified. The following examples include grids so the effect of the border is clear, the grids are not required when using the axis 'border option. X-axis example view quick-plot [ 300x200 line [4 5 6 7 8 9 10] x-axis 7 border y-axis 4 x-grid 7 y-grid 4 ] Y-axis example view quick-plot [ 300x200 line [4 5 6 7 8 9 10] x-axis 7 y-axis 4 border x-grid 7 y-grid 4 ] Both axis view quick-plot [ 300x200 line [4 5 6 7 8 9 10] x-axis 7 border y-axis 4 border x-grid 7 y-grid 4 ] The default is to have the axis labels drawn inside the plot. This can be made explicit by using the 'inset keyword. view quick-plot [ 300x200 line [4 5 6 7 8 9 10] x-axis 7 inset y-axis 4 inset x-grid 7 y-grid 4 ] ===Special Rules for Dates (X axis) When the x-data is make up of date! entries, they can be passed in a block as any other data series. Note that the values may appear to increment irregularly, if the number of data entries is not evenly divisible by the number of axis marks displayed (due to rounding errors). Here is an example. date-data: copy [] y-data: copy [] for i 0 10 1 [ insert y-data i insert date-data (now/date - i) ] val: 6 view quick-plot [ 600x300 x-data [(date-data)] line [(y-data)] x-axis (val) border x-grid (val) ] Alternatively, the x-data block can be condensed to a block containing only two values, the minimum and maximum of the data series. !Note: There may be slight differences is the values displayed for the axis between these two methods if the number of axis values is not a factor of the number of data points. This discrepancy is caused by rounding errors when selecting which whole number date to display. Here is an example of the shorthand method of specifying x values (two item x-data block). date-data: reduce [now/date - 10 now/date] y-data: copy [] for i 1 10 1 [ insert y-data i ] val: 6 view quick-plot [ 600x300 x-data [(date-data)] line [(y-data)] x-axis (val) border x-grid (val) ] ===Grid Lines Grid lines are added to any plot by using the keyword x-grid or y-grid followed by the number of grid lines to be drawn. The x-grid and y-grid do not need to be the same number. Here is an example view quick-plot [ 200x200 line [4 5 6 7 8 9 10] x-grid 5 y-grid 4 ] ===Text To add text at an arbitrary location the keyword 'text are used in combination with keywords 'up and 'over. Keywords 'up and 'over are followed by an integer specifying the amount to move the pen before writing the text string. The amounts are specified in percent, i.e., up 25 means start the text 25% of the distance from the bottom of the plot and over 50% means start the text 50% of the way across the plot. If not specified the text will be added at the current pen location (usually off the visible plot). view quick-plot[ 300x300 title "Adding Text" pen green line [0 2 4 6 8 10 12 14 16 18 20 22] label "A Line" pen black y-axis 6 y-grid 6 x-axis 6 x-grid 6 pen yellow text "y = 2x + 0" up 75 over 15 ] Additionally the font for the text can be changed using the 'font keyword followed by a font object. The text color can also be changed in the same way by using the keyword 'color followed by a color. data1: copy [] for i 1 500 .5 [ append data1 sine i ] option-font: make face/font [ size: 13 style: [italic bold] name: font-serif ] view quick-plot [ 300x300 pen red title "Using Fonts" line [(data1)] label "Sine curve" text color green "Not an exciting plot" up 25 over 45 text font option-font "But the colors are bold" color red up 20 ] Notice that the over keyword need not be specified if the value is not changed between uses. ===Element Effects Element effects can be used to visually enhance the plots generated by quick-plot. The same options usable in the draw dialect are usable in the quick-plot dialect. Please see the draw dialect documentation of details. Some specific comments follow. ---Line Colors Line colors are changed by using the 'pen keyword followed by a color or tuple specifying the color. ---Line Pattern Line patterns are changed by using the 'line-pattern keyword followed by integers indicating how many pixels to draw and then skip. ---Fill Color When drawing bar charts, a fill color can be specified using the 'fill-pen keyword. The default is no fill (transparent boxes). ===Multi-Plots A multi-plot is an embedding of two or more plots in a single pane. !A multi-plot is created by calling the multi-plot function with the following parameters; size [pair!] representing the total size of the plot plots [block!] a block of quick-plot data blocks !refinements that can be added include /ratio [block!] a block of the relative size of the plots The default is for each sub-plot to be of equal size. /down assemble the component plots going down (default) /across assemble the component plots going left to right Note that when using a multi-plot if any of the quick-plot data blocks contain an initial pair (as required by the quick-plot dialect) it is ignored and the sub-plot will be generated in a appropriate size to meet the requirements of the multi-plot. Optionally, the initial pair can be left out of a data bock and multi-plot will supply a correct value. This scheme was adopted to enable the simple reuse of plot data blocks, the initial quick-plot pair is accepted and ignored, if it is included in the block. Here is a basic example m-plots: multi-plot 400x400 [ [ ; note that no initial pair is used title "2 to a Power" pen green line [0 2 4 8 16 32 64 128] pen white y-axis 5 ; y-grid 5 x-axis 8 x-grid 8 ] [200x400 ; this will be ignored by multi-plot line [0 5 10 15 20 25] title "A Line" y-axis 4 ; y-grid 4 x-grid 5 ] [600x600 ; this will be ignored as well title "No Meaning" line [0 10 20 10 0] y-axis 5; y-grid 5 ;x-axis 5 ; x-grid 5 ] ] view m-plots A multi-plot example showing the use of the /ratio refinement. m-plots: multi-plot/ratio 600x600 [ [200x400 ; ignored in multi-plot title "2 to a Power" pen green line [0 2 4 8 16 32 64 128] pen white y-axis 5 y-grid 5 x-axis 8 x-grid 8] [line [0 5 10 15 20 25] title "A Line" y-axis 4 y-grid 4 x-grid 5 ] [600x600 ; ignored in multi-plot title "Still No Meaning" line [0 10 20 10 0] y-axis 5 y-grid 5 x-grid 5 ] ][3 1 2] ; need not be integers view m-plots Plots going across the page. m-plots: multi-plot/across 600x200 [ [200x400 ; ignored in multi-plot title "2 to a Power" pen green line [0 2 4 8 16 32 64 128] pen white y-axis 5 y-grid 5 x-axis 8 x-grid 8] [line [0 5 10 15 20 25] title "A Line" y-axis 4 y-grid 4 x-grid 5 ] [600x600 ; ignored in multi-plot title "Still No Meaning" line [0 10 20 10 0] y-axis 5 y-grid 5 x-grid 5 ] ][3 1 2] ; this will be ignored since the ; ratio refinement was not specified view m-plots !Note, since multi-plot is a function, the order of arguments is significant. When using multi-plot you must provide a pair (size) a block of blocks (plot data) and if using the /ratio refinement a block of relative sizes. ===Plots in a Sub-panel When building applications and interactive programs with plots it may be useful to place them in sub-panels within the GUI. A plot returned by quick-plot is a complete pane and can be easily incorporated into a sub-panel. Here is a simple and fun example of switching plots dynamically. window: layout [ vh2 "Switching plots" guide pad 20 button "Sine wave" [graph/pane: plot1 show graph] button "Parabola" [graph/pane: plot2 show graph] button "Cubic Curve" [graph/pane: plot3 show graph] return box 2x204 blue return graph: box 354x204 coal ] data1: copy [] data2: copy [] data3: copy [] for i -400 400 .5 [ append data1 sine i append data2 (i * i) append data3 (i ** 3) ] graph-size: 350x200 plot1: quick-plot [ (graph-size) line [(data1)] title "Sine Wave" ] plot2: quick-plot [ (graph-size) line [(data2)] title "Parabola" ] plot3: quick-plot [ (graph-size) line [(data3)] title "Cubic Function" ] plot1/offset: 2x2 plot2/offset: 2x2 plot3/offset: 2x2 graph/pane: plot1 view window ===Data Set Size Limits Quick-plot is usable even with large data sets, its scalability is limited only by the interpreted nature of REBOL. On a reasonably fast computer creating panes with well over 10,000 points is not a problem. Here is an example of 50,000 points being calculated and plotted. view quick-plot [ 600x200 title "A Big Example" line [( data: copy [] fl: flash "Calculating points" i: 0 loop 50000 [ i: i + 1 append data sine (i / 40) ] unview/only fl data )] x-axis 5 ] ===Additional Examples Here are some additional examples you may want to try. plotter: quick-plot [ 200x200 title "Example" line [( data: copy [] i: 0 loop 500 [ i: i + 1 append data sine (i * 4) ] )] text "A fast sine" over 20 up 30 ] view plotter Skipping some y values in the data. data: copy [] i: 0 loop 500 [ i: i + 1 either ((remainder i 5) = 0) [append data none] [append data sine (i)] ] plotter: quick-plot [ 200x200 title "More Examples" line [(data)] text "Every 5th value skipped" over 30 up 30 ] view plotter A stock chart with an exponential moving average and OHLC plot, displayed over a volume plot. do %get-stock.r ticker: copy "IBM" either exists? (stock-file: to-file join ticker ".csv") [ set [dt op hi lo cl vo] get-stock/data/retrieve ticker (now/date - 250) now/date stock-file ][ fl: flash join join "Downloading " ticker " stock data" set [dt op hi lo cl vo] get-stock/data/store ticker (now/date - 250) (now/date) stock-file unview/only fl ] prices: reduce [op hi lo cl] ema: copy [] hold-blk: copy [] ma-length: 10 ;length of the moving average ema-val: 2 / ( ma-length + 1) ; ema multiplier ; corresponding to a time constant of ma-length ema-carry: 1.0 - ema-val append ema first cl cl: next cl until [ today: first cl ; ema calculations append ema (today * ema-val + (ema-carry * last ema)) ; advance one day tail? cl: next cl ] cl: head cl total-plot: multi-plot/ratio 600x600 [ [600x600 scale dynamic 25 title (ticker) style vh2 x-data [(dt)] stock [(prices)] ; x-axis 5 y-axis 7 border x-grid 5 y-grid 7 pen yellow line [(ema)] label "EMA"] [600x100 pen coal fill-pen 110.110.110 bars [(vo)] x-data [(dt)] rescale y-axis 3 border pen black text "Daily Volume" over 10 up 85 x-axis 5 border x-grid 5] ][4 1] view total-plot This may be taking these toy examples a little too far, but it provides an idea of what is easy to do using REBOL. (Perhaps useful as a prototype for another whiteboard?) ; lets add some user interaction/annotation m-plots: multi-plot/ratio 450x400 [ [title "2 to a Power" pen green line [0 2 4 8 16 32 64 128] pen white y-axis 5 y-grid 5 x-axis 8 x-grid 8] [200x400 line [0 5 10 15 20 25] title "A Line" y-axis 4 y-grid 4 x-grid 5 ] [600x600 title "Pointless" line [0 10 20 10 0] y-axis 5 y-grid 5 ;x-axis 5 x-grid 5 ] ][3 1 2] top-pane: layout [ h1 "Hand Annotations!!!" h3 "Write on the plots with the mouse while holding down mouse button-1" image to-image m-plots with [ ; this borrows from Allen Kamp's Simple Canvas effect: copy/deep [draw [pen red line]] line: second effect feel: make feel [ engage: func [top-pane a e][ if find [down over] a [ append top-pane/line e/offset show top-pane ] if a = 'up [ append top-pane/line 'line ; posit: e/offset ] ] ] ] across button "Save Image" [save/png request-file/only/filter 'png to-image top-pane] button "View Saved" [ view/new saved-pix: layout [ do [ txt: "" if (error? try [img: load request-file/only/filter 'png]) [txt: "Unable to load the Image file you requested." img: logo.gif] ] image img frame aqua h2 :txt button "close" [unview saved-pix] ] ] ] view top-pane } ; end of content code: text: layo: xview: none sections: [] layouts: [] space: charset " ^-" chars: complement charset " ^-^/" rules: [title some parts] title: [text-line (title-line: text)] parts: [ newline | "===" section | "---" subsect | "!" note | example | paragraph ] text-line: [copy text to newline newline] indented: [some space thru newline] paragraph: [copy para some [chars thru newline] (emit txt para)] note: [copy para some [chars thru newline] (emit-note para)] example: [ copy code some [indented | some newline indented] (emit-code code) ] section: [ text-line ( append sections text append/only layouts layo: copy page-template emit h1 text ) newline ] subsect: [text-line (emit h2 text)] emit: func ['style data] [repend layo [style data]] emit-code: func [code] [ remove back tail code repend layo ['code 460x-1 trim/auto code 'show-example] ] emit-note: func [code] [ remove back tail code repend layo ['tnt 460x-1 code] ] show-example: [ if xview [xy: xview/offset unview/only xview] xcode: load/all face/text if not block? xcode [xcode: reduce [xcode]] ;!!! fix load/all intro-blk: copy xcode ;; Here's the mess I added to allow arbitrary code before 'view either xcode: next find xcode 'view [ ; if there is an explicit 'view in the block, ; then break it up and 'do the part of the block up to 'view reduce head clear find intro-blk 'view ; finally feed the part after 'view to the dialect ; to make a face (quick-plot) and then drive ; the properly offset 'view either 'quick-plot = first xcode [ xview: view/new/offset quick-plot second xcode xy ][ xview: view/new/offset do xcode xy ] ][ if here: select xcode 'layout [xcode: here] xview: view/new/offset layout xcode xy ] ] page-template: [ size 500x480 origin 8x8 backdrop white style code tt black silver bold as-is para [origin: margin: 12x8] font [colors: [0.0.0 0.80.0]] style tnt txt maroon bold ] parse/all detab content rules show-page: func [i /local blk last-face][ i: max 1 min length? sections i append clear tl/picked pick sections i show tl if blk: pick layouts this-page: i [ f-box/pane: layout/offset blk 0x0 last-face: last f-box/pane/pane f-box/pane/pane/1/size: f-box/pane/size: max 500x480 add 20x20 add last-face/offset last-face/size update-slider show f-box ] ] update-slider: does [ either object? f-box/pane [ sld/redrag min 1.0 divide sld/size/2 f-box/pane/size/2 sld/action: func[face event] compose [ f-box/pane/offset/2: multiply face/data (subtract 480 f-box/pane/size/2) show f-box ] ][ sld/redrag 1.0 show sld sld/action: none ] sld/data: 0 show sld ] main: layout [ backdrop effect [gradient 1x1 220.220.255 0.0.172] across h2 title-line return space 0 tl: text-list 160x480 bold black white data sections [ show-page index? find sections value ] h: at f-box: info 500x480 at h + 500x0 sld: slider 16x480 at h + 456x-24 across space 4 arrow left keycode [up left] [show-page this-page - 1] arrow right keycode [down right] [show-page this-page + 1] pad -120 txt form system/script/header/date/date ] update-slider show-page 1 xy: main/offset + 480x100 view main
halt ;; to terminate script if DO'ne from webpage
Notes
  • email address(es) have been munged to protect them from spam harvesters. If you are a Library member, you can log on and view this script without the munging.
  • (m:s:licholai:ieee:org)