Charting Example

Below is an example declarative way to indicate charts, such as line graphs, bar charts, and pie charts. It is to illustrate that many API's need very little in actual behaviors (methods and function calls) to achieve complex and useful results.

It is roughly based on a combination of ColdFusion MX's chart API's and a few others I have worked with over the years. (ColdFusion's API's are only partially declarative.)

The only "action" that is needed is "Plot(chartID)".

  Table: Charts
  --------------
  chartID
  chartTitle
  chartType   // line, plot, bar, or pie
  XTitle      // X axis title
  YTitle
  width
  height
  showGrid   // true if grid lines
  showLegend
  ....

Table: chartSeries // a line or group on chart ----------- seriesID chartRef // foreign key to Charts table seriesTitle // for (optional) legend title markerCode // see note seriesColor // 6-char HTML-style color indicator query // SQL, see note seriesOrder // order of presentation in legend and/or bars
The "query" must return 3 columns with the names "s_order", "x_value", and "y_value". (One usually uses SQL column aliasing to produce the needed names.) S_order is needed because x_value is assumed to be a string. It may sound odd to do it this way, but it works out fine in actual API's and has some subtle benefits that I won't go into here. In many cases it can simply be the numeric version of the x_value column. (An optional design approach is to let the order of the query itself determine the order, eliminating the need for an "s_order" column. A case can be made for both approaches.)

"markerCode" can be blank, digits, or letters. Blank means there is no marker (for line graphs). Digits 1 through 9 indicate specific symbol markers such as diamonds, crosses, circles, squares, etc. Zero means automatic symbol selection. Letters will plot a capital alphabetic character as the marker. There are fancier ways to specify markers, but this approach keeps things simple. Automatic mode will cycle through letters also if more than 9 lines.

Note that some combinations of attributes are not relevant. For example, pie charts only use one series. If there are multiple series specified and "pie" is selected, then only the first one is plotted. Some might argue for an exception to be raised, but sometimes people want to try out different display approaches without deleting and and reloading data. Thus, I lean toward the "just ignore" approach to dealing with non-applicable attributes or data. Maybe warning messages can be put into a log or something. (I suppose we could make it print multiple pies, but positioning can get messy.)

If the ordering conflicts in multiple series, then the lower-ordered series is given priority. "Order" columns can also be floating point, not just integer. Pie charts will base bie portion on ratios of total rather than absolute percents, although it will work out the same if percents are used.

One advantage of this approach is that a charting engine that uses it can easily be adapted to just about any programming language since it does not depend on specific language syntax. I suppose one could argue that it depends on SQL, but that can be removed by changing the API to ask for a table name or input file that fits a certain format. I find that less flexible, but certainly doable. A fancy engine will perhaps allow multiple data input approaches.

The API is actually tied to something even more constraining than the language syntax - it's tied to a specific language's representation of a dataset.

There is no language-neutral "data structure" that I know of. "Array" is probably the closest to universal, but cannot mix strings and values in many languages, such as for bar charts. I suppose one could argue that an addData(...) or setData(...) accessor/mutator could be implemented in any language, and is thus a bit more transferable. But a table fan would probably feel that languages that don't support native tables and/or queries is primitive or crippled, needing accessors or comma-separated data files to compensate.

This works great in Cold Fusion, where there's a language-defined query type with consistent semantics, not so much if you're going for a language-neutral engine. Taking a table name makes it even more complicated, because now your graphing engine needs to incorporate a database access layer that knows how to connect to and query an arbitrary set of databases(!). Again, this is no problem in the Cold Fusion environment, which provides just such a layer. If you were writing a low level (for example, the engine that actually implements the CF charting) engine, you'd have to define some sort of internal data format and expose that via an api or data structure. It certainly isn't anything as easy as "plot(dataset)", but it's how you're going to get language neutrality - your language wrappers can then provide the simple api by mapping an appropriate language datatype to the underlying one. -- ChrisMellon?

I don't see where it was claimed this was to be more language-neutral. It is referenced in IsDeclarativeLessExpressive. Issues of expressiveness and being language-neutral may not be related. If anything, language-neutral interfaces need to be "dumbed down" to some extent, which tends to take away a lot of pet features that people prefer in their favorite language or paradigm, such as closures, objects, higher-order functions, try/catch blocks, tables, etc.


EditText of this page (last edited August 30, 2005) or FindPage with title or text search