Skip to content

Conversation

@ilayda-cp
Copy link
Contributor

@ilayda-cp ilayda-cp commented Nov 13, 2024

When creating a pie chart, users can currently specify only a single radius (outer radius), which applies uniformly to all pie sectors. This PR proposes allowing developers to define different radius sizes for each pie sector, enabling more customized and varied visualizations.

Description

A function type has been added to the outerRadius parameter. Users can now pass a function to outerRadius to calculate the radius dynamically. This function takes an element as a parameter and expects a number to be returned.

Related Issue

#5224

How Has This Been Tested?

Run the existing unit tests and added unit tests for the new feature.

Screenshots:

Screenshot from 2024-11-13 15-37-47

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • I have added a storybook story or extended an existing story to show my changes

Copy link
Member

@ckifer ckifer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to need some unit tests to make sure this does what we say it does.

Also this might be better added to Cell rather than as a different data key.

@PavelVanecek thoughts?

},
];
const tooltipPosition = polarToCartesian(coordinate.cx, coordinate.cy, middleRadius, midAngle);
const outerRadiusParam = getValueByDataKey(entry, radiusKey, coordinate.outerRadius);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this no longer allow you to specify outerRadius as you currently can? I can't tell. But it should prefer outerRadius if set - otherwise use radiusKey

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use both "outerRadius" and "radiusKey", the code first calculates the outer radius by using the "outerRadius" parameter. Then the "radiusKey" parameter is checked. If its provided it will use it otherwise it fallbacks to the calculated outerRadius. But i can definitely update it to prefer outerRadius parameter first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern is how a user can define a reference radius for the pie chart if the sector radius is specified as a percentage. In this case, the outer radius parameter is used to calculate the sector's radius.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my new comment above, I don't think this is the best way we can do this.

If we had the prop take a number or a function we wouldn't have to prefer one over the other

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not too sure what you mean by reference radius. Can you give me a scenario?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i agree on making outerRadius a function. It would make more sense. Ill update it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have it allow both. A static number or percent like you can do today, or a function that returns a number.

Thanks! And thanks for being willing to change things a bit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made the changes

@ckifer ckifer requested a review from PavelVanecek November 13, 2024 15:46
@codecov
Copy link

codecov bot commented Nov 13, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 95.23%. Comparing base (1dedbc2) to head (3c5b111).
Report is 16 commits behind head on 3.x.

Additional details and impacted files
@@           Coverage Diff           @@
##              3.x    #5244   +/-   ##
=======================================
  Coverage   95.23%   95.23%           
=======================================
  Files         164      164           
  Lines       18654    18663    +9     
  Branches     4059     4061    +2     
=======================================
+ Hits        17765    17774    +9     
  Misses        883      883           
  Partials        6        6           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.


🚨 Try these New Features:

className?: string;
dataKey: DataKey<any>;
nameKey?: DataKey<any>;
radiusKey?: DataKey<any>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also have a concern with the naming of this. There is currently both innerRadius and outerRadius props. Calling the new prop radiusKey might be confusing as to which radius we are affecting? And if you can do it to outerRadius why not inner as well?

Maybe instead of a new prop at all we should just let inner and outer radius take functions which give your data as an argument. Then you can do something like

outerRadius={(data) => data.someRadius}

That seems a lot simpler

},
];
const tooltipPosition = polarToCartesian(coordinate.cx, coordinate.cy, middleRadius, midAngle);
const outerRadiusParam = getValueByDataKey(entry, radiusKey, coordinate.outerRadius);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my new comment above, I don't think this is the best way we can do this.

If we had the prop take a number or a function we wouldn't have to prefer one over the other

@ilayda-cp ilayda-cp requested a review from ckifer November 14, 2024 12:52
Copy link
Member

@ckifer ckifer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! Few more comments

Comment on lines 361 to 365
if (typeof item.outerRadius === 'function') {
outerRadius = item.outerRadius(element);
} else {
outerRadius = getPercentValue(item.outerRadius, maxPieRadius, maxPieRadius * 0.8);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we could make this a small helper function so we don't have to use a let?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made the change

innerRadius?: number | string;
/** The outer radius of sectors */
outerRadius?: number | string;
outerRadius?: number | string | ((element: any) => number);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

element implies "html element" or "react element". Can we name this something related to data?

dataItem, dataPoint, even just item would be ok

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made the change

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be missing something but I don't see the changes. Can you try to push again?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Collaborator

@PavelVanecek PavelVanecek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm okay with this change, better than the Cell. I have one request though, can you make the Pie accept a DataKey? That also allows functions, and more. We have a helper for resolving it so that should be easy change.

@ilayda-cp ilayda-cp requested a review from ckifer November 15, 2024 08:26
@PavelVanecek
Copy link
Collaborator

DataKey is this recharts-specific thing. It's either function or string or I forgot what else and we use it to allow users to decide how to pull primitives out of the data object.

Look at what other components do when they accept a dataKey prop. Basically I want this new feature to follow the same pattern.

@PavelVanecek
Copy link
Collaborator

I'm on phone on a train, I can paste some examples of what it should look like later when I get to the PC.

@ilayda-cp
Copy link
Contributor Author

ilayda-cp commented Nov 15, 2024

@PavelVanecek I checked it out, and the Pie component already has a dataKey prop. The value is extracted as follows:

const val = getValueByDataKey(entry, dataKey, 0);

This value is then passed to the function assigned to the outerRadius parameter (if its a function).

But do you mean you would like a 'key' (like data key) whose value would be used as the outer radius?

@PavelVanecek
Copy link
Collaborator

What I'm trying to say is, make the outerRadius also a DataKey type. So that one can decide how to decide the radius out of values of the data array.

@PavelVanecek
Copy link
Collaborator

PavelVanecek commented Nov 15, 2024

const outerRadius = getValueByDataKey(entry, props.outerRadius, defaultOuterRadius)

Something like this.

@ilayda-cp
Copy link
Contributor Author

this is similar to my first solution. I can revert back to that solution with some changes. What do you think @ckifer ?

@PavelVanecek
Copy link
Collaborator

Ah sorry for the back and forth. Maybe I should be more careful and read the history first.

Either way please don't make it use the Cell 😬 that's a blocker for us in the future and I will try to remove it in next versions.

@ckifer
Copy link
Member

ckifer commented Nov 15, 2024

The problem with dataKey is it adds a bunch of props associated to each radius type. I guess that's fine and we shouldn't be scared of new props but this feels less intrusive.

If we want to add a dataKey down the road we still can, this essentially acts the same though

@ckifer
Copy link
Member

ckifer commented Nov 19, 2024

@ilayda-cp just waiting on you to push your last commit on this one. Thanks!

@ilayda-cp
Copy link
Contributor Author

@ckifer sorry about the delay pushed the change

Copy link
Member

@ckifer ckifer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two more tiny things but no worries about them. LGTM


const getOuterRadius = (
dataPoint: any,
outerRadius?: number | string | ((element: any) => number),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: for consistent interface this should be updated too

But it's not outward facing so all good

minAngle?: number;
innerRadius?: number | string;
outerRadius?: number | string;
outerRadius?: number | string | ((element: any) => number);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Same here

@ckifer ckifer merged commit 3cca3b0 into recharts:3.x Nov 20, 2024
5 checks passed
@ckifer
Copy link
Member

ckifer commented Nov 20, 2024

Thanks @ilayda-cp!

@ilayda-cp ilayda-cp deleted the pie-chart-with-step branch November 20, 2024 06:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants