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

New polar chart type #11131

Open
pacastro opened this issue Feb 10, 2023 · 12 comments
Open

New polar chart type #11131

pacastro opened this issue Feb 10, 2023 · 12 comments

Comments

@pacastro
Copy link

pacastro commented Feb 10, 2023

Feature Proposal

Enhance the current Polar charts adding a new type thats adds new data displayed for each current data category. Making it posible to create and display wind rose plots like the following, this type of plot is called polar bar:
BGD_yearly

Possible Implementation

Starting with the current "Polar area centered point labels chart", add a new data set for each current data category. Color codes and legends should be for this new data set (like in the wind rose plot in the previous picture). Also, the current "centered point label" could be made customizable to hide some labels (to achieve something like in the wind rose plot)

@LeeLenaleee
Copy link
Collaborator

I think you might be able to do this already by using a scriptable function for the angle lines width or color

@pacastro
Copy link
Author

I'm not sure if I can achieve this, I'm just starting to use this... will take a look. each angle have its own data set and so its a different width for the colors inside each angle... also no idea if you can get the legend working for the new proposed data set (wind speed) instead of the current legend for the outside of the circle data

@pacastro
Copy link
Author

Ok, got it to work... more or less. No scripting so far, just stacked data over each other.

Screenshot 2023-02-12 at 14 02 57

Got working almost everything I was looking for, but there are a couple of problems with this method:

1- Legends, legends are displayed for the global labels category, not for each dataset.. so you get the label for cardinal directions and not the ones for dataset (wind speed ranges in this case)

2- Colors, if no alpha channel is used you have to use order config for each dataset to make sure the smaller arcs get drawn after the bigger ones. Using transparency, colors get stacked and mixed, very restricted due to the staking of the sets

For 1.. no idea if scripting can make it work. Maybe add in Namespace: options.scales[scaleId].pointLabels a "dataLabels" boolean option toggle or something like that that displays the label defined for each dataset with their assigned color.

For 2, works with solid colors... the problem is with transparencies.. no idea how to solve this. No problem if you don't need transparent colors (really useful sometimes)

@etimberg
Copy link
Member

For the legend you can definitely do it. Basically you're going to need a custom generateLabels function and a custom onClick in the legend options

For 2, this is going to be a lot bigger challenge. Are you able to share the dataset? I can take a look at some options

@pacastro
Copy link
Author

var data = {
            labels: ['N', 'NNE', 'NE', 'NEE', 'E', 'SEE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'SWW', 'W', 'NWW', 'NW', 'NNW'],
            datasets: [
                {
                    label: "11-14 m/s",
                    data: [0, 0, 0, 0, 0, 0, 0, 35, 85, 43, 15, 0, 0, 0, 0, 80],
                    backgroundColor: 'rgba(255,0,0, 1)',
                    fill: true,
                    borderColor: 'rgba(255, 255, 255, 0.5)',
                    borderWidth: 1,
                    order: 3
                },
                {
                    label: "8-11 m/s",
                    data: [0, 0, 0, 0, 0, 0, 0, 30, 60, 35, 12, 0, 0, 0, 0, 60],
                    backgroundColor: 'rgba(100,255,100, 1)',
                    fill: true,
                    borderColor: 'rgba(255, 255, 255, 0.5)',
                    borderWidth: 1,
                    order: 2
                },
                {
                    data: [0, 0, 0, 0, 0, 0, 0, 15, 45, 20, 5, 0, 0, 0, 0, 50],
                    label: "5-8 m/s",
                    backgroundColor: "rgb(100,255,255,1)",
                    fill: true,
                    borderColor: 'rgba(255, 255, 255, 0.5)',
                    borderWidth: 1,
                    order: 1
                },
                {
                    label: "< 5 m/s",
                    data: [0, 0, 0, 0, 0, 0, 0, 10, 25, 10, 2, 0, 0, 0, 0, 40],
                    backgroundColor: 'rgba(100,180,255, 1)',
                    fill: true,
                    borderColor: 'rgba(255, 255, 255, 0.5)',
                    borderWidth: 1,
                    order: 0
                }
            ]
        };
        var options = {
            plugins: {
                legend: {
                    display: true,
                    fullWidth: true,
                    position: 'bottom',
                },
                title: {
                    display: true,
                    text: 'Windrose test',
                    position: "top",
                    //color: 'rgba(0, 0, 255, 1)',
                    font: {
                        size: 20
                    }
                },
                tooltip: {
                    enabled: true,
                    caretSize: 10,
                    backgroundColor: 'rgba(0, 0, 55, 0.5)'
                }
            },
            scales: {
                r: {
                    startAngle: -11.25,
                    angleLines: {
                        display: true,
                        lineWidth: 1,
                        borderDash: [6, 8]
                    },
                    grid: {
                        lineWidth: 1
                    },
                    ticks: {
                        color: 'black',
                        backdropColor: "rgba(0,0,0,0)",
                        stepSize: 10,
                        font: {
                            size: 12
                        },
                        z: 1,
                        callback: function (value, index) {
                            if (value !== 0) return value + '%';
                        }
                    },
                    pointLabels: {
                        display: true,
                        centerPointLabels: true,
                        font: {
                            size: 12
                        },
                        callback: function (value, index) {
                            if ((index % 2) === 0) return value;
                        }
                    }
                }
            }
        };
        var myChart = new Chart(ctx, {
            type: 'polarArea',
            data: data,
            options: options
        });

@kurkle
Copy link
Member

kurkle commented Feb 12, 2023

I think adding "stacked: true" to the scale options should make the colors not overlap. Though the values will be stacked too.

@pacastro
Copy link
Author

pacastro commented Feb 12, 2023

Just tried "stacked: true" and it did not make any difference... but as in solid colors, using order for each dataset actually works for transparent colors too and prevent the mixing of colors. problem solved I guess. Now still learning how to use generateLabels function to solve my other problem.

UPDATE: actually order config for transparent colors do not work, I was using very light colors and it seemed to work but it doesn't, so color staking problem with transparent colors is still there... but on the other hand got generateLabels to work so problem 1 solved for me!

thanks!

@etimberg
Copy link
Member

etimberg commented Feb 12, 2023

Stacked doesn't work on polar area chart because the controller doesn't support it. https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.polarArea.js#L195 would need to be updated to read the previous dataset pixel coordinate when stacked

@pacastro
Copy link
Author

For the legend you can definitely do it. Basically you're going to need a custom generateLabels function and a custom onClick in the legend options

You were right! got the legend working with a custom generateLabelsfunction directly in labels, did not use onClick:

Screenshot 2023-02-12 at 22 37 50 Medium

Thanks!

@pacastro
Copy link
Author

pacastro commented Feb 20, 2023

A new question for building a PolarBar for windrose applications... as you can see in the first picture example for what I wanted to achieve, there is an empty small white circle in the middle of the chart (empty with text in it: calm 5.7%), so that the ticks for the actual polar chart start on the outside radius of this inner circle... its like a cutout for a doughnut chart, but the cutout option does not work for polar charts.

So, is there a way to make something like this work in a Chart.js Polar chart? enable something like the cutout ?

@etimberg
Copy link
Member

A new question for building a PolarBar for windrose applications... as you can see in the first picture example for what I wanted to achieve, there is an empty small white circle in the middle of the chart (empty with text in it: calm 5.7%), so that the ticks for the actual polar chart start on the outside radius of this inner circle... its like a cutout for a doughnut chart, but the cutout option does not work for polar charts.

So, is there a way to make something like this work in a Chart.js Polar chart? enable something like the cutout ?

AFAIK there is no way to get the cutout working. It'd likely require code changes inside the radial scale to stop assuming it can draw to this.xCenter, this.yCenter

@pacastro
Copy link
Author

Ok, will use external summary text to display calm %.

Thanks again!

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

No branches or pull requests

4 participants