ASE Home Page Products Download Purchase Support About ASE
ChartDirector General
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  Radial Bar Chart creation
Posted by Rand on Jan-24-2020 03:17
Attachments:
We need a radial bar chart but I do not see any in class list or examples.  How would this be created?

Following image shows an example of what we are looking for.
2020-01-23 14_15_32-test result and comparison concepts - luke jan 2020.png

  Re: Radial Bar Chart creation
Posted by Peter Kwan on Jan-24-2020 14:49
Hi Rand,

There are several methods:

(a) You can use a circular meter and add the circular bars as "zones".

The following is an example of a meter with a "zone". Note the "red circular bar" from 72 to 94.

https://www.advsofteng.com/doc/cdnet.htm#angularpointer2.htm

You can add multiple zones (circular bars) with different radius to the meter. You do not need to add the pointers of other decorations to the meter. You can hide the scale by setting the scale and text color to transparent.

(b) You can use a circular meter and add the circular bars as "color scale".

The following is an example of meters with color scales:

https://www.advsofteng.com/doc/cdnet.htm#colorroundmeter.htm

Again, you can add multiple color scales with different radius. The color scale can just be a flat regular color if you do not want to use color gradients.

(c) You can use a concentric donut chart with two sectors, with one of the sector being transparent.

https://www.advsofteng.com/doc/cdnet.htm#concentric.htm

(d) You can use addZone with a Polar Chart.


If you can inform me which programming language you are using, and whether it is a web or desktop application, I can write a simple example for you.

Regards
Peter Kwan

  Re: Radial Bar Chart creation
Posted by Rand on Jan-25-2020 00:55
Peter Kwan wrote:

If you can inform me which programming language you are using, and whether it is a web or desktop application, I can write a simple example for you.

Regards
Peter Kwan
I am using C++, desktop application using wxWidgets framework.

  Re: Radial Bar Chart creation
Posted by Peter Kwan on Jan-25-2020 15:44
Attachments:
Hi Rand,

I have modified the "Round Meter" sample code included in ChartDirector to produced the attached meter. (If you are using wxWidgets port of the ChartDirector sample code, the original code is in "wxdemo/wxdemo/democharts.cpp".) The following subroutine creates the meter and return the chart object. You can then assign the chart object to the chart viewer for display. When the chart object is no longer needed, remember to delete it to avoid memory leak.


BaseChart *roundmeter(int /* chartIndex */, const char ** /* imageMap */)
{
    double value0 = 80;
    double value1 = 64;
    const char* label = "125%";

    AngularMeter *m = new AngularMeter(120, 120, 0x000000);
    double cx = m->getWidth() / 2;
    double cy = m->getHeight() / 2;

    m->setMeter(cx, cy, cx - 5, 0, 360);
    m->setScale(0, 100);
    m->setCap(0, Chart::Transparent);
    m->setMeterColors(Chart::Transparent, Chart::Transparent);

    m->addZone(0, value0, cx - 5, cx - 15, 0x55aaff);
    m->addZone(0, value1, cx - 15, cx - 25, 0xff8800);

    double bgGradient[] = { 0, 0xffffff, 0.75, 0xeeeeee, 1, 0xdddddd };
    m->addRing(0, cx - 25, m->relativeRadialGradient(DoubleArray(bgGradient, 6), cx - 25));
    m->addText(cx, cy, label, "ariali.ttf", 15, 0x000000, Chart::Center);

    m->makeChart();
    return m;
}


Hope this can help.

Regards
Peter Kwan
circular_bar.png

  Re: Radial Bar Chart creation
Posted by Rand on Feb-20-2020 21:28
Attachments:
Peter,
Thank you, that worked great.  The only problem I have is that the ring shows a segment if the value is 0 or max value for range.  In other words if range is 0 through 100 then the values 0 and 100 result in the same ring appearance.  I can set the range max to one more than required in order to fix the top end display but 0 still shows a thin line when I would expect it to show nothing. I have included my graph generation code below, and graph images are attached.  What am I doing wrong?

Also, if the value is greater than range max then the value displayed becomes (value - range_max) recursive until within range.  I am not concerned about this other than I wonder what is going on in the background as far as data manipulation is concerned because I would expect either a full ring to be drawn or an error to be generated.

<CODE>
SetGraphValues( const RadialBarValues& value )
{
const int max_bar_values_idx = value.bar_values.size() - 1;
wxASSERT_MSG( ( max_bar_values_idx > -1 ), "bar_values vector was empty" );
// No need to check other sizes here, if view_port_id does not match an existing view port then nothing is done
// and it is not an error to manipulate the same view_port_id more than once though only the last values
// will be retained.  If bar_values contains more than 3 items the remaining will be ignored
double     bgGradient[] = { 0, 0xFFFFFF, 0.5, 0xBEBEBE, 1, 0x7F7F7F };
BaseChart* old_chart    = nullptr;
for( auto& vpp : m_view_port_props )
{
if( ( vpp.id == value.view_port_id ) && ( vpp.view_port != nullptr ) )
{
const RadialBarGraphProps& props = vpp.graph_props;
// Create the meter
AngularMeter* angular_meter = new AngularMeter( 210, 210, Chart::Transparent );
double        cx            = angular_meter->getWidth() / 2;
double        cy            = angular_meter->getHeight() / 2;
angular_meter->setMeter( cx, cy, cx - 5, 0, 360 );
angular_meter->setScale( props.value_min, props.value_max );
angular_meter->setCap( 0, Chart::Transparent );
angular_meter->setMeterColors( Chart::Transparent, Chart::Transparent );

// Use switch fall through behavior to set values as needed
switch( max_bar_values_idx )
{
case 2:
angular_meter->addZone( 0, value.bar_values[2], cx - 5, cx - 15, COLOR_BAR_OUTER ); // blue zone
case 1:
angular_meter->addZone( 0, value.bar_values[1], cx - 15, cx - 25, COLOR_BAR_MIDDLE ); // green zone
case 0:
angular_meter->addZone( 0, value.bar_values[0], cx - 25, cx - 35, COLOR_BAR_INNER ); // yellow zone
}

angular_meter->addRing(
0, cx - 35, angular_meter->relativeRadialGradient( DoubleArray( bgGradient, 6 ), cx - 35 ), 0x000000 );

double disp_val = value.display_value;
// Round disp_val to a single digit of precision
disp_val                 = round( disp_val * 10 ) / 10;
std::string disp_val_str = std::to_string( disp_val ); // 6 DoP by default
disp_val_str             = disp_val_str.substr( 0, ( disp_val_str.length() - 5 ) );
// If the final digit is 0 then remove it and the decimal point
if( disp_val_str.find_last_of( '0' ) == disp_val_str.length() - 1 )
{
// Remove the decimal point and trailing 0
disp_val_str = disp_val_str.substr( 0, ( disp_val_str.length() - 2 ) );
}
angular_meter->addText(
cx, cy, disp_val_str.c_str(), "arialb.ttf", SIZE_FONT_GRAPH_LABEL, 0x000000, Chart::Center );
angular_meter->makeChart();
// If there is an existing chart in the view port, delete it
old_chart = vpp.view_port->getChart();
if( old_chart != nullptr )
{
delete old_chart;
old_chart = nullptr;
}
vpp.view_port->setChart( angular_meter );
}
}
m_sizer->Layout();
}
</CODE>
radial_bar_graph_images.png

  Re: Radial Bar Chart creation
Posted by Peter Kwan on Feb-20-2020 21:42
Hi Rand,

Instead of using:

m->addZone(0, v, r1, r2, color);

may be you can use:

if (v > 0) {
    if (v == 100)
       m->addRing(r1, r2, color, color);
    else
       m->addZone(0, v, r1, r2, color);
}

The above should take care of 0 and 100.

Hope this can help.

Regards
Peter Kwan