dataframe-toolkit 0.11.1__tar.gz → 0.11.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/PKG-INFO +126 -19
  2. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/README.md +124 -18
  3. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/pyproject.toml +2 -1
  4. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/pyproject.toml.orig +2 -1
  5. dataframe_toolkit-0.11.3/src/dftk/commands/eval_cmd.py +409 -0
  6. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/query_cmd.py +22 -0
  7. dataframe_toolkit-0.11.3/src/dftk/common/evalfuncs.py +439 -0
  8. dataframe_toolkit-0.11.1/src/dftk/commands/eval_cmd.py +0 -831
  9. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/__init__.py +0 -0
  10. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/cli.py +0 -0
  11. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/__init__.py +0 -0
  12. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/annotate_cmd.py +0 -0
  13. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/base.py +0 -0
  14. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/binx_cmd.py +0 -0
  15. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/chi_cmd.py +0 -0
  16. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/clean_cmd.py +0 -0
  17. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/cleannames_cmd.py +0 -0
  18. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/concat_cmd.py +0 -0
  19. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/corr_cmd.py +0 -0
  20. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/dataset_cmd.py +0 -0
  21. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/describe_cmd.py +0 -0
  22. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/explode_cmd.py +0 -0
  23. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/fit_cmd.py +0 -0
  24. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/func_cmd.py +0 -0
  25. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/help.py +0 -0
  26. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/hist_cmd.py +0 -0
  27. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/implode_cmd.py +0 -0
  28. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/info_cmd.py +0 -0
  29. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/interp_cmd.py +0 -0
  30. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/line_cmd.py +0 -0
  31. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/melt_cmd.py +0 -0
  32. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/merge_cmd.py +0 -0
  33. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/pivot_cmd.py +0 -0
  34. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/print_cmd.py +0 -0
  35. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/randvar_cmd.py +0 -0
  36. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/sample_cmd.py +0 -0
  37. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/scale_cmd.py +0 -0
  38. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/scat_cmd.py +0 -0
  39. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/segid_cmd.py +0 -0
  40. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/split_cmd.py +0 -0
  41. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/stat_cmd.py +0 -0
  42. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/test_cmd.py +0 -0
  43. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/transpose_cmd.py +0 -0
  44. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/commands/wstat_cmd.py +0 -0
  45. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/common/__init__.py +0 -0
  46. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/common/copula.py +0 -0
  47. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/common/io.py +0 -0
  48. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/common/plot.py +0 -0
  49. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/common/seed.py +0 -0
  50. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/common/seq.py +0 -0
  51. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/common/stats.py +0 -0
  52. {dataframe_toolkit-0.11.1 → dataframe_toolkit-0.11.3}/src/dftk/io.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dataframe-toolkit
3
- Version: 0.11.1
3
+ Version: 0.11.3
4
4
  Summary: A command-line toolkit for DataFrame analysis and manipulation
5
5
  Keywords: dataframe,statistics,data analysis,CLI,TSV,pandas
6
6
  Author: Gunnar Pálsson
@@ -20,6 +20,7 @@ Requires-Dist: statsmodels>=0.14
20
20
  Requires-Dist: patsy>=0.5.6
21
21
  Requires-Dist: duckdb>=0.8
22
22
  Requires-Dist: matplotlib>=3.7
23
+ Requires-Dist: pillow>=13.0
23
24
  Requires-Dist: seaborn>=0.12
24
25
  Requires-Dist: tqdm>=4.65
25
26
  Requires-Python: >=3.12
@@ -226,35 +227,141 @@ printf "sample\tfluor\ns1\t60\ns2\t110\n" \
226
227
 
227
228
  ### Filling missing values
228
229
 
229
- `eval -f` takes pandas column methods (`COL.method(...)`), and `fillna`,
230
- `ffill`, `bfill` and `interpolate` fill empty cells. Defaults from another
231
- table, after a merge (a column in both files gets the suffix `_r`):
230
+ `eval -f` takes pandas column methods (`COL.method(...)`); `fillna`,
231
+ `ffill`, `bfill` and `interpolate` fill empty cells and keep the others.
232
+
233
+ | Formula | Fills with |
234
+ |---|---|
235
+ | `x = x.fillna(y)` | the value in column `y` |
236
+ | `x = x.fillna(0)`, `sex = sex.fillna('unknown')` | a fixed value |
237
+ | `x = x.fillna(y).fillna(0)` | `y` first, then 0 |
238
+ | `x = x.fillna(x.groupby(g).transform('mean'))` | the mean of the row's group (or `'median'`, ...) |
239
+ | `x = x.ffill()` / `x = x.bfill()` | the value above / below (`ffill(limit=1)`: at most one row) |
240
+ | `x = x.groupby(g).ffill()` | the value above, within each group of `g` |
241
+ | `x = x.interpolate()` | a straight line between the values above and below, by row position |
242
+
243
+ Write to a new column (`x_filled = x.fillna(y)`) to keep the original, and
244
+ mark the gaps first (`missing = x.isna()`) to tell filled values apart.
245
+ Only empty cells are filled: a missing row (a year with no row at all) is
246
+ not added.
247
+
248
+ **Defaults from another table.** A column that is in both files gets the
249
+ suffix `_r` from `merge`; fill from it, then drop it. Here the defaults are
250
+ each species' median body mass:
232
251
 
233
252
  ```bash
234
- dftk merge data.tsv -r defaults.tsv -k type -t left -o \
235
- | dftk eval ... -f "depth = depth.fillna(depth_r)" --drop depth_r
253
+ dftk dataset penguins -o | dftk pivot ... -i species -v body_mass_g \
254
+ -f median --move median_body_mass_g:body_mass_g -o defaults.parquet
255
+ dftk dataset penguins -o \
256
+ | dftk merge ... -r defaults.parquet -k species -t left -o \
257
+ | dftk eval ... -f "body_mass_g = body_mass_g.fillna(body_mass_g_r)" \
258
+ --drop body_mass_g_r
236
259
  ```
237
260
 
238
- The group mean, a fixed value, or the last value above (`ffill`) within
239
- each group:
261
+ **From neighbouring rows** (`co2` is a weekly series with gaps):
240
262
 
241
263
  ```bash
242
- dftk dataset penguins -o | dftk eval ... \
243
- -f "mean = body_mass_g.groupby(species).transform('mean')" \
244
- -f "body_mass_g = body_mass_g.fillna(mean)" --drop mean \
245
- -f "sex = sex.fillna('unknown')"
264
+ dftk dataset co2 -o | dftk eval ... -f "ffill = co2.ffill()" \
265
+ -f "bfill = co2.bfill()" -f "linear = co2.interpolate()"
266
+ ```
267
+
268
+ `ffill` leaves the first rows empty and `bfill` the last ones;
269
+ `x.ffill().fillna(x.bfill())` fills both. `interpolate()` counts one step
270
+ per row, so the rows must be evenly spaced; for an x-based lookup from a
271
+ reference curve, see `dftk interp`.
246
272
 
273
+ **Row order and groups.** These methods use the rows in the order they are
274
+ in. Sort first, in a step of its own: `--sortasc` applies to a command's
275
+ output, so in the same command it would come after the fill. When a table
276
+ holds several series (sites, countries, samples), fill within each group,
277
+ or values are taken from the neighbouring group. Rows of a group don't need
278
+ to be next to each other, but within each group they must be in order:
279
+
280
+ ```bash
247
281
  dftk dataset healthexp -o \
248
- | dftk eval ... -f "le = Life_Expectancy.where(Year % 10 != 5)" -o \
282
+ | dftk eval ... -f "le = Life_Expectancy.where(Year % 10 != 5)" \
283
+ --sortasc Country Year -o \
249
284
  | dftk eval ... -f "le_filled = le.groupby(Country).ffill()"
250
285
  ```
251
286
 
252
- `ffill`, `bfill` and `interpolate` use the rows in the order they are in:
253
- sort in a step of its own first (`dftk eval data.tsv --sortasc site day -o
254
- | dftk eval ... -f ...`), and use `groupby(...)` when the table holds
255
- several series, or values are taken from the neighbouring group.
256
- `interpolate()` has no grouped form and works by row position. `dftk eval
257
- -h` covers these cases, with examples.
287
+ `interpolate()` has no grouped form. Once each group's rows are together,
288
+ gaps inside a group are right, but a gap at a group's start or end is
289
+ filled from the neighbouring group. To leave those empty, keep only values
290
+ with something before and after them in the same group:
291
+
292
+ ```bash
293
+ dftk dataset healthexp -o \
294
+ | dftk eval ... -f "le = Life_Expectancy.where(Year % 10 != 5)" \
295
+ --sortasc Country Year -o \
296
+ | dftk eval ... -f "before = le.groupby(Country).ffill().notna()" \
297
+ -f "after = le.groupby(Country).bfill().notna()" \
298
+ -f "le_linear = le.interpolate().where(before & after)" \
299
+ --drop before after
300
+ ```
301
+
302
+ ### Differences between rows
303
+
304
+ For the change in a column from one row to the next, `eval -f` takes
305
+ pandas `diff()` and `pct_change()`, also within groups. They use the rows
306
+ in their order, so sort first, in a step of its own:
307
+
308
+ ```bash
309
+ dftk dataset healthexp -o | dftk eval ... --sortasc Country Year -o \
310
+ | dftk eval ... -f "change = Spending_USD.groupby(Country).diff().round(1)" \
311
+ -f "pct = (Spending_USD.groupby(Country).pct_change() * 100).round(1)" \
312
+ -f "years = Year.groupby(Country).diff()"
313
+ ```
314
+
315
+ ```text
316
+ Year Country Spending_USD Life_Expectancy change pct years
317
+ 1971 Canada 313.391 72.8
318
+ 1976 Canada 543.337 73.8 229.9 73.4 5.0
319
+ 1979 Canada 692.269 75.1 148.9 27.4 3.0
320
+ 1980 Canada 791.812 75.2 99.5 14.4 1.0
321
+ ```
322
+
323
+ The first row of each country gets an empty cell. Without
324
+ `groupby(Country)`, it would be compared with the last row of the
325
+ previous country.
326
+
327
+ To compare a value with one in another column of the previous or next row, for example the
328
+ gap between segments given by `Chr`, `Begin`, `End`, use SQL's `LAG()` /
329
+ `LEAD()` in `query --sql`:
330
+
331
+ ```bash
332
+ dftk query segments.tsv --sql \
333
+ 'SELECT *, "Begin" - LAG("End") OVER (PARTITION BY Chr ORDER BY "Begin")
334
+ AS gap
335
+ FROM data ORDER BY Chr, "Begin"'
336
+ ```
337
+
338
+ ```text
339
+ Chr Begin End Id gap
340
+ chr1 100 200 a
341
+ chr1 250 400 b 50
342
+ chr1 390 500 c -10
343
+ chr2 50 80 d
344
+ chr2 100 300 e 20
345
+ ```
346
+
347
+ A negative gap is an overlap, and the first segment on each chromosome
348
+ gets an empty cell. `lead("Begin") OVER (...) - "End"` gives the gap to
349
+ the next segment instead.
350
+
351
+ - `Begin` and `End` are SQL keywords: quote such column names with double
352
+ quotes and the whole statement with single quotes.
353
+ - No sorting is needed first; `ORDER BY` inside `OVER` sets the order.
354
+ - Integers stay integers.
355
+
356
+ `eval -f` can do the same with pandas `shift`, but it goes by row order, so
357
+ sort by `Chr` and `Begin` first (results are floats):
358
+
359
+ ```bash
360
+ dftk eval segments.tsv -f 'gap = Begin - End.groupby(Chr).shift()'
361
+ ```
362
+
363
+ Without `groupby(Chr)` the first segment of a chromosome is compared with
364
+ the last one of the previous chromosome.
258
365
 
259
366
  ### Bootstrap confidence intervals
260
367
 
@@ -197,35 +197,141 @@ printf "sample\tfluor\ns1\t60\ns2\t110\n" \
197
197
 
198
198
  ### Filling missing values
199
199
 
200
- `eval -f` takes pandas column methods (`COL.method(...)`), and `fillna`,
201
- `ffill`, `bfill` and `interpolate` fill empty cells. Defaults from another
202
- table, after a merge (a column in both files gets the suffix `_r`):
200
+ `eval -f` takes pandas column methods (`COL.method(...)`); `fillna`,
201
+ `ffill`, `bfill` and `interpolate` fill empty cells and keep the others.
202
+
203
+ | Formula | Fills with |
204
+ |---|---|
205
+ | `x = x.fillna(y)` | the value in column `y` |
206
+ | `x = x.fillna(0)`, `sex = sex.fillna('unknown')` | a fixed value |
207
+ | `x = x.fillna(y).fillna(0)` | `y` first, then 0 |
208
+ | `x = x.fillna(x.groupby(g).transform('mean'))` | the mean of the row's group (or `'median'`, ...) |
209
+ | `x = x.ffill()` / `x = x.bfill()` | the value above / below (`ffill(limit=1)`: at most one row) |
210
+ | `x = x.groupby(g).ffill()` | the value above, within each group of `g` |
211
+ | `x = x.interpolate()` | a straight line between the values above and below, by row position |
212
+
213
+ Write to a new column (`x_filled = x.fillna(y)`) to keep the original, and
214
+ mark the gaps first (`missing = x.isna()`) to tell filled values apart.
215
+ Only empty cells are filled: a missing row (a year with no row at all) is
216
+ not added.
217
+
218
+ **Defaults from another table.** A column that is in both files gets the
219
+ suffix `_r` from `merge`; fill from it, then drop it. Here the defaults are
220
+ each species' median body mass:
203
221
 
204
222
  ```bash
205
- dftk merge data.tsv -r defaults.tsv -k type -t left -o \
206
- | dftk eval ... -f "depth = depth.fillna(depth_r)" --drop depth_r
223
+ dftk dataset penguins -o | dftk pivot ... -i species -v body_mass_g \
224
+ -f median --move median_body_mass_g:body_mass_g -o defaults.parquet
225
+ dftk dataset penguins -o \
226
+ | dftk merge ... -r defaults.parquet -k species -t left -o \
227
+ | dftk eval ... -f "body_mass_g = body_mass_g.fillna(body_mass_g_r)" \
228
+ --drop body_mass_g_r
207
229
  ```
208
230
 
209
- The group mean, a fixed value, or the last value above (`ffill`) within
210
- each group:
231
+ **From neighbouring rows** (`co2` is a weekly series with gaps):
211
232
 
212
233
  ```bash
213
- dftk dataset penguins -o | dftk eval ... \
214
- -f "mean = body_mass_g.groupby(species).transform('mean')" \
215
- -f "body_mass_g = body_mass_g.fillna(mean)" --drop mean \
216
- -f "sex = sex.fillna('unknown')"
234
+ dftk dataset co2 -o | dftk eval ... -f "ffill = co2.ffill()" \
235
+ -f "bfill = co2.bfill()" -f "linear = co2.interpolate()"
236
+ ```
237
+
238
+ `ffill` leaves the first rows empty and `bfill` the last ones;
239
+ `x.ffill().fillna(x.bfill())` fills both. `interpolate()` counts one step
240
+ per row, so the rows must be evenly spaced; for an x-based lookup from a
241
+ reference curve, see `dftk interp`.
217
242
 
243
+ **Row order and groups.** These methods use the rows in the order they are
244
+ in. Sort first, in a step of its own: `--sortasc` applies to a command's
245
+ output, so in the same command it would come after the fill. When a table
246
+ holds several series (sites, countries, samples), fill within each group,
247
+ or values are taken from the neighbouring group. Rows of a group don't need
248
+ to be next to each other, but within each group they must be in order:
249
+
250
+ ```bash
218
251
  dftk dataset healthexp -o \
219
- | dftk eval ... -f "le = Life_Expectancy.where(Year % 10 != 5)" -o \
252
+ | dftk eval ... -f "le = Life_Expectancy.where(Year % 10 != 5)" \
253
+ --sortasc Country Year -o \
220
254
  | dftk eval ... -f "le_filled = le.groupby(Country).ffill()"
221
255
  ```
222
256
 
223
- `ffill`, `bfill` and `interpolate` use the rows in the order they are in:
224
- sort in a step of its own first (`dftk eval data.tsv --sortasc site day -o
225
- | dftk eval ... -f ...`), and use `groupby(...)` when the table holds
226
- several series, or values are taken from the neighbouring group.
227
- `interpolate()` has no grouped form and works by row position. `dftk eval
228
- -h` covers these cases, with examples.
257
+ `interpolate()` has no grouped form. Once each group's rows are together,
258
+ gaps inside a group are right, but a gap at a group's start or end is
259
+ filled from the neighbouring group. To leave those empty, keep only values
260
+ with something before and after them in the same group:
261
+
262
+ ```bash
263
+ dftk dataset healthexp -o \
264
+ | dftk eval ... -f "le = Life_Expectancy.where(Year % 10 != 5)" \
265
+ --sortasc Country Year -o \
266
+ | dftk eval ... -f "before = le.groupby(Country).ffill().notna()" \
267
+ -f "after = le.groupby(Country).bfill().notna()" \
268
+ -f "le_linear = le.interpolate().where(before & after)" \
269
+ --drop before after
270
+ ```
271
+
272
+ ### Differences between rows
273
+
274
+ For the change in a column from one row to the next, `eval -f` takes
275
+ pandas `diff()` and `pct_change()`, also within groups. They use the rows
276
+ in their order, so sort first, in a step of its own:
277
+
278
+ ```bash
279
+ dftk dataset healthexp -o | dftk eval ... --sortasc Country Year -o \
280
+ | dftk eval ... -f "change = Spending_USD.groupby(Country).diff().round(1)" \
281
+ -f "pct = (Spending_USD.groupby(Country).pct_change() * 100).round(1)" \
282
+ -f "years = Year.groupby(Country).diff()"
283
+ ```
284
+
285
+ ```text
286
+ Year Country Spending_USD Life_Expectancy change pct years
287
+ 1971 Canada 313.391 72.8
288
+ 1976 Canada 543.337 73.8 229.9 73.4 5.0
289
+ 1979 Canada 692.269 75.1 148.9 27.4 3.0
290
+ 1980 Canada 791.812 75.2 99.5 14.4 1.0
291
+ ```
292
+
293
+ The first row of each country gets an empty cell. Without
294
+ `groupby(Country)`, it would be compared with the last row of the
295
+ previous country.
296
+
297
+ To compare a value with one in another column of the previous or next row, for example the
298
+ gap between segments given by `Chr`, `Begin`, `End`, use SQL's `LAG()` /
299
+ `LEAD()` in `query --sql`:
300
+
301
+ ```bash
302
+ dftk query segments.tsv --sql \
303
+ 'SELECT *, "Begin" - LAG("End") OVER (PARTITION BY Chr ORDER BY "Begin")
304
+ AS gap
305
+ FROM data ORDER BY Chr, "Begin"'
306
+ ```
307
+
308
+ ```text
309
+ Chr Begin End Id gap
310
+ chr1 100 200 a
311
+ chr1 250 400 b 50
312
+ chr1 390 500 c -10
313
+ chr2 50 80 d
314
+ chr2 100 300 e 20
315
+ ```
316
+
317
+ A negative gap is an overlap, and the first segment on each chromosome
318
+ gets an empty cell. `lead("Begin") OVER (...) - "End"` gives the gap to
319
+ the next segment instead.
320
+
321
+ - `Begin` and `End` are SQL keywords: quote such column names with double
322
+ quotes and the whole statement with single quotes.
323
+ - No sorting is needed first; `ORDER BY` inside `OVER` sets the order.
324
+ - Integers stay integers.
325
+
326
+ `eval -f` can do the same with pandas `shift`, but it goes by row order, so
327
+ sort by `Chr` and `Begin` first (results are floats):
328
+
329
+ ```bash
330
+ dftk eval segments.tsv -f 'gap = Begin - End.groupby(Chr).shift()'
331
+ ```
332
+
333
+ Without `groupby(Chr)` the first segment of a chromosome is compared with
334
+ the last one of the previous chromosome.
229
335
 
230
336
  ### Bootstrap confidence intervals
231
337
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dataframe-toolkit"
3
- version = "0.11.1"
3
+ version = "0.11.3"
4
4
  description = "A command-line toolkit for DataFrame analysis and manipulation"
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -29,6 +29,7 @@ dependencies = [
29
29
  "patsy>=0.5.6",
30
30
  "duckdb>=0.8",
31
31
  "matplotlib>=3.7",
32
+ "pillow>=13.0",
32
33
  "seaborn>=0.12",
33
34
  "tqdm>=4.65",
34
35
  ]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dataframe-toolkit"
3
- version = "0.11.1"
3
+ version = "0.11.3"
4
4
  description = "A command-line toolkit for DataFrame analysis and manipulation"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -26,6 +26,7 @@ dependencies = [
26
26
  "patsy>=0.5.6",
27
27
  "duckdb>=0.8",
28
28
  "matplotlib>=3.7",
29
+ "pillow>=13.0", # not used directly (matplotlib needs it); floor for security fixes
29
30
  "seaborn>=0.12",
30
31
  "tqdm>=4.65",
31
32
  ]