Repository: saulpw/visidata

Issue:
frequency histogram for number is wrong
**Small description**

With [this data](https://github.com/saulpw/visidata/files/5543325/a.txt), when type casting year column to number `#`, and asking for frequency `F`, bins are wrong. I works correctly when not type casting.

**Expected result**

(obtained without type casting and moving 2020 to the top)

```
year	count	percent	histogram
2020	11	7.69	*********************************************
2019	12	8.39	**************************************************
2018	12	8.39	**************************************************
2017	12	8.39	**************************************************
2016	12	8.39	**************************************************
2015	12	8.39	**************************************************
2014	12	8.39	**************************************************
2013	12	8.39	**************************************************
2012	12	8.39	**************************************************
2011	12	8.39	**************************************************
2010	12	8.39	**************************************************
2009	12	8.39	**************************************************
```


**Actual result with screenshot**

(typecasting to number)

```
year	count	percent	histogram
2009	12	8.39	**************************
2010	12	8.39	**************************
2011	12	8.39	**************************
2012	12	8.39	**************************
2013	12	8.39	**************************
2014	12	8.39	**************************
2015	12	8.39	**************************
2016	12	8.39	**************************
2017	12	8.39	**************************
2018	12	8.39	**************************
2019	23	16.08	**************************************************
2020	0	0.00	
```


**Steps to reproduce with sample data and a .vd**

* [data](https://github.com/saulpw/visidata/files/5543325/a.txt)
* [commands](https://github.com/saulpw/visidata/files/5543339/a.vd.txt)

**Additional context**

version `saul.pw/VisiData v2.0.1`

it seems there is a limit to 11 bins and the rest is empty. The more I put data, the more is aggregated in the 11th bin.



Discussion:
Does anyone reproduce this bug ? It seems surprising for a such central feature ...
Hi @setop!

What happens when you run this with `-g --numeric-binning=False`?

What happens if you run this with the branch off `develop` (while keeping numeric binning on)? It is possible that I have fixed this bug already on develop. 

Numeric binning is a relatively recent feature that still has some edge case kinks. We are debating keeping it off by default for this reason (the Frequency Table being so central).

If the problem is numeric binning, and this has not been fixed yet, your use case will be really useful for debugging this!
I can confirm that this is a bug that is related to `numeric-binning` and is still relevant to `develop`. The current workaround for this dataset is to set `options.numeric_binning = False` in your `~/.visidatarc` or `-g --numeric-binning=False` on the commandline.

I will add it to my bug fixing queue.

Resolving patch:
diff --git a/visidata/pivot.py b/visidata/pivot.py
--- a/visidata/pivot.py
+++ b/visidata/pivot.py
@@ -181,10 +181,11 @@ def groupRows(self, rowfunc=None):
             if width == 0:
                 # only one value (and maybe errors)
                 numericBins = [(minval, maxval)]
-            elif numericCols[0].type in (int, vlen) and nbins > (maxval - minval):
-                # more bins than int vals, just use the vals
+            elif (numericCols[0].type in (int, vlen) and nbins > (maxval - minval)) or (width == 1):
+                # (more bins than int vals) or (if bins are of width 1), just use the vals as bins
                 degenerateBinning = True
-                numericBins = [(minval+i, minval+i) for i in range(maxval-minval+1)]
+                numericBins = [(val, val) for val in sorted(set(vals))]
+                nbins = len(numericBins)
             else:
                 numericBins = [(minval+width*i, minval+width*(i+1)) for i in range(nbins)]
 
@@ -214,7 +215,8 @@ def groupRows(self, rowfunc=None):
                     if not width:
                         binidx = 0
                     elif degenerateBinning:
-                        binidx = val-minval
+                        # in degenerate binning, each val has its own bin
+                        binidx = numericBins.index((val, val))
                     else:
                         binidx = int((val-minval)//width)
                     groupRow = numericGroupRows[formatRange(numericCols[0], numericBins[min(binidx, nbins-1)])]


Test patch: