gaza-stats/README.md

255 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.