wxIshiko / wxCharts

A library to create charts in wxWidgets applications
https://www.wxishiko.com/wxCharts/
MIT License
114 stars 50 forks source link

Legend for StackedColumnChart #166

Open gismowdd opened 4 years ago

gismowdd commented 4 years ago

When I add a legend to my stacked column chart it only uses the 2 default colors. I assume there is a default theme similar to my previous issue that needs to be modified.

StackedBarChart

Kvaz1r commented 4 years ago

It's similar but a bit more tricky. wxChartsLegendCtrl doesn't have own theme it's only use theme from wxLineChartCtrl. So to use it properly one should update one of those themes (or made LineChartDatasetOptions as in wxStackedColumnChartDatasetOptions or vice versa). For example(paste this code after updating default theme):

    for (int i = 0; i < nDatasets; i++) //nDatasets - amount of datasets
    {
        auto color = wxChartsDefaultTheme->GetDatasetTheme(wxChartsDatasetId::CreateImplicitId(i))->GetStackedColumnChartDatasetOptions()->GetBrushOptions().GetColor();
        wxChartsDefaultTheme->GetDatasetTheme(wxChartsDatasetId::CreateImplicitId(i))->SetLineChartDatasetOptions(
            wxLineChartDatasetOptions(
                color,
                color,
                color
            )
        );
    }
gismowdd commented 4 years ago

I'm getting the same shared pointer error that I got on the previous issue. The chartData has 1 categorical data sets and 5 double datasets so I set nDatasets = 7 and I get the shared pointer error. I tried setting nDatasets to 8 and the app closed on execcution.

` void AcornFrame::OnButtonGraphClick(wxCommandEvent& event) {

wxChartsDatasetTheme datasettheme = new wxChartsDatasetTheme(); datasettheme->SetStackedColumnChartDatasetOptions(wxStackedColumnChartDatasetOptions( wxChartsPenOptions(wxGREEN, 2), wxChartsBrushOptions(*wxGREEN)

));

wxChartsDefaultTheme->SetDatasetTheme(wxChartsDatasetId::CreateImplicitId(3), wxSharedPtr<wxChartsDatasetTheme>(datasettheme));

wxChartsDatasetTheme* datasettheme1 = new wxChartsDatasetTheme();
datasettheme1->SetStackedColumnChartDatasetOptions(wxStackedColumnChartDatasetOptions(
    wxChartsPenOptions(*wxRED, 2),
    wxChartsBrushOptions(*wxRED)
));
wxChartsDefaultTheme->SetDatasetTheme(wxChartsDatasetId::CreateImplicitId(4), wxSharedPtr<wxChartsDatasetTheme>(datasettheme1));

int i,j; wxWindow* ChartWindow = new wxWindow(Panel5,wxID_ANY,wxDefaultPosition, wxSize(1312,800));

// Create the data for the bar chart widget
double testno1;
double testno2;
double testno3;
double testno4;
double testno5;

 // Add the categorical dataset
wxVector<wxString> points0;
for(j=1;j<7;++j)
{
double testno=stumpdbh10table[0][j];
wxString teststring=wxString::Format(wxT("%4.1f"), testno);
points0.push_back(teststring);
}

    wxVector<wxString> labels;
labels.push_back("0.5");
labels.push_back("1.5");
labels.push_back("2.5");
labels.push_back("3.5");
labels.push_back("4.5");
labels.push_back("5.5");

//wxChartsCategoricalData::ptr chartData=(new wxChartsDoubleDataset("Dataset 0", points0));
 wxChartsCategoricalData::ptr chartData = wxChartsCategoricalData::make_shared(labels);

// Add the first dataset
wxVector<wxDouble> points1;
for(j=1;j<7;++j)
{

testno1=stumpdbh10table[6][j];
points1.push_back(testno1);
}
wxChartsDoubleDataset::ptr dataset1(new wxChartsDoubleDataset("MIXED HARDWOODS", points1));
chartData->AddDataset(dataset1);

// Add the second dataset
wxVector<wxDouble> points2;
for(j=1;j<7;++j)
{

testno2=stumpdbh10table[7][j];
points2.push_back(testno2);
}
wxChartsDoubleDataset::ptr dataset2(new wxChartsDoubleDataset("CONIFER SPECIES", points2));
chartData->AddDataset(dataset2);
//legenData->AddDataset(dataset2);

// Add the third dataset
    wxVector<wxDouble> points3;
for(j=1;j<7;++j)
{

testno3=stumpdbh10table[8][j];
points3.push_back(testno3);
}
wxChartsDoubleDataset::ptr dataset3(new wxChartsDoubleDataset("HICKORY SPECIES", points3));
chartData->AddDataset(dataset3);

// Add the fourth dataset
  wxVector<wxDouble> points4;
for(j=1;j<7;++j)
{

testno4=stumpdbh10table[10][j];
points4.push_back(testno4);
}
wxChartsDoubleDataset::ptr dataset4(new wxChartsDoubleDataset("GUM SPECIES", points4));
chartData->AddDataset(dataset4);

// Add the fifth dataset
wxVector<wxDouble> points5;
for(j=1;j<7;++j)
{
testno5=stumpdbh10table[5][j];
points5.push_back(testno5);
}
wxChartsDoubleDataset::ptr dataset5(new wxChartsDoubleDataset("WHITE OAK GROUP", points5));
chartData->AddDataset(dataset5);

// Create the legend widget

for (int i = 0; i < 7; i++) //nDatasets - amount of datasets
{
    auto color = wxChartsDefaultTheme->GetDatasetTheme(wxChartsDatasetId::CreateImplicitId(i))->GetStackedColumnChartDatasetOptions()->GetBrushOptions().GetColor();
    wxChartsDefaultTheme->GetDatasetTheme(wxChartsDatasetId::CreateImplicitId(i))->SetLineChartDatasetOptions(
        wxLineChartDatasetOptions(
            color,
            color,
            color
        )
    );
}

wxChartsLegendData legendData(chartData->GetDatasets());
wxChartsLegendCtrl* legendCtrl = new wxChartsLegendCtrl(ChartWindow, wxID_ANY, legendData,wxPoint(0,0),wxSize(150,100), wxSIMPLE_BORDER);

// Create the bar chart widget

wxStackedColumnChartCtrl* stackedColumnChartCtrl = new wxStackedColumnChartCtrl(ChartWindow,
wxID_ANY, chartData, wxPoint(151,0),wxSize(800,500));

} `

Kvaz1r commented 4 years ago

nDatasets is 5 in your case because you have 5 values on legend.

You got shared pointer error because you created chart before updating theme. All theme updates should be done before creating any chart control.

gismowdd commented 4 years ago

Thanks again for all your help. Worked like a charm. One last question is there a way to specify colors by rbg values?

Kvaz1r commented 4 years ago

Yes, just use wxColour object:

    datasettheme->SetStackedColumnChartDatasetOptions(wxStackedColumnChartDatasetOptions(
        wxChartsPenOptions(*wxBLACK, 2),
        wxChartsBrushOptions(wxColour(208,208,28))
    ));
gismowdd commented 4 years ago

I think the LineChartDatasetOptions stays in memory. If I build it after rebooting it executes and makes the changes fine. But if I rebuild it again it dies on execution. If I then drop your linechart loop out and recompile on execution it runs but without the changes the loop makes. Then if I recompile again with the loop in it makes the changes and looks fine

gismowdd commented 4 years ago

Yeah I added event.Skip(); at the end and it all works fine. Thanks for your help and patienc.e

gismowdd commented 4 years ago

In the stacked bars the first data set is at the bottom of the bar but it's at the top of the legend. Is there a way to reverse the order of the legend so that the first data set is at the bottom of the legend so that the order of the legend matches the order on the bars?

Kvaz1r commented 4 years ago

You can construct data for legend in any order, just put them in separate wxVector and pass to the wxChartsLegendData constructor instead of chartData->GetDatasets().

gismowdd commented 4 years ago

So I added the data set to a new data set in reverse order of the data used to make the chart:

` reverseChartdata->AddDataset(dataset13); reverseChartdata->AddDataset(dataset12); reverseChartdata->AddDataset(dataset11); reverseChartdata->AddDataset(dataset10); reverseChartdata->AddDataset(dataset9); reverseChartdata->AddDataset(dataset8); reverseChartdata->AddDataset(dataset7); reverseChartdata->AddDataset(dataset6); reverseChartdata->AddDataset(dataset5); reverseChartdata->AddDataset(dataset4); reverseChartdata->AddDataset(dataset3); reverseChartdata->AddDataset(dataset2); reverseChartdata->AddDataset(dataset1);

// Create the legend widget

wxChartsLegendData legendData(reverseChartdata->GetDatasets());
wxChartsLegendCtrl* legendCtrl = new wxChartsLegendCtrl(ChartWindow, wxID_ANY, legendData,wxPoint(991,30),wxSize(130,300), wxSIMPLE_BORDER);`

but the colors in the legend are still in the same order though the names are in the correct order. I need to flip the order of the colors in the legend.

Kvaz1r commented 4 years ago

Right it won't work.

As we "transfer" colors from StackedColumnChartDataset (main chart) into LineChartDataset(legend) in usual order (0-0, 1-1, ...) so for flipping we should do it in reverse order (0-nDatasets-1, 1 - nDatasets-2,...). So loop above become:

    for (int i = 0; i < nDatasets; i++)
    {
        auto color = wxChartsDefaultTheme->GetDatasetTheme(wxChartsDatasetId::CreateImplicitId(nDatasets-i-1))->GetStackedColumnChartDatasetOptions()->GetBrushOptions().GetColor();
        wxChartsDefaultTheme->GetDatasetTheme(wxChartsDatasetId::CreateImplicitId(i))->SetLineChartDatasetOptions(
            wxLineChartDatasetOptions(
                color,
                color,
                color
            )
        );
    }
gismowdd commented 4 years ago

Got it thanks