Giter Club home page Giter Club logo

Comments (10)

Fil avatar Fil commented on May 2, 2024 2

Here's a heuristic that seems not too bad: https://observablehq.com/d/07db25f490cf93d1

We look at the differences between the angles, and if that difference is large or one of the angles is really sharp, we push the inner Bézier control points gently towards the border. I tried it on two examples only, so I'm not 100% sure it works everywhere.

PS: I converted the quadratic Bézier to a cubic Bézier—though probably not 100% necessary, I found this made it easier to think — the control points are just 1/3 of the way towards the circumference, and we can nudge them a little more to make the shape smaller.

before

Capture d’écran 2020-07-04 à 01 33 36

after

Capture d’écran 2020-07-04 à 01 33 32

before

Capture d’écran 2020-07-04 à 01 33 27

after

Capture d’écran 2020-07-04 à 01 33 20

from d3-chord.

Fil avatar Fil commented on May 2, 2024 1

New research!

See https://observablehq.com/d/4dcd344d74fcccc8 for the application, and https://observablehq.com/d/1af6b73d28c93927 for the (interactive) research.

Conclusions:

1). the moderation factor must be the same for the inner and outer parts of the path.

why? because in some cases you want parallel ribbons stemming from the same source and flying to nearby targets. If the inner part of the outer ribbon was the only one that got "moderated", then it would overlap the outer part of the inner ribbon. (see example image below)

2). With quadratic Bézier I don't think we can find an analytical solution, in the sense that some overlap will always be present when you have a very small angle inside e.g. a π/4 angle — but with a good heuristic the overlap can be limited to 1 or 2 pixels.

3). As a starting point the following heuristic works quite well:
f(x) := max(0, 1 - x) ** 4 * max(0.7, 1 - 6 * x)

Where f(x) controls how much we move the control point from <0,0> towards the midpoint of the angle x.

(We might have to map all the angle pairs (a,b), measure the overlap, and see if we can optimize this function further?)

Capture d’écran 2020-09-24 à 10 28 31

from d3-chord.

mbostock avatar mbostock commented on May 2, 2024

It would also be nice to have meaningful ribbon widths. For example, if the start and end value are the same, the ribbon width should be constant. I believe this is possible to implement if we compute the Bézier paths ourselves and use graduated curve offsetting, but it’s not trivial.

Short of that, we could use a tension parameter so that rather than always using ⟨0,0⟩ as the control point for the quadratic curve,

context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));

we shift the control point out towards the circumference of the circle at the midangle between the source and target.

from d3-chord.

vasturiano avatar vasturiano commented on May 2, 2024

Ah, I realize now that indeed the issue is with the control point of the quadratic curve, not the arc geometries, those are fine. 👍

Approach # 1 definitely seems ideal, but the math looks tricky.

For # 2 I think we'd only need to adjust one of the quadratic curves (the one with the smallest angular distance).

from d3-chord.

mbostock avatar mbostock commented on May 2, 2024

This is discussed in the circlize documentation for R:

https://jokergoo.github.io/circlize_book/book/graphics.html#links

from d3-chord.

vasturiano avatar vasturiano commented on May 2, 2024

The article suggests to allow the consumer to specify an h2 for the problematic links.

It happens especially when position of the two ends are too close or the width of one end is extremely large while the width of the other end is too small. In that case, users can manually set height of the top and bottom border by h and h2

What would be convenient is to calculate h2 automatically internally, so the user doesn't have to be bothered with it.
It seems to be a factor of the four angles sa0, sa1, ta0 and ta1. Now, what would that expression look like?

from d3-chord.

Fil avatar Fil commented on May 2, 2024

I believe PR #16 fixes this in all(?) cases. @vasturiano could you test it on your dataset, or share the notebook so we can see if it works there too?

from d3-chord.

vasturiano avatar vasturiano commented on May 2, 2024

@Fil thanks for looking at this!

I've tested the change on my side and it certainly fixes all the twisting cases I could find. 👍
Though it also makes the ribbons generally wider in the middle, which tends to make dense cases look a bit more cluttered.

Here's a few before/after sshots:

before
Screen Shot 2020-07-07 at 12 23 42 AM
after
Screen Shot 2020-07-07 at 12 16 40 AM

before
Screen Shot 2020-07-07 at 12 24 16 AM
after
Screen Shot 2020-07-07 at 12 17 42 AM

before
Screen Shot 2020-07-07 at 12 24 42 AM
after
Screen Shot 2020-07-07 at 12 18 45 AM

before
Screen Shot 2020-07-07 at 12 24 58 AM
after
Screen Shot 2020-07-07 at 12 19 26 AM

I haven't looked at the code changes, but would there be a way to detect and modify only the twisted cases, leaving the ribbons that had no issues untouched?

from d3-chord.

Fil avatar Fil commented on May 2, 2024

would there be a way to detect and modify only the twisted cases

I believe it can be done analytically, since it's the intersections of two parabolas.

This PR's approach is also a little bit more consistent with Mike's desire to have…

meaningful ribbon widths. For example, if the start and end value are the same, the ribbon width should be constant

but that will inevitably result in much thicker ribbons in your use case. (If you could share it as data it would be great to experiment).

More research needed :)

from d3-chord.

vasturiano avatar vasturiano commented on May 2, 2024

@Fil I added a change request to your notebook with the additional datasets so it can be experimented with. 👍
https://observablehq.com/d/07db25f490cf93d1

from d3-chord.

Related Issues (12)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.