# gaza-stats A Clojure library designed to explore donations data for people in Gaza whose accounts have been verified by the [Gaza Verified volunteers](gaza-verified.org/team/). ![Graph of donations between April 2024 and today](all-donations.png) ## Dependencies * [Leiningen](https://leiningen.org/) * [Clojure](https://clojure.org/) * [cljc.java-time](https://github.com/henryw374/cljc.java-time) * [SQL Korma](https://web.archive.org/web/20190223025406/http://www.sqlkorma.com/) * [clj-xchart](https://github.com/hypirion/clj-xchart) ## Usage This is a very experimental, unfinished and unpolished library designed for use with leiningen. To use, clone this repository, connect to the directory into which you cloned it, and type `lein repl`. At present several useful functions are implemented: ## gaza-stats.core Functions to interrogate the [`gaza.onl`](https://gaza.onl/app.db) database. ### accounts-with-donations-by-date-range ``` (accounts-with-donations-by-date-range start-date end-date) ``` Return a list of maps, each representing one account from the `gaza.onl` database, with a key `:donations`, whose value is a float representing the total donations received by that account between the dates `start-date` (exclusive) and `end-date` (inclusive). Date arguments should be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L108) ### active-accounts ``` (active-accounts date) ``` Return, as an integer, the number of accounts believed to have been active on this `date`, which should be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd` [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L97) ### average-donations-received-by-month ``` (average-donations-received-by-month start-date end-date) ``` Return data as a map keyed by the date of the first of each month between `start-date` and `end-date`; the values are maps with keys `:average`, `:count` and `:total`. Arguments should be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L128) ### db **TODO**: write docs [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L17) ### db-spec Database specification in a format which can be used with either JDBC or Korma. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L10) ### enhance-account-with-donations ``` (enhance-account-with-donations account-map sd ed) ``` Take this `account_map`, which must at least have a valid value for the key `:campaign_url` and return a similar map including the key `:donations`, whose value is a float representing the total donations received by that campaign URL between the dates `sd` (exclusive) and `ed` (inclusive). Date arguments should be supplied as `java.time.LocalDate` objects. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L81) ### local-date->date #### macro ``` (local-date->date x) ``` Construct and return a new `java.util.Date` object from a `java.time.LocalDate` object. As usual, doing anything with Java time/date stuff is a complete bureaucratic nightmare. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L72) ### local-date? #### macro ``` (local-date? x) ``` Is this `x` an instance of `java.time.LocalDate`? [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L21) ### normalise-date #### macro ``` (normalise-date date default) ``` More messing around with Java’s bizarre mess of date/time classes. We want our default date representation to be `java.time.LocalDate`, except, of course, when we don’t. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L26) ### total-donations-by-weeks `(total-donations-by-weeks start-date)``(total-donations-by-weeks start-date end-date)` Return a list of pairs `[java.time.LocalDate date, float amount]` representing the total of donations made between `start-date` and `end-date`. Arguments may be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. If `end-date` is not supplied, data for a single week will be returned. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/core.clj#L43) ## gaza-stats.chart Produce charts from data functions in other namespaces. ### chart-accounts-with-donations-by-months-in-range ``` (chart-accounts-with-donations-by-months-in-range start-date end-date) ``` Return a chart with one line for each calendar month covering from `start-date` (inclusive) to `end-date` (inclusive). Arguments should be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`, showing donations as for `chart-donations-by-accounts-in-date-range`, q.v. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/chart.clj#L58) ### chart-average-donations-received-by-month ``` (chart-average-donations-received-by-month start-date end-date) ``` Return a chart comparing the average donations received per account with the total number of active accounts per month between `start-date` and `end-date`. Arguments should be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/chart.clj#L76) ### chart-donations-as-percentage-in-date-range ``` (chart-donations-as-percentage-in-date-range start-date end-date) ``` Return a chart of donations received by individual accounts between `start-date` (exclusive) and `end-date` (inclusive). Arguments should be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. Accounts are identified in the chart only by rank order. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/chart.clj#L45) ### chart-donations-by-accounts-in-date-range ``` (chart-donations-by-accounts-in-date-range start-date end-date) ``` Return a chart of donations received by individual accounts between `start-date` (exclusive) and `end-date` (inclusive). Arguments should be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. Accounts are identified in the chart only by rank order. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/chart.clj#L35) ### chart-donations-by-donor `(chart-donations-by-donor start-date end-date key)``(chart-donations-by-donor start-date end-date key exclude-anons)` Return a rank-ordered graph of the values of this `key` in the `donations-by-donor` data between this `start-date` and this `end-date`. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/chart.clj#L88) ### chart-donations-by-weeks ``` (chart-donations-by-weeks start-date end-date key) ``` Create and return an XY chart of data on field represented by `key` of donations made between `start-date` and `end-date`. Arguments may be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/chart.clj#L11) ### chart-number-donations-by-weeks ``` (chart-number-donations-by-weeks start-date end-date) ``` Create and return an XY chart of data on number of donations made between `start-date` and `end-date`. Arguments may be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/chart.clj#L28) ### chart-total-donations-by-weeks ``` (chart-total-donations-by-weeks start-date end-date) ``` Create and return an XY chart of data on total donations made between `start-date` and `end-date`. Arguments may be supplied as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`. [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/chart.clj#L21) ## gaza-stats.donors Statistics on donors. ### donations-by-donor ``` (donations-by-donor start-date end-date) ``` Return a sequence of maps, one representing each donor who has donated between `start-date` and `end-date`, each with keys `:count`, `:donor` and `:total` [view source](https://git.journeyman.cc/simon/gaza-stats/src/branch/main/src/gaza_stats/donors.clj#L6) ### Viewing charts In your REPL, invoke `(require '[com.hypirion.clj-xchart :refer [view]])`. You can then invoke `view` on a chart returned by the above function, for example: ```clojure (view (chart-total-donations-by-weeks "2024-04-01" "2026-09-20")) ``` ### Saving charts as graphics files Again, xchart provides facilities for saving charts as graphics files. To do this, in your REPL first invoke `(require '[com.hypirion.clj-xchart :refer [spit]])`. This will, obviously, over-ride `clojure,core/spit`. You can now save a chart as a graphic using, e.g.: ```clojure (spit (chart-accounts-with-donations-by-months-in-range "2025-01-01" "2025-12-31") "donations-by-months-2025.svg") ``` The graphics format will be taken from the file extension, and at least all of `bmp`, `gif`, `jpg`, `png`, and, most importantly, `svg` are supported. The SVG is properly constructed as a drawing rather than as a raster, although there is no semantic labelling of the nodes or edges, which is disappointing. ## NOTE: Data This code is designed to explore data in a [SQLite](https://www.sqlite.org/) database which it expects to be called `app.db` and find in its `resources` directory. This database is not included in this repository but may be downloaded from [here](https://gaza.onl/app.db). ## NOTE: Currency of `amount` column The `campaign_donations` table has a column `amount`. I don't have any documentation on what currency the column is denominated in, but by inspecting my own donations, which I know to be in Pounds Sterling, I infer the column is probably denominated in US Dollare. ## NOTE: Use of SQL Korma I used SQL Korma in this project because I know it and I like it, but it is no longer maintained and its website is no longer online. The last version I could find on the Internet Archive is [here](https://web.archive.org/web/20190223025406/http://www.sqlkorma.com/). The source code is on [Github](https://github.com/korma/Korma). It might be better to rewrite so as not to use it, especially given that (at present) the SQL usage is trivial. ## License Copyright © 2026 Simon Brooke. This program and the accompanying materials are made available under the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.