D3 has an unnecessarily non-intuitive API design, and I think that kills it for a lot of people.
For example, why must a data join be performed like `selection.data(array).join(element-type)` instead of something like `selection.join(element-type, array)`. Looking from a pure API-design perspective, not getting bogged down in the technical details.
Lazy eval method chaining is a natural fit for applying+branching large amounts of HTML/CSS state updates but I feel that the designers took it a bit too far with the core D3 operations.