Formula: Spreadsheet-like mathematics for TiddlyWiki

2,917 views
Skip to first unread message

Evan Balster

unread,
Dec 14, 2017, 11:37:26 PM12/14/17
to tiddl...@googlegroups.com
Hello, all —

I got fed up with the lack of good number-crunching capabilities in TiddlyWiki, and after griping about it for a year I fixed it.

Introducing the Formula plugin:  http://evanbalster.com/tiddlywiki/formulas.html  (currently version 0.2.0)

Report issues and view source GitHub:  https://github.com/EvanBalster/TiddlyWikiFormula


Formula is implemented as a widget, with a special (= "mushroom bracket" =) syntax for inclusion in WikiText.  It supports filters, transclusion and variables, can process other formulas included via those mechanisms, and automatically refreshes like the rest of TiddlyWiki.

(= ( sum([tag[Profits]get[value]]) - sum(tag[Expenses]get[value]]) ) * {{Tax!!rate}} =)

A macro allows formulas to be used as attributes (pending proper integration with the wiki parser):

<svg viewBox=<<formula " '0 0 ' & {{!!width}}*2 & ' ' & {{!!height}}">> >

I'm modeling most of the syntax and behavior after popular spreadsheet software (Microsoft Excel and Google Sheets) and have implemented a decent library of math functions so far.  While I don't plan on making a full spreadsheet UI, I'm working on support for cell numbers and ranges in formulas (so others can do so).

EDIT:  0.2.0 adds support for local variables, lambda functions and operating on individual array or filter items.

The wiki itself documents formula syntax extensively:  http://evanbalster.com/tiddlywiki/formulas.html


I'm sure many of you, like me, have been looking for something like this for a long time.  If so, please give it a look, report any issues you encounter on GitHub, and feel free to share any function or operator extensions you develop.

For my part, I'll be tearing a lot of old, bad code out of my tax ledger wiki and my D&D character sheet automator.  And generating some slick SVGs.  :)


Enjoy —
Evan Balster, imitone

Diego Mesa

unread,
Dec 14, 2017, 11:47:39 PM12/14/17
to TiddlyWiki
Thanks Evan! Also if others could please post some cool examples that would be great! 


On Thursday, December 14, 2017 at 10:37:26 PM UTC-6, Evan Balster wrote:
Hello, all —

I got fed up with the lack of good number-crunching capabilities in TiddlyWiki, and after griping about it for a year I fixed it.

Introducing the Formula plugin:  http://evanbalster.com/tiddlywiki/formulas.html  (version 0.1.0 at time of posting)
Source and issue tracking on GitHub:  https://github.com/EvanBalster/TiddlyWikiFormula


Formula is implemented as a widget, with a special (= "mushroom bracket" =) syntax for inclusion in WikiText.  It supports filters, transclusion and variables, can process other formulas included via those mechanisms, and automatically refreshes like the rest of TiddlyWiki.

(= ( sum([tag[Profits]get[value]]) - sum(tag[Expenses]get[value]]) ) * {{Tax!!rate}} =)

A macro allows formulas to be used as attributes (pending proper integration with the wiki parser):

<svg viewBox=<<formula " '0 0 ' & {{!!width}}*2 & ' ' & {{!!height}}">> >

I'm modeling most of the syntax and behavior after popular spreadsheet software (Microsoft Excel and Google Sheets) and have implemented a decent library of math functions so far.  While I don't plan on making a full spreadsheet UI, I'm working on support for cell numbers and ranges in formulas (so others can do so).

Joshua Fontany

unread,
Dec 15, 2017, 12:05:58 AM12/15/17
to TiddlyWiki
Evan, this looks great! I think it will replace MathCell in my Earthdawn "CampaignWiki" plugin. :)

Mahalo (Thanks)!


On Thursday, December 14, 2017 at 8:37:26 PM UTC-8, Evan Balster wrote:
Hello, all —

I got fed up with the lack of good number-crunching capabilities in TiddlyWiki, and after griping about it for a year I fixed it.

Introducing the Formula plugin:  http://evanbalster.com/tiddlywiki/formulas.html  (version 0.1.0 at time of posting)
Source and issue tracking on GitHub:  https://github.com/EvanBalster/TiddlyWikiFormula


Formula is implemented as a widget, with a special (= "mushroom bracket" =) syntax for inclusion in WikiText.  It supports filters, transclusion and variables, can process other formulas included via those mechanisms, and automatically refreshes like the rest of TiddlyWiki.

(= ( sum([tag[Profits]get[value]]) - sum(tag[Expenses]get[value]]) ) * {{Tax!!rate}} =)

A macro allows formulas to be used as attributes (pending proper integration with the wiki parser):

<svg viewBox=<<formula " '0 0 ' & {{!!width}}*2 & ' ' & {{!!height}}">> >

I'm modeling most of the syntax and behavior after popular spreadsheet software (Microsoft Excel and Google Sheets) and have implemented a decent library of math functions so far.  While I don't plan on making a full spreadsheet UI, I'm working on support for cell numbers and ranges in formulas (so others can do so).

Mat

unread,
Dec 15, 2017, 12:43:28 PM12/15/17
to TiddlyWiki
@Evan, as noted; fantastic stuff!!! It's like you've collected several of the things people have desired for for several years and solved it in one big Ka-Boom!

One that that would be very useful are arrays. It seems Formulas almost features this with the filter output and e.g the choose function (more?). TBH, it's not the math aspect I'm personally interested in but just that I think it would be easier to work with arrays than with lists as they are currently implemented in TW. (As I write this, it sparks an idea... that is probably not relevant for your project, but anyway; analogous to the ListWidget, an ArrayWidget.)

Thoughts on arrays?

<:-)

Evan Balster

unread,
Dec 15, 2017, 1:16:31 PM12/15/17
to TiddlyWiki
Hey, Mat —

So there is an Array datatype in the plugin now, but filter runs are the only way to create one.  TiddlyWiki's filters are (in my mind) the most natural analog to "cell ranges" in spreadsheet software, so this does make some sense for the record.  That said, there's a strong case for adding some other ways to define arrays, like an ARRAY(a, b, c) function...  It's also natural that there should be more functions dealing with arrays moving forward, as the only thing you can do with them right now is compute a sum!

(Excel/Sheets nerds with Opinions, please chime in.)

Some related functions I've been thinking about include a <$for x="0,100"> widget to make it easier to iterate over a series of numbers.  (I was also thinking about how useful it would be to have a timer widget, which either fires events at an interval or advances a state tiddler's numeric value over a period of time...  This would be sufficient to implement animations, simulations and self-organizing maps.)


As a conversation piece, here's a quick experiment in SVG animation I did on my tablet last night:

<$tiddler tiddler="$:/temp/SvgSlider">
<$edit-text tag=Input field=val type=range class=longslider/>


<svg viewBox="-100 -100 200 200" width=400 height=400>
<circle cx=0 cy=0 r=<
<formula "100*{{!!val}}%">> style="fill:black;"/>
<circle cx=0 cy=0 r=<
<formula "100*{{!!val}}%^3">> style="fill:red;"/>
<circle cx=0 cy=0 r=<
<formula "100*{{!!val}}%^4">> style="fill:white;"/>
<$list filter=".1 .2 .3 .4 .5 .6 .7 .8 .9 1" variable=rad>
<$list filter="0 1 2 3 4 5 6 7 8" variable=ori>
<circle
  cx=<<formula "<
<rad>>*100*{{!!val}}%^1.2*sin(pi*<<ori>>/4.5+{{!!val}}*.08+<<rad>>)">>
  cy=<<formula "<
<rad>>*100*{{!!val}}%^1.2*cos(pi*<<ori>>/4.5+{{!!val}}*.06+<<rad>>+.5)">>
  r=<
<formula "5*{{!!val}}%^1.5">> style="fill:white;"/>
</$list>
</$list>
</svg>


</$tiddler>

Joshua Fontany

unread,
Dec 15, 2017, 3:22:44 PM12/15/17
to TiddlyWiki
That is a neat demo.

Question: do you have or are you planning any rounding  or averaging functions?

Best,
Joshua Fontany

Ste Wilson

unread,
Dec 15, 2017, 3:39:58 PM12/15/17
to TiddlyWiki
Arrgghhh another option!!!!
rboue.tiddlyspot.com
mathcell.tiddlyspot.com
Reverse polish notation.. (can't find the link...)


I shall check this out! Cheers.

Mat

unread,
Dec 15, 2017, 3:41:24 PM12/15/17
to TiddlyWiki
Evan Balster wrote:
... this does make some sense for the record.
 
:-)


... <$for x="0,100"> widget to make it easier to iterate over a series of numbers.   (I was also thinking about how useful it would be to have a timer widget, which either fires events at an interval or advances a state tiddler's numeric value over a period of time... 

Vaguely connected would an explicit IFTTT-type widget that can trigger based on e.g reached iterative numbers or time. Or any state for that matter. Currently, the closest we get is to use listwidgets or revealwidgets which is very contrieved IMO, especially for multiple conditions where you must stack them. With iterations or timers, one could imagine an IFTTT with thresholds like "for as long as x<y then...". Shold be very useful.


... timer widget .... This would be sufficient to implement animations, simulations and self-organizing maps.)

Self-organizing maps...?? 


As a conversation piece, here's a quick experiment in SVG animation

haha! That's either the singularity coming or the collapse of the milky way.

<:-)

TonyM

unread,
Dec 15, 2017, 6:53:33 PM12/15/17
to TiddlyWiki
I suppose I am a "Excel/Sheets nerd with Opinions",

Also in addition to Excel a SharePoint user/developer I like implementing structures on top of Tiddlywiki we find elsewhere, such as hierarchies (one, two or multiple parents), Queues, Networks etc... because once you have a method it is easy to capture, analyse and use data structured that way in tiddlywiki.

I am very interested in "Multidimensional" arrays. Most people can conceptualise multidimensional arrays as row column spreadsheets with alternative sort orders and column orders (easy to achieve in SharePoint Views). Tiddlers can be rows (with fields) or cells or contain lists.

If we have a complete set of tools to interrogate tiddlywiki there seems to me to be no structure in the universe we cant represent.

Regards
Tony

myst...@gmail.com

unread,
Dec 15, 2017, 10:34:56 PM12/15/17
to TiddlyWiki

is this campaignWiki plugin available?

Birthe C

unread,
Dec 16, 2017, 12:38:12 AM12/16/17
to TiddlyWiki
Reverse polish notation https://tid.li/tw5/hacks.html

Mal

unread,
Dec 16, 2017, 2:13:57 AM12/16/17
to TiddlyWiki
Great work Evan!

I did find that the rounding functions fail when a second parameter is provided, so I submitted an issue on Github.

Regards,

Mal

ste...@gmail.com

unread,
Dec 16, 2017, 5:29:18 AM12/16/17
to TiddlyWiki
This looks very good, especially since it is incredibly easy to set up and use! One question: Could this be made to work with date and time?

Cheers,

Stef

Evan Balster

unread,
Dec 16, 2017, 11:20:17 AM12/16/17
to TiddlyWiki
Question: do you have or are you planning any rounding  or averaging functions?

There are rounding functions in there now.  See "Functions" and "FormulaWidget" in the doc wiki.  No averaging yet, but that's a popular function I'll replicate at some point soon.  (My last round of functions was ).

I did find that the rounding functions fail when a second parameter is provided, so I submitted an issue on Github.

Ah, I'll fix those then.  Good catch.


I am very interested in "Multidimensional" arrays.
 
From what I can tell Excel and Sheets can do 1D and 2D arrays, and these may be internally represented as selection sets.  Anyway, there's a lot of flexibility in what "value" types could be added (especially with extensions) but I'll probably imitate spreadsheet conventions and functions to begin with. 


One question: Could this be made to work with date and time?
 
Yes, I'll be adding support for a date/time datatype.  There's a long history of date/time functionality in Excel/Sheets and there are some standard TiddlyWiki/javascript functions that can be built upon.


Reverse polish notation https://tid.li/tw5/hacks.html
 
Useful reference.  Before I was driven to implement this plugin I experimented various macro-based solutions (including some homemade ones).  I even have an accounting wiki built around a sum macro.  It was my conclusion that the $set/$vars/$macrocall boilerplate makes recursive JS macros a bit too unwieldy compared to a dedicated formula syntax.  A widget also has more potential for caching/optimization/efficiency in the long term.

TonyM

unread,
Dec 16, 2017, 8:17:24 PM12/16/17
to TiddlyWiki
Evan,

Very exciting, date manipulation is timely for me, rather than wait I will look into some existing options. Is there value sharing what I find, or do you have it covered?

On multidimensional, I am not so much looking for array manipulation. Tiddlywiki and your solution already meets my requirements. Imagin a large 2d spreadsheet with 3 columns containing unique keys (or missing keys) even including date/time. If you choose a key and sort on it before you manipulate a 2D array you are effectively looking at the data in another dimension. This is very easy for TiddlyWiki.

May I ask how you use the results TRUE and FALSE in wikitest once calculated?

Do you use it in filters etc?

Regards
Tony

Evan Balster

unread,
Dec 16, 2017, 8:41:19 PM12/16/17
to TiddlyWiki
Hey, Tony —

I'm not an impatient reader.  :)

I've added a Date type in my working copy, based on JavaScript's built-in Date (which is reasonably feature-rich).  TiddlyWiki has some functions for date formatting in core, too.  Libraries like moment.js offer a "kitchen sink" of features but I'm not sure if that's necessary at the moment.

Probably my next step will be to add a basic date parser and some utility functions (convert timestamps, convert with string, construct and decompose dates).

Is there value sharing what I find, or do you have it covered?

If you find something interesting, sure, share it.  But given that there's standardized support for basic date processing in JavaScript itself I'm going to try to steer clear of libraries.

May I ask how you use the results TRUE and FALSE in wikitest once calculated?

Right now, the best use of these is in Formulas' logical functions, like IF and IFS.  In the future I might implement a $formula-if widget that works a little like the reveal widget.

Expect a new update tomorrow or so.

TonyM

unread,
Dec 16, 2017, 9:02:28 PM12/16/17
to TiddlyWiki
Evan,

Please forgive my Ignorance; What can a and b be equal to in Formulas' logical functions, like IF and IFS?

I am thinking if something evaluates to true how do I use this to
  • list
  • transclude
  • Use macro
  • Show some text etc...
  • Set a variable/field

I imagine there is a way to write a list filter if a formula it true to show when true (or False) etc...

I expect knowing this may help the less sophisticated users (still me at this point) make use of formula.

Thanks in Advance
Tony

Evan Balster

unread,
Dec 17, 2017, 3:22:36 AM12/17/17
to TiddlyWiki
Hey, Tony —

I might have been a little terse in documenting the logical functions.

The IF function chooses between its second and third arguments based on the first.  For example,

if({{!!x}}<1, "x is less than 1", "x is more than 1")

The second and third argument can be whatever sort of date you like.  Instead of strings they could be transclusions, or other functions or complicated bits of math.

IFS basically works like "if (arg1) {return arg2} else if (arg3) {return arg4} else if (arg5) {return arg6} else return undefined".  The odd-numbered arguments should be booleans and the even-numbered arguments can be whatever you like.  So this would be fine:

ifs(and({{!!x}} > {{!!y}}, {{!!x}} > {{!!z}}), "x is biggest", ({{!!y}} > {{!!z}}), "y is biggest", TRUE, "z is biggest");

Though it would be the same as:

if(and({{!!x}} > {{!!y}}, {{!!x}} > {{!!z}}), "x is biggest", if({{!!y}} > {{!!z}}, "y is biggest", "z is biggest"));

Anyway, all the logic functions are designed to work like their (better-documented) analogs in Excel and Google Sheets.

* (Notably, formula currently uses javascript rules when determining whether to treat numbers and strings as "true" or "false".  So zero and empty strings are falsy, while non-zero numbers and non-empty strings are truthy.  I can't guarantee this behavior will continue to be the case, as it might be different from how spreadsheet software does things.)

Evan Balster

unread,
Dec 17, 2017, 6:14:02 PM12/17/17
to TiddlyWiki
Hey, all —

Here's Formula plugin 0.1.1:  http://evanbalster.com/tiddlywiki/formulas.html
Source and issue tracking on GitHub:  https://github.com/EvanBalster/TiddlyWikiFormula

This version adds:
  • A $formula-vars macro
  • Preliminary date and time support
    • Date literals as datum values
    • Support for converting to/from TiddlyWiki timestamps
    • Offset and difference functions
    • Calendar functions
  • Workflow enhancements based on spreadsheet software
    • Datums (included values) beginning with "=" are treated as formulas
    • Can use names like "B3" as shorthand for individual DataTiddler indexes
  • Fixed errors with rounding functions
  • Fixed an issue with error handing in datums
  • Various other small stuff
Please continue experimenting and reporting any issues you turn up.  I'll be interested to see if the date & time stuff suits the needs of the users who've chimed in about that.

TonyM

unread,
Dec 17, 2017, 6:35:54 PM12/17/17
to TiddlyWiki
Wow, is all I can say. Thanks

Tony

TonyM

unread,
Dec 17, 2017, 7:18:13 PM12/17/17
to TiddlyWiki
Evan,

I have started using the date functions. What appears missing that I need at the moment is;

Add_month
Add_year

In fact add_month would be sufficient because
+12 months is add year
+3 months is add quarter (next quarter)
+6 months is next half year

In an attempt to create a TW date 14 days hence I use this

(= to_tw_date(add_days(now,14) ) =)

But it returns want I want, but in an error message.

`ValueError: TypeError: value.asString is not a function value: 20180101001411129`

I have tried to set variables to make this work with no luck.

Regards
Tony

Mat

unread,
Dec 17, 2017, 9:23:02 PM12/17/17
to TiddlyWiki
Evan, 

Just to make sure it is intentional - concatenation:

1 & 2 = 1.002.00 (...i.e 1.00 and 2.00) 

... is this supposed to be allowed? A user might expect "= 12" but missed the quote marks because he e.g transcluded the numbers.

I can see use in concatenating numbers if constructing number sequences, e.g binary 0010110001. No decimals then of course. But then maybe that would be strings rather than numbers? I don't have an opinion on this, just asking to make sure it's intentional.

Apropos binary - additional feature idea: I occasionally want to convert between number bases... hex, dec, binary etc.

<:-)

Evan Balster

unread,
Dec 17, 2017, 10:40:18 PM12/17/17
to TiddlyWiki
Hey all —

What appears missing that I need at the moment is; Add_month, Add_year

Heh, you got me.  I haven't written add or difference functions for years or months yet because those entities represent variable quantities of time and the proper approach wasn't quite clear.  For the moment you can hack around it with something like:

(= date(year(mydate)+1, month(mydate), day(mydate)) =)

Results might not be what you expect if the month-day isn't applicable to the resulting month.  Anyway, I'll add these functions next iteration. 


`ValueError: TypeError: value.asString is not a function value: 20180101001411129`

That's an internal error and a rookie mistake on my part.  I'll patch it tonight or tomorrow.


Just to make sure it is intentional - concatenation:  1 & 2 = 1.002.00 (...i.e 1.00 and 2.00) 

OK, so this is a weird one.

When numbers are turned into strings (including by concatenation) they use the conversion rules defined for the widget.  Currently you can choose to set no rule (in which case fractional numbers tend to print very long), you can set fixed point (N digits after zero, as I've done on the wiki's main page), or you can set a fixed number of significant digits.  There is not, at the moment, any logic to nudge a number like .2500000001 to .25 without forcing a format onto it (because the Javascript standard library doesn't appear to provide as much).

Anyway, long story short, I could probably stand to implement smarter stringification and/or a function that allows the string format to be specified on an individual basis.


Apropos binary - additional feature idea: I occasionally want to convert between number bases... hex, dec, binary etc.

This isn't hard; I'd probably just make it a new function. 

Mat

unread,
Dec 18, 2017, 7:57:38 AM12/18/17
to TiddlyWiki
Evan, I find it confusing that 

2+3*4 > 12 works but not  "2+3*4 = 12" nor "2+3*4 == 12" .

And why does (= pow(3, 2) =) work but not (= gr(3, 2) =) ?

<:-)

hubertgk

unread,
Dec 18, 2017, 9:33:58 AM12/18/17
to TiddlyWiki
Amazing work, Evan! Thank you!

@TiddlyTweeter

unread,
Dec 18, 2017, 10:02:45 AM12/18/17
to TiddlyWiki
I'm interested in this as a spreadsheet like thing to do basic accounts.

I can't really follow the discussion when I see formulae out of context.

Can I ask some simple questions?

 (1) Can I create a table like this that auto gives the results?...

 Date       Description         Cost
 
01/12/17   Hair cut            12.00
 
07/12/17   Buy Squirrel        45.00
 
10/12/17   Innoculate Badger   14.44
                         TOTAL
: 71.44
DAILY AVERAGE SPEND
(December):  2.30

(2) Quite important. Can I in the interface just add a line? That would make for basic accounting bliss.

Best wishes
Josiah

Mat

unread,
Dec 18, 2017, 11:41:51 AM12/18/17
to TiddlyWiki
Josiah,


(2) Quite important. Can I in the interface just add a line? That would make for basic accounting bliss.

I'm pretty sure this is rather easily implemented by many people here so no worry if Evan doesn't personally make this.

<:-)

Evan Balster

unread,
Dec 18, 2017, 2:14:15 PM12/18/17
to TiddlyWiki
Hello, all —

Evan, I find it confusing that 

2+3*4 > 12 works but not  "2+3*4 = 12" nor "2+3*4 == 12" .

And why does (= pow(3, 2) =) work but not (= gr(3, 2) =) ?

 (2+3*4 = 12) should work fine — it evaluates to FALSE.  "==" is not an operator, as it's not a conventional syntax for calculators, spreadsheets or functional languages.  (I say this as a C++ programmer!)  I should note that equality might evaluate to false in unexpected situations because of floating-point error...

I don't know what the GR function should do.  No such function exists in Sheets, Excel or standard math libraries.


(1) Can I create a table like this that auto gives the results?...
(2) Quite important. Can I in the interface just add a line? That would make for basic accounting bliss.

Formulas doesn't do UI, only calculation.  So you can follow other tutorials on how to make tables.  In your case, I would suggest storing expenses as Tiddlers tagged with Expense, with fields for date, description and cost, where the date field is written in YYYY-MM-DD format.

I'm currently building your example as a test-run, but I've run into some hitches due to bugs in the plugin:

<!-- note: we want dates in this format, and numbers displayed with two digits after the decimal point. -->

<$vars formulaDateFormat="DD/mmm/YYYY" formulaFixed="2">

<table>
<!-- This first row is the table header. -->
<tr>
 
<th>Date</th>
 
<th>Description</th>
 
<th>Cost</th>
</tr>
<!-- This $list widget will show each of our expenses. -->
<$list filter="[prefix[Demo]tag[Expense]]">
<tr>
 
<td> <$link>(= {{!!date}} =)</$link> </td>
 
<td> {{!!summary}} </td>
 
<td> {{!!cost}} </td>
</tr>
</$list>
<!-- This row calculates a total. -->
<tr>
 
<td colspan="3"> <hr/> </td>
</tr>
<!-- This row calculates a total using SUM. -->
<tr>
 
<th> </th>
 
<th> TOTAL: </th>
 
<th>
    (= sum([prefix[Demo]tag[Expense]get[cost]]) =)
 
</th>
</tr>
<!-- This row shows our average per day. This is a bit more complex! -->
<tr>
 
<td> </td>
 
<td> Average per day (December): </td>
 
<td> (= sum([prefix[Demo]tag[Expense]get[cost]]) / 31 =) </td>
</tr>
</table>

</$vars>

ste...@gmail.com

unread,
Dec 18, 2017, 3:34:25 PM12/18/17
to tiddl...@googlegroups.com
Hi,

On Monday, December 18, 2017 at 12:14:02 AM UTC+1, Evan Balster wrote:

Please continue experimenting and reporting any issues you turn up.  I'll be interested to see if the date & time stuff suits the needs of the users who've chimed in about that.

Very cool! Thank you! 

Two quick observations:

1.) Apparently, a date from a tiddler field is accepted only when it is formatted as "YYYYMMDD" (but not e.g. "YYYY-MM-DD"). Maybe you could add this info to the documentation?

2.) I created a group of tiddlers with the same tag. Each tiddler contains a date in the "datum" field. I was able to pick the latest date from the list and add 14 days with the following syntax:

Deleted (see correction below)

Using the "sum" function here is a bit clumsy, though (because only one argument is provided). Is there any other way to get "date" to accept the filter result?

Cheers,

Stef

Evan Balster

unread,
Dec 18, 2017, 3:57:41 PM12/18/17
to TiddlyWiki
Hey, Stef —

I was running into some of the issues you mentioned when I tried to put together the example for @TiddlyTweeter.

1.) Apparently, a date from a tiddler field is accepted only when it is formatted as "YYYYMMDD" (but not e.g. "YYYY-MM-DD"). Maybe you could add this info to the documentation?

Actually, YYYY-MM-DD is processed as a date if it's transcluded directly.  I'm guessing you used the DATE function, which converts TiddlyWiki timestamps to dates but (somewhat stupidly) doesn't convert dates or strings in "YYYY-MM-DD" format to dates.  (I'll have to fix that.)  You can include the date directly by transcluding, eg. {{!!date}} but be advised there's a bug where the month is off by one.  It's fixed in the Git repository and I'll release the fix later today.


2.) I created a group of tiddlers with the same tag. (...) Using the "sum" function here is a bit clumsy, though.

Yes, it's pretty lame that the only thing you can do with filters at the moment is sum them (meaning strings like "2015-10-01" can't be meaningfully included).  I'll need to add some more functions to expand the options there.

I should probably come up with a more intuitive term than "datum" to describe information "included" via filters, transclusion and variables.  I fear that currently the distinction between these values and literal ones is a bit unclear.


On Monday, 18 December 2017 14:34:25 UTC-6, ste...@gmail.com wrote:
Hi,

On Monday, December 18, 2017 at 12:14:02 AM UTC+1, Evan Balster wrote:

Please continue experimenting and reporting any issues you turn up.  I'll be interested to see if the date & time stuff suits the needs of the users who've chimed in about that.

Very cool! Thank you! 

Two quick observations:

1.) Apparently, a date from a tiddler field is accepted only when it is formatted as "YYYYMMDD" (but not e.g. "YYYY-MM-DD"). Maybe you could add this info to the documentation?

2.) I created a group of tiddlers with the same tag. Each tiddler contains a date in the "datum" field. I was able to pick the latest date from the list and add 14 days with the following syntax:

(= date(sum([tag<currentTiddler>!sort[]last[1]get[datum]],14)) =)

ste...@gmail.com

unread,
Dec 18, 2017, 4:18:04 PM12/18/17
to TiddlyWiki

On Monday, December 18, 2017 at 9:34:25 PM UTC+1, ste...@gmail.com wrote:

2.) I created a group of tiddlers with the same tag. Each tiddler contains a date in the "datum" field. I was able to pick the latest date from the list and add 14 days with the following syntax:

Just in case someone wants to copy my code, this seems to be the proper syntax:

(= date(sum([tag<currentTiddler>sort[datum]last[1]get[datum]],14)) =)

The "sort" operator in my code above was wrong (it only worked for me because of the particular order of my tiddlers). 

~Stef
 

Evan Balster

unread,
Dec 18, 2017, 8:32:36 PM12/18/17
to TiddlyWiki

* Add months, years, add_months, add_years functions.
* The DATE function no longer rejects a date argument.
* Fix an off-by-one-month error parsing transcluded date fields in YYYY-MM-DD format
* Better documentation about extending formulas with new functions and operators
* Added dateFormat option to $formula and $formula-vars widgets

Also
* Added badger inoculation simulator for @TiddlyTweeter (still lacks month automation, though)

Evan Balster

unread,
Dec 18, 2017, 8:36:57 PM12/18/17
to TiddlyWiki
Issues targeted for next update:

* Make arrays more useful (add NTH, AVERAGE, etc):  https://github.com/EvanBalster/TiddlyWikiFormula/issues/11
* Parsing bug with zero-argument functions:  https://github.com/EvanBalster/TiddlyWikiFormula/issues/8

Evan Balster

unread,
Dec 18, 2017, 9:35:54 PM12/18/17
to TiddlyWiki
Got a little absorbed apparently.  Here's 0.1.3:  http://evanbalster.com/tiddlywiki/formulas.html
  • Add array functions FIRST, LAST, NTH, COUNT, COUNTA, AVERAGE
  • Fix the parsing bug with zero-argument functions
  • Require parentheses for zero-argument functions like NOW(), RAND(), but not constants like PI, _E
  • Fix non-functional DATE function
  • Fix non-functional unary plus operator
That clears most of the pressing functional issues.  Keep reporting any issues on GitHub:  https://github.com/EvanBalster/TiddlyWikiFormula

Mat

unread,
Dec 18, 2017, 9:59:36 PM12/18/17
to tiddl...@googlegroups.com

(= nth([tag[Expenses]], 3)=)

Ten-Sodas


Wohooo!

<:-)

Mat

unread,
Dec 18, 2017, 10:07:21 PM12/18/17
to TiddlyWiki
Getting greedy but... possible to make array output be links? I tried this but no worky:

(= "[[" & nth([tag[Expenses]], 1) & "]]" =)

This is so cooool! 


<:-)

Mat

unread,
Dec 18, 2017, 10:16:41 PM12/18/17
to TiddlyWiki
Evan, what you're doing is just terrific! It is such a big chunk that has been missing for so long. It's like you're coming into the dinner going "...so, guys, I just built these things called chairs for us all" !

<:-)

Evan Balster

unread,
Dec 18, 2017, 10:52:45 PM12/18/17
to TiddlyWiki
Hey, Mat —

Getting greedy but... possible to make array output be links? I tried this but no worky:
(= "[[" & nth([tag[Expenses]], 1) & "]]" =)

Oh, yeah!  This had actually crossed my mind.  The default array-to-string conversion isn't very useful except as a display format, because it's unrelated to TiddlyWiki semantics.  I was thinking, therefore, about stringifying them in the same format as TiddlyWiki's own filter output.  That would mean output //wouldn't// actually be links unless the titles contained spaces, though.

It would be easy enough to make a tw_links function that generates markup for links.  I've also thought about a more general array-to-string function that would stringify an array with "before", "between" and "after" strings, so that link generation would look like this:

(= arraystring([tag[Expenses]], "[[", "]] [[", "]]")

One caveat is that the $formula macro doesn't actually wikify its output at the moment, which should probably be among my next agenda items.

Mat

unread,
Dec 18, 2017, 11:19:46 PM12/18/17
to TiddlyWiki
(= arraystring([tag[Expenses]], "[[", "]] [[", "]]")

A bit cumbersome.
Maybe (= arraylinks([tag[Expenses]]) =)  


...and, btw, given how filters are delimited with outer square brackets, just maybe parentheses could be omitted for filters? 

(= arraylinks[tag[Expenses]] =)

(= sum[tag[Expenses]get[value]] =)

<:-)

Evan Balster

unread,
Dec 18, 2017, 11:25:51 PM12/18/17
to TiddlyWiki
Time will tell.  It's my experience that hasty decisions about syntax can make language design tougher later on, so I'm not inclined to jump the gun on brevity options.  One of the tough things about filters, in particular, is that the multi-run syntax should be supported in the future.  That has some weird implications.

It wouldn't be unreasonable to have an arraylinks function, though.

Diego Mesa

unread,
Dec 19, 2017, 11:24:01 AM12/19/17
to TiddlyWiki
Hey Evan,

In your demo, when I try: 
  • count([tag[Expenses]])
    • `ComputeError: ReferenceError: V_Num is not defined operand: [Operand function-call]`
  • [tag[Expenses]count[]]
    • [3.00]
    • This is normal
  • IF(([tag[Expenses]count[]]=3),"yes","no")
    • `ValueError: TypeError: value.asString is not a function value: no`
    • Where 3 can be either of the below without changing the returned error
      • 3.00
      • [3.00]
      • "[3.00]"
      • "3"
Thank you very much for your hard work on this plugin. Mat is right - you brought the chairs to the dinner party!

Diego

Evan Balster

unread,
Dec 19, 2017, 12:38:58 PM12/19/17
to TiddlyWiki
Hey, Diego —

Noticed the COUNT error last night and fixed it in repo.  Good catch on the IF error.  I've also noticed that IFERROR won't behave correctly and I'll be looking into fixing that at some point.

For the impatient, I'm attaching patch files that can be imported into a wiki that already has the plugin.
$__plugins_ebalster_formula_functions_logic.js.json
$__plugins_ebalster_formula_functions_math.js.json

ste...@gmail.com

unread,
Dec 19, 2017, 3:24:45 PM12/19/17
to TiddlyWiki
Hi,


On Tuesday, December 19, 2017 at 2:32:36 AM UTC+1, Evan Balster wrote:
* Fix an off-by-one-month error parsing transcluded date fields in YYYY-MM-DD format

Thank you! However, the "month" function still seems to be off by one month (please note that I used version 0.13).

(= year(date(20180314)) =)-(= month(date(20180314)) =)-(= day(date(20180314)) =)

yields

2018-2-14 (should be 2018-3-14)

Could you look into this?

Cheers,

Stef

Diego Mesa

unread,
Dec 19, 2017, 3:31:08 PM12/19/17
to TiddlyWiki
Hey Evan,

Thanks again for all your hard work. With a plugin of this complexity, Im wondering if there should be "unit tests" tiddler that could keep track of the various corner cases proposed here and that you also identify. 

Also, if/when new functionality is added we can also make sure none of the previous unexpectedly change. 

Best,
Diego

Evan Balster

unread,
Dec 19, 2017, 4:00:27 PM12/19/17
to TiddlyWiki
Hey, Diego — 

Thanks again for all your hard work. With a plugin of this complexity, Im wondering if there should be "unit tests" tiddler that could keep track of the various corner cases proposed here and that you also identify. 

This, times a million.  I had already been thinking about it.


I would like to solicit unit test contributions from users of the plugin, following this format:
  • Exported as JSON or TID
  • Tagged "UnitTest"
  • Text is a formula in (= mushroom brackets =) that should produce TRUE
  • Title Format:
    • For functions:  UnitTest/Functions/<function_name>/<test_name>
    • For operators:  UnitTest/Operators/<operator_name>/<test_name>
    • For other stuff:  UnitTest/Other/<test_name>

In other news I'm realizing that selective evaluation is going to be necessary for IFERROR to work at all, and to efficiently implement things like IF and SWITCH which shouldn't be computing the arguments they don't use.  In the long term I expect to explore some aggressive optimizations for formulas, depending on what uses I put it to.

Evan Balster

unread,
Dec 19, 2017, 4:02:36 PM12/19/17
to TiddlyWiki
Heya —

However, the "month" function still seems to be off by one month (please note that I used version 0.13).

Whoops!  That's some JavaScript leaking through.  Patched in git, hotfix attached.
$__plugins_ebalster_formula_functions_datetime.js.json

ste...@gmail.com

unread,
Dec 19, 2017, 4:25:53 PM12/19/17
to TiddlyWiki

On Tuesday, December 19, 2017 at 10:02:36 PM UTC+1, Evan Balster wrote:

Whoops!  That's some JavaScript leaking through.  Patched in git, hotfix attached.

Wow, that was fast! Can confirm that it works (after a reload, if anyone else wants to try).

~Stef 

Diego Mesa

unread,
Dec 19, 2017, 4:46:38 PM12/19/17
to TiddlyWiki
Hey Evan,

Were you thinking something like this? Or peraps something more self-contained where the input is defined as a field of this tiddler? Let me know!

Diego
UnitTest_Functions_nth_sorted-return.json

Evan Balster

unread,
Dec 19, 2017, 5:23:35 PM12/19/17
to TiddlyWiki
Hmm, it would probably be better if any unit tests were "self-contained" or relied on other data prefixed with UnitTest/data/ or some such.  I'll probably write a bundle of them on my next pass and work out a system.

@TiddlyTweeter

unread,
Dec 20, 2017, 11:18:20 AM12/20/17
to TiddlyWiki
Dear Evan

Thank you for adding that simple demo. It really helped me better understand how to use the plugin and make steps towards what I need!!

Best wishes
Josiah

Evan Balster wrote:
...

Evan Balster

unread,
Dec 20, 2017, 7:31:49 PM12/20/17
to TiddlyWiki
Formulas version 0.1.4:  https://evanbalster.com/tiddlywiki/formulas.html
  • Add text conversion functions:
    • tvaluetextjoin
  • Add text utility functions:
    • lenexactmidsubstitutesplittrim
  • Add regular expression functions:
    • regexreplaceregexmatchregexextractregexextract1.
  • Add julian day / date conversion functions:
    • julianto_julian
  • Fix off-by-one error in month function
  • Fix error in if function, disable if function pending support for more powerful function construction
  • Fix errors in count and counta functions.
  • Code cleanup
New features are documented in the wiki.

The strings and regex work were driven by my own needs with a data archiving project.

TonyM

unread,
Dec 20, 2017, 8:31:53 PM12/20/17
to tiddl...@googlegroups.com
Evan,

Once again for you great work. I have started playing with the date related functions and finding it a little complex using Make a date from a TiddlyWiki timestamp and return.

Is there any way to make this more direct or can you suggest a pattern to follow if all my dates are TiddlyWiki timestamps?

PS I have many dates in one tiddler so it get unwieldy.

Thanks in advance
Tony

Evan Balster

unread,
Dec 20, 2017, 8:53:59 PM12/20/17
to TiddlyWiki
Hey, TonyM —

Are you formatting a lot of dates using the year/month/day functions?  If so, you'll probably have better luck with the text conversion function T() and setting a dateFormat.  See the documentation for the FormulaWidget for more information on date format strings (which use the same rules as in TiddlyWiki's settings).

Evan Balster

unread,
Dec 20, 2017, 9:04:57 PM12/20/17
to TiddlyWiki
General warning:  There is a bug in filter processing that prevents filters in formulas from returning duplicate values.  This is likely to cause trouble with formulas like sum([tag[Expense]get[value]]) if two Expenses have the same value.

This bug appears to have existed since the first release.

I've got an incentive to fix this one quickly, so I might be patching this tonight.

Evan Balster

unread,
Dec 20, 2017, 10:05:37 PM12/20/17
to TiddlyWiki
  • Duplicate values in filters are now handled correctly.

TonyM

unread,
Dec 20, 2017, 10:17:40 PM12/20/17
to TiddlyWiki
Evan,

What you considered a Bug is a feature, because Titles are unique in TiddlyWiki so if you have two of the same name appear such as in when Tagged A, or B Or A and B we want the list of titles to be "de-duplicated", Of course when you use filters from non title sources we do not want this occurring. As you found.

How did you address this? (details not necessary), I presume its only in formulae and not when you are filtering titles?

Best wishes
Tony

Evan Balster

unread,
Dec 20, 2017, 10:40:21 PM12/20/17
to TiddlyWiki
Hey, Tony —

I'm aware of the ordinary "de-duplication" behavior.  In this case, it was happening even with filter operators that would normally allow duplication, like "get".  This was because of a poorly-implemented optimization I'd written to reduce compilation overhead during filter processing.  Behavior is now consistent with typical filter operations.

The unusual behavior of TiddlyWiki's "get" operator is pretty important if you're doing something like summing up a bunch of "quantity" fields where many hold values like 1 or 2.

Diego Mesa

unread,
Dec 21, 2017, 2:46:57 PM12/21/17
to TiddlyWiki
Hey Evan,

Im more and more impressed with this plugin, the more I use it. If anyone has some time and has already come up with cool examples, can you share? Also, Im interested in answering each of Tony's points from his earlier question:

Evan,
Please forgive my Ignorance; What can a and b be equal to in Formulas' logical functions, like IF and IFS?
I am thinking if something evaluates to true how do I use this to
  • list
  • transclude
  • Use macro
  • Show some text etc...
  • Set a variable/field

I imagine there is a way to write a list filter if a formula it true to show when true (or False) etc...
I expect knowing this may help the less sophisticated users (still me at this point) make use of formula.
Thanks in Advance
Tony


with specific examples. If anyone has any that would be great! 

Best,
Diego

Evan Balster

unread,
Dec 21, 2017, 3:04:37 PM12/21/17
to TiddlyWiki
Hey, Diego —

Using conditions to:
  • list / transclude
    • Both of these are a bit difficult because formula results aren't wikified right now.
    • You could have a formula result in a filter or tiddler and list or transclude that
      • <$list filter=<<formula "if (insert condition here, [tag[SomeTag]], [[mycondition is false]]">> > {{!!title}}... </$list>
  • use a macro
    • Zero-argument macros can be used directly in formulas
    • It's tougher for macros with arguments, until I add support for those
  • show some text
    • (= if (insert condition here, "text to show when condition is true", "") =)
  • set a variable
    • Set a variable based on a condition
      • <$formula-vars varToSet="if (insert condition here, "true-value", "false-value")"> <<varToSet>>... </$formula-vars>
  • set a field
    • Changing fields will usually involve a $button widget and an $action-setfield widget inside that whose arguments include formulas.  I use this myself for auto-calculation of tiddler fields and might make an example of this later.

Here are a few examples doing some fancy calculations with the current plugin:

Diego Mesa

unread,
Dec 21, 2017, 3:24:23 PM12/21/17
to TiddlyWiki
Thanks for this Evan! 

I was thinking of being able to use the if statement like this (in semi-pseduo code)

IF( gt([all[tiddlers]get[modified]], add_days(date(now()),-5)), <<title>> + "has been recently modified")

And that would display all tiddlers who were recently modified. But as I understand it, these arent really built to operate on arrays just yet - but might be in the future.

Thanks again,
Diego

Evan Balster

unread,
Dec 21, 2017, 3:38:47 PM12/21/17
to TiddlyWiki
Hey, Diego —

Yes, that kind of logic is a ways off yet and would likely need to be done with a for-loop like construct.

For now, you'll need to construct it using the $list widget, like this;

Recently modified:
<$list filter="[all[tiddlers]]">
(= if(days(tw_date({{!!modified}}), now())<2, {{!!title}}&", ", "") =)
</$list>

The fact that the output isn't wikified is pretty disadvantageous here, as it means you add <br/>...

Diego Mesa

unread,
Dec 21, 2017, 7:27:08 PM12/21/17
to TiddlyWiki
Hey Evan,

Is this expected:

  • IF([],'yes','no')
    • yes
  • IF([]=[],'yes','no')
    • no
  • IF([]='[]','yes','no')
    • no
My motivation for testing this: I have several fields that if present, trigger a footer to be displayed preceded by <hr/> tag. Recently, Ive had tiddlers with two or more of these fields, leaving me with more than one <hr/> which is undesirable. I was thinking of using this plugin to solve that. 

Evan Balster

unread,
Dec 21, 2017, 8:33:46 PM12/21/17
to TiddlyWiki
Hey, Diego —

Currently boolean expressions use JavaScript's concept of "truthyness" which is rather messy and not necessarily ideal.

Pending more sensible behavior in formulas, I recommend this:

(=  IF(count([some-filter-that-grabs-the-fields]) > 0, "<hr/>", "")  =)

That <hr/> won't actually wikify to a horizontal rule in the current plugin, but I expect to fix that in a new update tonight.

Diego Mesa

unread,
Dec 21, 2017, 8:36:51 PM12/21/17
to TiddlyWiki
Ah I see - sorry I remember you mentioning that previously I should have gone back to look that up. 

I'm still not sure why IF([]=[]) comes out false though. 

Thanks again for all your hard work

Diego

Evan Balster

unread,
Dec 21, 2017, 8:49:15 PM12/21/17
to TiddlyWiki
Hey, Diego —

The reason for ([]=[]) being false is pretty dumb and has to do with me leaving more up to JavaScript than I should (because internal implementation is pretty rough right now).

To summarize, [] is not interpreted as an empty list but a filter, and its result is every tiddler in the wiki.  Javascript equality comparison between these two large arrays returns false because they are separate objects (even though they have the same content).  It's a hot mess!

The EXACT function converts the arguments to strings before comparing them, and exact([], []) returns true.  But remember those aren't empty arrays!

@TiddlyTweeter

unread,
Dec 22, 2017, 10:51:15 AM12/22/17
to TiddlyWiki
Ciao Evan

A simple question I'm not sure or not if it deals with ...

Can it generate serial numbering?

Example Use Case: 12 Tiddlers, each of which, using your formulae, is a financial ledger for transactions for one month of the year for multiple expenses and incomes. Each transaction needs a serial number--starting from 1 for the first transaction in January (Italian accounting year is co-terminus with the calendar year). It would be best if this were automatically incremented. Manually applying them would be error prone. In book-keeping they are very useful. So that you can manually add them onto source documentation so that accountants can quickly locate the source for a record. In my use case I'd restart numbering at 1 each financial year.

Just wondering as I work with your plugin creating a real book-keeping system how to do this?

Very best wishes
Josiah

On Friday, 15 December 2017 05:37:26 UTC+1, Evan Balster wrote:
Hello, all —

I got fed up with the lack of good number-crunching capabilities in TiddlyWiki, and after griping about it for a year I fixed it.

Introducing the Formula plugin:  http://evanbalster.com/tiddlywiki/formulas.html  (currently version 0.1.2)

coda coder

unread,
Dec 22, 2017, 11:34:46 AM12/22/17
to TiddlyWiki
Hi Evan -- I have the exact same question...

I was hoping to apply the range operator but couldn't figure out the syntax.

<$list filter="[tag[x]range-magic-here[]]" variable=tid>

 <!-- now each iteration outputs title1, title2, title3 ... etc -->

</$list>

I figured maybe I need textjoin outside the filter?  But again... can't get my head around the two syntax "universes" ;)


Coda

Evan Balster

unread,
Dec 22, 2017, 12:33:50 PM12/22/17
to TiddlyWiki
Hey, Coda, Josiah —

You could try something like this:

<!-- Set a range from 1 to the number of items -->
<$formula-vars indexRange=" '1,' & count([myFilter]) ">
<!-- Go through the range... -->
<$list variable="index" filter="[range< indexRange >]">
<!-- Get the Nth element from the filter... -->

<$list filter="[myFilter] +[nth
<index>]">


#<
<index> = {{!!title}}


</$list>
</$list>
</$formula-vars>



In the future, Formulas should include some ability to go through arrays and apply a function to each item inside them, which would form a more efficient solution than the one here (which will scale up poorly because it runs myFilter once for each element in the list).

Last year I wrote a filter operator plugin called addposition that can be used to solve this same problem more efficiently.

@TiddlyTweeter

unread,
Dec 22, 2017, 1:58:04 PM12/22/17
to TiddlyWiki
Ciao Evan

Thankyou.

That's gonna work on one Ledger Tiddler at a time? Is there a way to get it seeded from a state Tiddler that gets incremented 1 each time that will always persist? Such that on Tiddler Ledger 2 it picks up numbering from where Tiddler Ledger 1 left off? Hope this is clear!

Not complaining. Just noting that the method you suggest will not fully support my use case which needs continuity between ledger pages (i.e. one Tiddler of transactions per month that continue sequential numbering over 12 "ledger Tiddlers", 1 "ledger Tiddler" per month for a year, each of which holds multiple sequentially numbered items).

As I look at and think about it more it is an interesting issue. Spreadsheet support is not quite the same as accounting. They overlap but are not identical. Accounting deals in discrete periods that are best handled in chunks like day, week, month or quarter. BUT they also need to handle cumulative carry-forwards between them and sequential enumeration that spans more than one of them.

Anyway I'm very grateful for what you done and working on seeing how to use it well for accounting.

Best wishes
Josiah

Evan Balster

unread,
Dec 22, 2017, 2:16:04 PM12/22/17
to TiddlyWiki
Hey, Josiah —

Sounds like this may be one of the cases where the $button and $action-setfield widgets come in handy, as a way to apply computed values permanently to some tiddlers.  It's usually good to write two versions of the code in these situations, where one displays the stuff you're generating and the other is a button that applies it.  Always be careful with programs like this so you don't nuke your data!

<$button>Apply Unique Ledger Numers
<!-- Set a range from 1 to the number of items -->
<$formula-vars indexRange=" '1,' & count([
myFilter]) ">
<!-- Go through the range... -->
<$list variable="index" filter="[range< indexRange >]">
<!-- Get the Nth element from the filter... -->
<$list filter="[
myFilter] +[nth<index>
]">
  <$action-setfield
ledger-number=<<index>>/>
</$list>
</$list>
</$formula-vars>
</$button>

coda coder

unread,
Dec 22, 2017, 3:16:09 PM12/22/17
to TiddlyWiki


On Friday, December 22, 2017 at 11:33:50 AM UTC-6, Evan Balster wrote:
In the future, Formulas should include some ability to go through arrays and apply a function to each item inside them, which would form a more efficient solution than the one here (which will scale up poorly because it runs myFilter once for each element in the list).


Yep, I see that.

 
Last year I wrote a filter operator plugin called addposition that can be used to solve this same problem more efficiently.


addposition was perfect for me, worked right out of the box!  And I agree, if the listWidget would pre-populate two other vars with pos and len (count) that would be excellent.

Many Thanks

Evan Balster

unread,
Dec 22, 2017, 6:41:25 PM12/22/17
to TiddlyWiki
  • Enhanced performance.
  • Add range Operator for counting.
  • FormulaWidget results are now wikified by default.
  • Made filter behavior more consistent with TiddlyWiki
    • Support compound filters with + and - (these break precedence rules).
    • Arrays now convert to strings in TiddlyWiki list format.
  • Implement escape sequences in String Literal.
    • \\\'\"\n\r\t\v\f\b\0\u1234 (unicode)
  • Add calendar functions: is_leap_year(y)days_in_year(y)days_in_month(y,m)
  • Add math functions: gcd and lcm
  • Fix support for (?igm) flags in regular expression strings.
  • Make regexextract and regexreplace search globally by default.
  • Make regexmatch and regexextract1 search non-globally by default.
  • Implement selective evaluation to save performance.
    • Logic functions supported: if
    • (Still experimenting with this, and may go in a very different direction).
  • Implement operand constructors for more flexible/performant functions.
Wikification of formula output opens up a bunch of doors for those willing to do some involved string processing.  Formulas is also getting fairly powerful as a tool for mining data with regular expressions (though the recent introduction of escape sequences makes these a little more burdensome to type out).

TonyM

unread,
Dec 22, 2017, 8:14:40 PM12/22/17
to TiddlyWiki
Evan,

For you
At https://evanbalster.com/tiddlywiki/formulas.html the Get your Plugin indicates the plugin is Version 0.1.0 although it is now 0.1.6

From me
Thanks so much for your work here, Looking ahead I can see dozens of features/solutions I wish to build, being supported by "formulas".

It seems this path you have taken is already removing barriers, that appeared in tiddlywiki  for some time, and providing shortcuts to others.

Of course the number of features are so rich I have had too little time to investigate and test how to solve some of my problems. But you have made my obsession with tiddlywiki even stronger.

You may of spent some time building this but that time is possibly small compared to the time I will now spend learning to leveraging it, not to mention that in the long run I will save time and reduce design to deployment times.

Be aware, I for one, and I presume many others, are very grateful for your work here. I can only wish you all the best in return and thank you deeply.

Regards
Tony

Evan Balster

unread,
Dec 22, 2017, 8:29:30 PM12/22/17
to TiddlyWiki
Hey, Tony —

Pleased to serve!  I'm building this with my own needs in mind foremost, but I happened to be in a situation where I could justify putting professional time into the project and make something fairly robust and feature-rich.  I get a lot of satisfaction out of putting together a nice tool, and it's a fun diversion from my larger project.  :)

The Get your Plugin indicates the plugin is Version 0.1.0 although it is now 0.1.6

Et tu, cache?  Try refreshing.

TonyM

unread,
Dec 22, 2017, 9:07:54 PM12/22/17
to TiddlyWiki
Evan,

Very small font, and 6 was, not easy to read. Sorry.

I am doing the same as you, investing a great deal of time in tiddlywiki for professional reasons and maximising my return to the community, I have a dozen solutions in Progress and Have not published any yet. 

If it interests you
The key one I am working on now, which is benefiting from your solution, thus I will need to bundle your plugin, is a "universal tiddler disposition tool". 
Be it code, macros, contacts, ideas, todo, book reading, book writing, reference notes etc... every tiddler can have or travel through various life cycles including reoccuring ones. 
I am providing a way to indicate the nature of each tiddler as it exists in the tiddlyverse, I am then providing canned listings according to these dispositions, which are largely date driven.

The theory is, with nothing more than describing what a given tiddler is via its disposition, then using tools I provide to query such dispositions the user effectively gains an unlimited number of solutions and applications.

For my business it turbo charges rapid development of solutions.

This is the virtuous circle of a healthy open source community.

Regards
Tony

Evan Balster

unread,
Dec 29, 2017, 6:59:55 PM12/29/17
to TiddlyWiki
Formula 0.1.7 released:  https://evanbalster.com/tiddlywiki/formulas.html

Changes:
  • Add math functions styled after GLSL for visual calculations
    • fractmodulo/modatan2clampmixstepsmoothstep
  • Add capture group index to regexextract and regexextract1 Functions.
    • EG. regexextract("cats, red cats, and blue cats", "([a-z]+) cats", 1) results in red and blue.
  • Fix FormulaWidget always parsing output in inline mode.
  • Add experimental $noRefresh option in FormulaVarsWidget.
    • This suppresses full-refreshing, resulting in a potentially significant performance boost (see) when variables change.
    • This can cause incorrect refresh behavior.
  • Add experimental support for Formulas as Tag Attributes.
    • Example: <td colspan=(= 2+2 =)/>
    • For now, this requires a second plugin that modifies the TiddlyWiki core!
    • I've started a Pull Request that would add official support to TiddlyWiki core for extensions like this.
The changes here mostly have to do with things I've been interested in lately — specifically explorable explanations with SVG rendering and datamining TiddlyWiki's source code with regular expressions.

TonyM

unread,
Dec 29, 2017, 8:47:37 PM12/29/17
to TiddlyWiki
Evan,

Thanks for another update.

FYI: I drag this to my wiki and it is named untitled until I hit the import button, not sure but there may be a plugin setting needing update.

Also; 

I am trying to see if I can get the following to work, basicaly as a version of Formulas as Tag Attributes

Total days between, with a progress bar of days so far relative to today

\define showtodayrange(datefield1,datefield2)
<progress value="(= days( date( {{!!$datefield1$}} ) , now() ) =)" max="(= days( date( {{!!$datefield1$}} ) , date( {{!!$datefield2$}} )) =)"></progress> 
\end

Regards
Tony

Evan Balster

unread,
Dec 29, 2017, 9:07:44 PM12/29/17
to TiddlyWiki
Hello, Tony —

Assuming you have both the formula plugin and the attribute-modules plugin installed, un-quoting your attributes will make them into formulas (instead of literal strings):

\define showtodayrange(datefield1,datefield2)
<progress
    value
=(= days( date( {{!!$datefield1$}} ) , now() ) =)
    max
=(= days( date( {{!!$datefield1$}} ) , date( {{!!$datefield2$}} )) =)/>
\end

The attribute-modules plugin is really just a stand-in for my core pull request, and the "safer" way to do this is to use the <<formula ...>> macro instead of the direct syntax.  In this case you do quote the formula, but you don't include the mushroom brackets:

\define showtodayrange(datefield1,datefield2)
<progress
    value
=<<formula "days( date( {{!!$datefield1$}} ) , now() )">>
    max
=<<formula "days( date( {{!!$datefield1$}} ) , date( {{!!$datefield2$}} ))">>/>
\end

Gets me thinking about how I'd like to add some more tiddlywiki-oriented functions like transclude(tiddlerName, fieldName) and filter(expressionString) to formulas...

TonyM

unread,
Dec 29, 2017, 10:16:00 PM12/29/17
to TiddlyWiki
Evan,

That works like a dream. Thank you.

As you say "tiddlywiki-oriented functions" here are some that come to mind I am trying to identify based on the current implementation

if then else or other logical operators to transclude a tiddler, or include content.

For example hiding or displaying content based on logic from prior answers or calculations.

I am currently building a couple of macros to provide buttons with the ability to increment a date by N days, weeks months etc... 
My Problem is ensuring the result not the formula is returned. I have calculated using formulas the new date and still struggling to right this back to the input date field.
I think this already possible I am just trying to workout how to do it, and as simply as possible.

Here is a snipit that is not working.

\define commitdateaction(label,datefield,update)
<$button tooltip="Change $datefield$ to $update$" class="tc-btn-invisible tc-tiddlylink" >
     <$action-setfield $field="$datefield$" $value="$update$"/>     
      $label$
</$button>
\end

\define dateincrements(datefield,inc:"D W F M Q H Y")
<$set name=indate value="(= tw_date( {{!!$datefield$}} ) =)">
<!-- Main Loop -->
<$list filter="$inc$" variable=period>
    <$list filter="[<period>prefix[D]]" variable=incperiod>
    <!-- Day -->
          <$set name=multiple value="1">
          <$set name=label value="(={{!!dateinc}}*<<multiple>>=)<<incperiod>>">
          <$set name=newdate value="(=to_tw_date(add_days(<<indate>>, <<multiple>>*{{!!dateinc}}))=)" >
               <$macrocall $name="commitdateaction" label="<<label>>" datefield=$datefield$ update=<<newdate>> />
           </$set>
           </$set>
           </$set>
    </$list>
....

<$select field=dateinc default='1'>
    <$list filter='1 2 3 4 5 6 12' >
       <option value=<<currentTiddler>>><$view field='title'/></option>
    </$list>
</$select>
<!---
<$select field=dateincdec default='+'>
       <option value="+">+</option>
       <option value="-">-</option>
</$select>
Save and Provide Reset
-->
</$set>
           <<newdate>>
\end

Regards
Tony
Last year I wrote a filter operator plugin called <a href="https://groups.google.com/forum/#!topic/tiddlywiki/13_TTJqEEiw" rel="nofollow" target="_blank" onmousedown="this.href='https://groups.google.com/forum/#!topic/tiddlywiki/13_TTJqEEiw';return t

TonyM

unread,
Dec 29, 2017, 10:22:33 PM12/29/17
to TiddlyWiki
Post Script,

Of note is being able to add calculations to elements in TiddlyWiki and HTML which would otherwise be controlled using java script which is not so accessible to a novice in TiddlyWiki.

Keep up the good work.
Tony
On Friday, 22 December 2017 14:16:09 UTC-6, coda coder wrote:<blockquote class="gmail_quote" style="margin:0;

Evan Balster

unread,
Dec 29, 2017, 10:30:31 PM12/29/17
to TiddlyWiki
Hey, Tony —

The trouble in your case is that you're putting the formulas in quotes, which makes TiddlyWiki treat them as strings.  The experimental syntax for attribute values is just <tag attribute=(= 2+2 =) /> — no quotes outside the mushroom brackets.  Generally I use the formula-vars widget when I want to set one or more variables to formula-computed values.  You could use the vars widget with the new syntax for the same effect...

Be mindful of how you format the date strings, too (or use to_tw_date).

Things I'm thinking about right now:
  • "if" and "else" widgets that work with formulas and switch their content on and off.
  • Functions to query transclusions/filters/variables with string arguments
    • eg. transclude(<<otherTiddler>>, "this-field")
    • eg. filter("[range[1," & <<rangeMax>> & "]]")
    • eg. variable("item" & <<index>>)
  • Functions to grab transclusions/variables as raw text rather than formula data.
    • Might make the functions above do this, and add a "datum" function that emulates the behavior of the direct syntax.

TonyM

unread,
Dec 29, 2017, 10:46:46 PM12/29/17
to TiddlyWiki
Evan,

I will heed your advice.

Sounds good what you are working on.

I am not sure if it is important to you but I was reading an explanation for formats in filters where we use <variable> rather than <<variable>> and {!!fieldname} was used in place of [{{!!fieldname}}] because when not in wiki text the << >> and {{  }} is used to avoid clashing with HTML. I would assume as a rule you will need to adopt one or the other rule for inside formulas and state it as such in documents.

In your above suggestions you are already adopting the double brackets, I expect you should stick with that and regular filters retain their exceptional rules, but what happens when people use your legal format in filters or filters in your legal formats?

Food for thought, no need to reply.

Regards
Tony

Evan Balster

unread,
Dec 29, 2017, 10:56:08 PM12/29/17
to TiddlyWiki
Heheh, well, I'll reply anyway.

The single vs. double format for variables and transclusions is another thing I've thought about for the plugin.  Right now, formulas use the WikiText syntax (double brackets) for transcluded and variable values, and this helps with general consistency.  Filter expressions inside formulas still use the single-bracket syntax, as they do everywhere else.

I've considered allowing the shorter <single-bracket> style anywhere in formulas, and there isn't much stopping me on a technical level, but I worry that supporting two styles might create more confusion than it's worth.  Better to stay similar to WikiText, in my mind...

PMario

unread,
Dec 30, 2017, 6:37:37 AM12/30/17
to TiddlyWiki
On Saturday, December 30, 2017 at 4:56:08 AM UTC+1, Evan Balster wrote:
I've considered allowing the shorter <single-bracket> style anywhere in formulas, and there isn't much stopping me on a technical level, but I worry that supporting two styles might create more confusion than it's worth. 

Better to stay similar to WikiText, in my mind...

IMO that's the right decision. I think consistency is key here!
-m

TonyM

unread,
Dec 30, 2017, 8:31:27 PM12/30/17
to TiddlyWiki
Totaly Agree

Let us state it upfront

Formula uses wiki text references except in Filters where the modified form also matches normal TiddlyWiki filter syntax.

Regards
Tony

Diego Mesa

unread,
Jan 8, 2018, 12:55:38 PM1/8/18
to TiddlyWiki
Hello all,

Just want to ping the community and see if anyone has had any cool uses they wouldn't mind sharing? 

Diego

Evan Balster

unread,
Jan 8, 2018, 2:35:02 PM1/8/18
to TiddlyWiki
Hello, Diego —

You can find a few curiosities hidden in the formulas wiki if you search "demo".

My impetus for building the formulas plugin was a "work journal" application I wanted to build for archiving and visualizing my time usage over a period of years (see the attached image).  That application also uses my condition and CSV unpacker plugins.
Screen Shot 2018-01-05 at 4.08.14 PM.png

Diego Mesa

unread,
Jan 8, 2018, 2:58:22 PM1/8/18
to TiddlyWiki
Wow! That looks awesome! hopefully one-day you'll share that as well!

Best,
Diego

Michael Wiktowy

unread,
Jan 9, 2018, 5:08:50 PM1/9/18
to TiddlyWiki
Thank you, Evan! This was a perfect and intuitive fit for my invoicing system.

/Mike

BurningTreeC

unread,
Jan 13, 2018, 1:04:52 AM1/13/18
to TiddlyWiki
Hi Evan,

I'm trying your plugin now and I've seen that the modulo function doesn't work as I expect,

maybe I'm doing something wrong or there's a bug

all the best,
Simon

Evan Balster

unread,
Jan 13, 2018, 11:41:00 AM1/13/18
to TiddlyWiki
Hello, Simon —

The latest version of Formula has some implementation errors in the modulo, trim and subtitute functions.  These have been found and patched, but the change isn't yet released, as I'm working on some major enhancements for release today or tomorrow.

Added a GitHub issue to document this:  https://github.com/EvanBalster/TiddlyWikiFormula/issues/15

BurningTreeC

unread,
Jan 13, 2018, 1:43:58 PM1/13/18
to tiddl...@googlegroups.com
The latest version of Formula has some implementation errors in the modulo, trim and subtitute functions.  These have been found and patched, but the change isn't yet released, as I'm working on some major enhancements for release today or tomorrow.

thanks Evan, I've only seen that and thought I'll mention it, maybe it helps

I'm also trying the regexreplace function but can't get it to work as I want, the first operand gets accepted if written in quotes but then the input has also to be wrapped in quotes to be replaced:

like: input: (= Hello, "Hello", "Goodbye" =) --> nothing     ... but: (= "Hello", "Hello", "Goodbye" =) --> Goodbye       .. (= Hello, Hello, "Goodbye" =) --> nothing

I guess I'm doing something wrong because I totally don't get regex or there's a small glitch somewhere


good weekend,
Simon

BurningTreeC

unread,
Jan 13, 2018, 1:50:31 PM1/13/18
to TiddlyWiki
Evan, you know what? I solved it reading what I posted :D

thanks for this plugin - I think now I kinda get it

it's huge

have a nice weekend

ste...@gmail.com

unread,
Jan 13, 2018, 2:28:30 PM1/13/18
to TiddlyWiki
Hi Evan, 

I just ran into a weird problem. When I enter

(= sum(1.5,1.2,2,0.9) =)

(= 2+1.2+0.9+1.5 =)

I get 5.6000000000000005 as a result (instead of 5.6). If I change the numbers slightly, I get the correct result. 

Is this a bug, or is there a well known explanation I'm not aware of?

Kind regards,

Stef

Evan Balster

unread,
Jan 13, 2018, 3:09:28 PM1/13/18
to TiddlyWiki
Hey, all —

I get 5.6000000000000005 as a result (instead of 5.6).

Right now formula uses the JavaScript style for displaying numbers by default, and it's pretty terrible.  The inaccuracy is "floating point" error and any reasonable system would round it off somehow.  To get rid of it, refer to the "fixed" and "precision" options in FormulaWidget:  http://evanbalster.com/tiddlywiki/formulas.html#FormulaWidget

I'm probably going to change how numbers are formatted, likely using numeral.js or something like it.  This is one of a few compatibility-breaking changes I'm thinking about for the big update.

coda coder

unread,
Jan 13, 2018, 4:25:29 PM1/13/18
to TiddlyWiki
Ah, the joys of IEEE-754...

<$if "anyone wants to see the gory details of fp in javascript (and a slew of other languages all of which are dependent on today's CPUs)">
  https://www.h-schmidt.net/FloatConverter/
</$if>

:)

Evan Balster

unread,
Jan 15, 2018, 12:05:05 AM1/15/18
to TiddlyWiki

This one's a doozie...  Changelog:

A substantial re-write of the formulas plugin that introduces various improvements and improves support for functional programming. Various minor compatibility-breaking changes were made.

  • Introduced (lambda) functions and formula-local variables.
    • Added let construct for making local variables.
    • Added function declaration. Closures are not supported yet.
  • Added map function for manipulating array elements.
  • Improved number formatting.
    • Default number formatting no longer displays tiny imprecisions.
    • Number formats may be specified with numeral.js, enabling thousands separators, k/m/b notation and greater control over digits.
    • Renamed some FormulaWidget and FormulaVarsWidget attributes.
    • Original number formatting can still be used by specifying precision (no value).
  • Enhanced support for imported values.
    • Added Functions for importing values as text: transcludetransclude_indexvariable
    • Added datum function for interpreting text as a Datum.
    • Datum parsing now recognizes qualifying 14- and 17-digit numbers as TiddlyWiki dates. (eg. created & modified fields).
  • Widgets now display errors in the TiddlyWiki stylelike this.
    • $formula-vars will display any errors instead of its normal content.
    • $formula uses tc-error styling.
  • Value conversion behaviors have changed.
    • Non-array values will not be treated as single-element arrays.
  • Enhanced array functions sumaverageproduct and count.
    • Multi-dimensional array values are properly supported.
    • count ignores empty values.
    • New function counta counts empty values.
  • Internal implementation was changed. This will break customizations.
    • Consolidated "Node" type replaces Operator, Operand and Value.
    • Removed Value "boxing" and percentage values.
    • Implemented a new type cast mechanism, making custom JavaScript functions simpler to write.
    • Computation now uses a "context" object.
  • Fixed doc error: $noRebuild option is not called $noRefresh
  • The substitute and trim functions now process all occurrences, not just one.
  • Fixed implementation of the modulo function.
  • The % operator no longer affects display style.
    • Use a format string instread.
  • +-add and subtract no longer auto-sum their operands.
    • Use sum instead.

General remarks:  This makes formula a lot more powerful, especially for iterating through arrays with the MAP function.  I might investigate even more flexible ways to use that later.  The absence of proper closures does make functions and locals less useful as they could be, as local variables can't currently be used inside the function supplied to MAP.

For a simple example of a computation that wasn't possible before, see the Line Graph demo:  http://localhost:8080/#Demo%3A%20Line%20Graph

TonyM

unread,
Jan 15, 2018, 12:20:53 AM1/15/18
to TiddlyWiki
Evan

Thanks once again. I will start using ASAP.

FYI Link dead (ie no tiddler)  http://localhost:8080/#Demo%3A%20Line%20Graph

Regards
Tony

Evan Balster

unread,
Jan 15, 2018, 12:27:31 AM1/15/18
to TiddlyWiki
Huh, maybe localhost is down.  :)


Generating SVG paths in TiddlyWiki is something I've been wanting for ages...  It was possible in a limited capacity with wikify before, but this makes it a lot more practical.

TonyM

unread,
Jan 15, 2018, 1:32:42 AM1/15/18
to TiddlyWiki
Evan,

I dragged the new version plugin to two different wikis, one saved and reloaded OK.

The Other will not reload, nor does safemode work, giving the following error.

Internal JavaScript Error

Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser
Error executing boot module $:/core/modules/widgets/attributes/macro.js: "Cannot find module named '$:/plugins/ebalster/formula/operands.js' required by module '$:/core/modules/widgets/attributes/macro.js', resolved to $:/plugins/ebalster/formula/operands.js" undefined

From where I can go no where.

I am trying to fix the wiki now but just wanted to let you know.

I installed a couple of your other plugins previously the attribute and if.else plugins if they may have something to do with it.

I am not so sure how to toggle a plugin enabled to disable when editing the tiddlywiki file directly, to eliminate your plugin.

Regards
Tony
It is loading more messages.
0 new messages