This is a migrated thread and some comments may be shown as answers.

Set color for each category in single series chart

5 Answers 1605 Views
Chart
This is a migrated thread and some comments may be shown as answers.
Bill
Top achievements
Rank 1
Bill asked on 16 Apr 2019, 01:49 PM

I know this has been asked before and referenced in regard to jquery (https://www.telerik.com/forums/different-color-for-each-bar-in-bar-chart-for-a-single-series-) as well as others but I can't seem to figure out how to do it in Core.   I have a simple Column chart from bound sql datasource.   Is it possible to set the category columns to different colors?  Note that the number of categories is variable.

Here is my controller action:

public ActionResult AttributeSummary_Read(int? id)
{
    {
        var assessmentId = new SqlParameter("@assessmentId", id);
        var data = _context.Reports.FromSql("rpt_AttributeSummaryBySite @assessmentId", assessmentId).AsNoTracking().ToList();
        List<Report_AttributeSummaryVM> AttributeSummaryList = data.Select(x => new Report_AttributeSummaryVM
        {
            AttributeName = x.AttributeName,
            SumAssessmentValue = x.SumAssessmentValue,
            AssessmentYear = x.AssessmentYear
        }).ToList();
 
        return Json(AttributeSummaryList);
    }

 

As an example with 3 categories, my stored proc produces this data:

OutcomeName                    |       AssessmentYear      |         AvgOutcomeValue
Best Practices in Ministry                   2019                                     5.16
Leadership Development                   2019                                        6
Strategic Alignment of Ministries        2019                                     4.59

 

Here is the Razor View

<div class="container w-75">
    <div class="demo-section k-content wide">
        @(Html.Kendo().Chart<ICPCore.Models.Reports>()
            .Name("chartOutcomeSummary")
            .Title("Outcomes Summary by Site")
            .Legend(legend => legend
                .Position(ChartLegendPosition.Top)
            )
            .DataSource(ds => ds.Read(read => read.Action("OutcomeAreaSummary_Read", "Reports").Data("curId")))
            .Series(series =>
            {
                series.Column(model => model.AvgOutcomeValue).Name("AvgOutcomeValue").CategoryField("OutcomeName");
            })
            .CategoryAxis(axis => axis
                .Categories(model=>model.OutcomeName)
                .Labels(labels => labels.Rotation(0))
                .MajorGridLines(lines => lines.Visible(false))
            )
            .ValueAxis(axis => axis.Numeric()
                .Labels(labels => labels.Format("{0:N0}"))
                .MajorUnit(1)
                .Max(10)
                .Min(1)
                .Line(line => line.Visible(false))
            )
            .Tooltip(tooltip => tooltip
                .Visible(true)
                .Format("{0:N0}")
            )
            .AutoBind(true)
        )
    </div>
</div>

5 Answers, 1 is accepted

Sort by
1
Accepted
Tsvetina
Telerik team
answered on 19 Apr 2019, 09:07 AM
Hi Bill,

Where will the colors come from in your case? If you are planning to add one more field to the model, containing the color value, you can set the series ColorField to this field name:

OutcomeName                    |       AssessmentYear      |         AvgOutcomeValue      |          Color
Best Practices in Ministry                   2019                                     5.16                           #336699
Leadership Development                   2019                                        6                             #ff8866
Strategic Alignment of Ministries        2019                                     4.59                           #4488cc 

series.Column(model => model.AvgOutcomeValue).Name("AvgOutcomeValue").CategoryField("OutcomeName").ColorField("Color");

If you want to determine the color on the client, based on some condition, use the ColorHandler setting:
series.Column(model => model.AvgOutcomeValue).Name("AvgOutcomeValue").CategoryField("OutcomeName").ColorHandler("getColor");

<script>
    // function will be called for each data point (column) in the Chart separately
    function getColor(arg){
       // run custom logic
       return color;
    }
</script>


Regards,
Tsvetina
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Bill
Top achievements
Rank 1
answered on 22 Apr 2019, 02:15 PM

Hi Tsvetina,

That is what I was looking for.   Is is possible for you to show me how I might create the "getColor" function so that it loops thru each element of the column and assigns a seriesColor?   

Bill

0
Tsvetina
Telerik team
answered on 24 Apr 2019, 11:37 AM
Hi Bill,

What do you mean by looping each element of the column? The getColor function is automatically called for each series data point, that is each separate column. Based on the provided arguments, you can return a different color value each time, resulting in different column colors. Do you want to apply more than one color in a single column?

Regards,
Tsvetina
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Bill
Top achievements
Rank 1
answered on 24 Apr 2019, 06:18 PM

Hi Tsventina,

I realize that the function loops.  The part I wasn't quite sure how to do is in the section "run custom logic".  I'm not sure how (or if I can) have the code select a theme color (I'm using the Bootstrap 4 theme in Telerik UI for ASP.NET Core) for each column.   My question is simply "how do I assign a theme color to each column in the getColor function".    I don't actually care what color gets assigned, I just want it to be a theme color and different for each column.    

0
Accepted
Tsvetina
Telerik team
answered on 25 Apr 2019, 02:37 PM
Hi Bill,

Here is one such implementation:
<script>
    var colors = ["red", "green", "blue"];
    function getColor(arg) {
        var index = arg.series.data.indexOf(arg.value);
        //  if number of series points is bigger than number of colors, reduce the index
        while (index > colors.length - 1) {
            index -= (colors.length - 1);
        }
        return colors[index];
    }
</script>

The snippet above finds the index of the current value in the series data and uses it to obtain a color from a pre-defined colors collection. 

Regards,
Tsvetina
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Bill
Top achievements
Rank 1
commented on 25 Apr 2019, 07:33 PM

Thank you!

 

Cherish
Top achievements
Rank 1
commented on 30 May 2022, 05:36 PM | edited

Hi,

This question applies to me exactly, except a linear gradient is required instead of solid color. How do I do this with Core? The only difference with the OP's data structure is that I have a ColorFrom and ColorTo values (hex). Here is the sample chart I need to implement:

Thanks a lot in advance!

 

Cherish

Mihaela
Telerik team
commented on 02 Jun 2022, 10:23 AM

Hi Cherish,

The described functionality is not available out-of-the-box for the column Chart because the Chart is rendered as SVG, and each column series is rendered as a single segment in a Path. However, I would suggest the following custom solution:

 

@(Html.Kendo().Chart<ChartViewModel>()
                .Name("chart")
                ...
                .SeriesDefaults(seriesDefaults =>
                    seriesDefaults.Column()
                )
                .Series(series => {
                    series.Column(model => model.SeriesField1).CategoryField("CategoryName").Overlay( o => o.Gradient(ChartSeriesGradient.None));
                    series.Column(model => model.SeriesField2).CategoryField("CategoryName").Overlay( o => o.Gradient(ChartSeriesGradient.None));
                })
                .Events(ev => ev.DataBound("onDataBound")) //Handle the "DataBound" event of the Chart
)

<script>
    function onDataBound(e) {
        var chartData = e.sender.dataSource.data(); //get the Chart's data
        var options = e.sender.options;
        var series = options.series; //get the Series options

        kendo.dataviz.Gradients.series1Gradient = { // define the gradients
            type: "linear",
            stops: [{
                offset: 0,
                color: `${chartData[0].ColorFrom}`, //set the color based on the Model field "ColorFrom"
                opacity: 0.5
            }, {
                offset: 1,
                color: `${chartData[0].ColorTo}`, //set the color based on the Model field "ColorTo"
            }]
        };

        kendo.dataviz.Gradients.series2Gradient = {
            type: "linear",
            stops: [{
                offset: 0,
                color: `${chartData[1].ColorFrom}`,
                opacity: 0.5
            }, {
                offset: 1,
                color: `${chartData[1].ColorTo}`,
            }]
        };
        // override gradients for each series
        series[0].overlay.gradient = "series1Gradient";
        series[0].overlay.gradient.start = [0.5, 0];
        series[0].overlay.gradient.end = [0.5, 1];

        series[0].overlay.gradient = "series2Gradient";
        series[0].overlay.gradient.start = [0.5, 0];
        series[0].overlay.gradient.end = [0.5, 1];
    }
</script>

Also, check out similar examples in the following KBs:

https://docs.telerik.com/kendo-ui/knowledge-base/create-left-to-right-gradient-multi-color-values

https://docs.telerik.com/kendo-ui/knowledge-base/chart-area-gradient-effect

I hope these examples will help you to achieve the desired result.

Tags
Chart
Asked by
Bill
Top achievements
Rank 1
Answers by
Tsvetina
Telerik team
Bill
Top achievements
Rank 1
Share this question
or