Seeking philosophical guidance on library interface design.

Alex Tweedly alex at tweedly.net
Wed Apr 24 20:47:31 EDT 2019


Thanks everyone for great feedback and suggestions.

Below I've included the current summary specs; currently this is all 
pretty much working, except for
titles (which I just haven't done yet :-), and a few minor tweaks to 
handle improvements I've added to the spec from reading the "R" docs 
(thanks for that pointer Richard).

I've pretty much decided to take Mark's and Bob's suggestion - but in 
reverse :-)  So the default will be to have default values for most 
parameters, and implement some kind of "intelligent" guess for those 
which need it (which it turns out is really only tick marks, grid lines 
and labelling of each of those) - but supply a single parameter which 
says "don't make guesses".


On 24/04/2019 14:54, prothero--- via use-livecode wrote:
> Also useful would be a message that sends the x,y data values as the mouse moves over it. That way it would be possible for me to build a little window that gives me data values and other information as needed. Perhaps it could be clicked on and off with a checkbox.

Yeah, I've been thinking about that - but haven't yet reached any kind 
of solution. Need to think some more - in particular, should it try to 
give messages when the mouse is over any line segment ? Or only when it 
is over the data point at the ends of the line segments (and within the 
bars of a bar-chart).


Anyway - here's the current spec, any further feedback welcome.

btw - my aim is to release a first (beta) version before the end of April.


A Graph has one or more sets of data plotted as an XY graph. There may 
be multiple sets of data displayed in the Y axis - but all of those 
share a single X-axis.


There are therefore a number of parameters which can be optionally 
defined for the entire
graph; then there are other parameters which can be set for each of the 
datasets to be displayed.

There are two distinct Y axes - the 'normal' one plus optionally one on 
the right.
Each dataset will describe whether it uses the right axis,  or defaults 
to the normal one.

Global parameters
-----------------

??   XRange - specify min/max in X for drawing (i.e. USE THIS, ignore 
values in datasets)
-- XRangeIncludes - list of x values to be included
-- XFit - round limits to multiple of this

??  YRange
-- YRangeIncludes, YFit - same for Y
?? YRightRange
-- YRightRangeIncludes, YRightFit - same for Y on right

-- Title - a title

-- XGridInterval - gap (in data units) between vertical grid lines (i.e. 
for X valuea)
--      set to 0 (default) for no grid
?? XGridMinor - number of minor grids per major grid
??      set to 0 (default) for no minor grid
-- XTickInterval - same as XGridInterval, but for ticks.
--      0 = no axis at all, empty = (default) axis but no tick
--      >0 = ticks at multiples of interval (0, 2, 4, ...)
--      <0 ticks at interval FROM xmin  (maybe 1, 3, 5, ...)
--
-- XTickLabelSpacing : 'N' = put label at each N'th tick ...
-- YTickLabelSpacing : 'N' = put label at each N'th tick ...

-- backgroundcolor - color for background of the whole graph

-- YGridInterval, ??YGridMinor,?? YTickInterval - as X
-- YRGridInterval, ??YRGridMinor,?? YRTickInterval - as X for right side
?? XTGridInterval, XTGridMinor, XTTickInterval - as X for top side

--  DataIncludesX - if TRUE, then each line of each dataset contains an 
X value
--                - otherwise, no X values are present in the datasets,
--                  and this element contains (up to) two values : 
initial and step X values
--                  deault (i.e. empty) is for inital value of 0, and 
step value 1
--
--            NB - applies to ALL datasets

--  'itemDel', 'lineDel' : replacing comma/CR for convenience

-- Data - one or more datasets, numerically indexed, in bottom-to-top 
drawing order.

Dataset Parameters
------------------

--   name - the name
--   graphtype  one of bar, line, step, Xticklabels, Yticklabels, 
Xgridlabels, Ygridlabels
--              for "line", it can be followed by additional optional 
words :
--                   - filled   - fill in below this line, with fillcolor
--                   - invisibe (i.e. no line segments, but still draw 
markers)
--              for "step", it can be followed by additional optional 
words :
--                   - verticalFirst (default) or horizontalFirst
--                      describe whether to go up/down then along, or 
along then up/down
--   Note that bar, step and line graphs can be "stacked" - i.e. there 
can be multiple Y values
--    producing "stacked" graphs.

--   color  : colour value, one per line for stacked charts
--   lineSize  : size (width) of the line to be drawn, one per line for 
stacked charts
--   fillcolor : color for the filled in polygon, one per line for 
stacked charts
--   fillblend : blend level for the filled polygon, one per line for 
stacked charts

--  values - list of values for the dataset
--           - so either Y, or if DataIncludesX then X,Y
--           -        or Y,Y,Y,Y... or if DataIncludesX then 
X,Y,Y,Y,...   - producing 'stacked' lines
--                    NB these all share other values, but can have 
different colors
--           - or,  if graphtype=Xlabels then it is  'label' or if 
DataIncludesX then X,Label
--  'blend' - blend level for drawing
--  'dropshadow' - put in a dropshadow

--  'YRaxis' : use the Right axis for scaling, etc.

--  'marker' : name of marker shape to use  (diamond, square, ???)
--  'markersize' : size of marker
--  'markercolor' : color for marker

--  'barDensity' :  specifies the percentage of the ratio between bar 
and gap
                     (e.g. 50 would say that each bar is the same size 
as the gap,
                     75 would say the bar takes 3/4 of the unit width, 
while the gap takes the rest, etc.)_
                     Default is 75


X Value spacing

For a graph consistng only of line charts, the calculation of X_value 
spacing is straightforward. We calculate the spread of X data values 
(i.e. min to max values, plus anything specified in an 'XIncludes', and 
then rounded out to include anything needed for an 'XFit'). Let's call 
this the "virtual data range". This range of values is then scaled to 
cover the visual space from the Y-axis to the right-Y-axis.

However, for a bar-chart, we need to allow the space for a 1/2 gap width 
plus a 1/2 bar width on each side of these (virtual) data values. Also, 
we need to allow a way to specify the 'density' of the display - i.e. 
how wide the bars are, and how wide the gaps between them are. And, 
especially in the case of DataIncludesX

--  Xunit - X_unit   (NB shared for all datasets in the whole graph)
         X_unit specifies the unit size (i.e. in 'source data' terms)

         The default is for the X_unit to be 1 (as it will be unless 
DataIncludesX is TRUE), while the default for barDensity is 75.



Examples
--------

1. the simplest possible example.

put "1:2:4:8:16:15:14:13:12:22:17:15" into temp
replace ":" with CR in temp
put temp into sA["data"][1]["values"]
gmMakeGraph the long id of grp "mycanvas", sA

1a. same thing, using the itemDel feature.

put ";" into sA["lineDel"]
put "1:2:4:8:16:15:14:13:12:22:17:15" into temp
put temp into sA["data"][1]["values"]
gmMakeGraph the long id of grp "mycanvas", sA

2. A better example, using percentages.

    put "0, 100" into sA["YRangeIncludes"]   -- make sure we have full 
percentage range shown
    put 5 into sA[K]["YTickInterval"]           -- tick every 5, label 
it every 10
    put 2 into sA[K]["YTickLabelSpacing"]

    put "Better line chart" into sA["title"]
    -- first data series
    put "1:2:4:8:16:15:14:13:12:22:17:15" into tA[1]["values"]
    replace ":" with CR in tA[1]["values"]

    put tA into sA[K]["data"]
    gmMakeGraph the long id of grp "mycanvas", sA


3.  A bar + line chart, 2 data series, X values included

    put "Simple bar & line chart" into sA["title"]
    put TRUE into sA["DataIncludesX"]

    put 0 into sA["YRangeIncludes"]
    put 5 into sA["YTickInterval"]
    put 2 into sA["YTickLabelSpacing"]
    put 10 into sA["YGridInterval"]

    -- first data series
    put "1,13:3,11:4,14:7,17:8,22:9,29:12,45:13,3" into tA[1]["values"]
    replace ":" with CR in tA[1]["values"]
    put "bar" into tA[1]["graphtype"]
    put "red" into tA[1]["color"]

    -- second data series
    put "1,4:3,12:5,7:9,5:10,23:11,7:12,33:13,9" into tA[2]["values"]
    replace ":" with CR in tA[2]["values"]
    put "diamond" into tA[2]["marker"]
    put 7 into tA[2]["markersize"]
    put "blue" into tA[2]["color"]
    put "blue" into tA[2]["markercolor"]
    -- third data series - not really data, but X-axis labels
    put "Xticklabels" into tA[3]["graphtype"]
    put "1,Jan:3,Mar:4,Apr:5,May:7,Jul:8,Aug:9,Sep:10,Oct:11,Nov:12,Dec" 
into tA[3]["values"]
    replace ":" with CR in tA[3]["values"]

    put tA into sA["data"]
    gmMakeGraph the long id of grp "mycanvas", sA


-- Alex.






More information about the use-livecode mailing list