Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaking change with contour-density thresholds starting from v3.0.2 #70

Closed
HackerNeoAnderson opened this issue Feb 24, 2023 · 2 comments

Comments

@HackerNeoAnderson
Copy link

Hi guys,
We are updating our dependency on d3-contour from 3.0.1 to 4.0.2.
But, it looks like it's not backward compatible starting from 3.0.2.
The breaking change was introduced in PR#57 and published as a patch version (3.0.2)

In our application, we provide thresholds as a callback function which returns an array:
contourDensity().thresholds((densityValues) => someArrayOfThresholds)

Could you suggest, how to make it compatible with the latest version (4.0.2) of d3-contour?
Maybe we need to use some built-in function like thresholdFreedmanDiaconis, thresholdScott, thresholdSturges to make the density chart drawn correctly again?

@Fil
Copy link
Member

Fil commented Feb 24, 2023

This notebook: https://observablehq.com/@fil/density-thresholds-70

Suppose you wanted to pass the following thresholds in d3-contour 3.0.1:

const contours = d3301
  .contourDensity()
  .thresholds([0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01])
    (data)

this would return contours with values:

contours.map((d) => d.value) // [0, 0.0000625, 0.000125, 0.0001875, 0.00025, 0.0003125, 0.000375, 0.0004375, 0.0005, 0.0005625, 0.000625]

This was inconsistent (you ask for 1, you get 1/16). #57 fixes the inconsistency, so starting with 3.0.2, you would pass this instead:

const thresholds = [0, 0.0000625, 0.000125, 0.0001875, 0.00025, 0.0003125, 0.000375, 0.0004375, 0.0005, 0.0005625, 0.000625];
const contours = d3_301
  .contourDensity()
  .thresholds(thresholds)
    (data)

and get the same contours (with the same values).

The relationship between the two is this ratio 2**k with k the cellSize which defaults to 4; in other words you should find the same contours as before if you did:

const thresholds = [0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01]; // old style
const contours = d3_302
  .contourDensity()
  .thresholds(thresholds.map(d => d/16)) // convert to new style
    (data)

@Fil Fil closed this as completed Feb 24, 2023
@NataliaM5
Copy link

NataliaM5 commented Feb 24, 2023

Hi, @Fil !
Thank you for the response. Faced the same issue.
After diving deep into d3-contour source code, I found that k depends on cellSize provided value:

return k = Math.floor(Math.log(_) / Math.LN2), resize();

So, to get a correct results, seems like we need to use the following formula when using cellSize method:

k = Math.floor(Math.log(cellSizeValue) / Math.LN2)

const thresholds = [0, 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01]; // old style
const contours = d3_302
  .contourDensity()
  .cellSize(cellSizeValue)
  .thresholds(thresholds.map(d => d/ Math.pow(2, 2 * k))) // convert to new style
    (data)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants