KoolReport's Forum

Official Support Area, Q&As, Discussions, Suggestions and Bug reports.
Forum's Guidelines

ColumnChart with DB Query #564

Open Jarmo Annunen opened this topic on on Dec 18, 2018 - 9 comments

Jarmo Annunen commented on Dec 18, 2018

I'm checking this example: https://www.koolreport.com/docs/google_charts/column_chart/

But I can't wrap my head around how I can convert MySQL Query to this format:

"dataSource"=>array(
    array("category"=>"Books","sale"=>32000,"color"=>"#4F5060"),
    array("category"=>"Accessories","sale"=>43000,"color"=>"#67819D"),
    array("category"=>"Phones","sale"=>54000,"color"=>"#ADBD37"),
    array("category"=>"Movies","sale"=>23000,"color"=>"#588133",),
    array("category"=>"Others","sale"=>12000,"color"=>"#003B45"),
),

I tried to fiddle around with Transpose, but that didn't get me so far.

Also tried to use Cube:

  ->pipe(new Cube(array(
                            "row" => "year",
                            "column" => "vat",
                            "sum" => "sale_amount"
                        )))

But it doesn't group into years for some reason when using the ColumnChart.

What I'm basically trying to do is to show yearly stats of sales which VAT as grouping.

 SELECT rr.vat,YEAR(r.tstamp) as year,sum(amount*price) as sale_amount 
                            FROM receipts r, receipt_row rr
                            where rr.receipt_id = r.id
                            GROUP BY year,rr.vat

This gives me

vat	year	sale_amount
10.0000	2015	207217.75000000
14.0000	2015	6187.36000000
24.0000	2015	57565.93000000
0.0000	2015	15511.03000000
10.0000	2016	275658.50000000
24.0000	2016	118417.46500000
14.0000	2016	12580.30000000
0.0000	2016	55515.60000000

And I don't have an idea how to get it to the right format for the ColumnChart. This is what I'm aiming for with the cube.

KoolReport commented on Dec 19, 2018

Could you briefly show us what is the format of your original data. How do you want to show on the chart?

Jarmo Annunen commented on Dec 19, 2018

Source data:

End result along these lines (but isStacked = true)

Jarmo Annunen commented on Dec 19, 2018

Ok, I looked at the data with fresh eyes. The problem seems to be that year 2015 is missing vat 10%.

Is there a way to check/fill missing values? I know the valid vat percentages before running the query.

KoolReport commented on Dec 19, 2018

You may prepend row to datastore with prepend() function:

https://www.koolreport.com/docs/datastore/overview/#adding-methods-prepend

KoolReport commented on Dec 19, 2018

Your way of using Cube process is correct. Your query is also correct. We need to combine both of them. First you query like you did

 SELECT rr.vat,YEAR(r.tstamp) as year,sum(amount*price) as sale_amount 
                            FROM receipts r, receipt_row rr
                            where rr.receipt_id = r.id
                            GROUP BY year,rr.vat

and then you pipe through Cube process:

 ->pipe(new Cube(array(
                            "row" => "year",
                            "column" => "vat",
                            "sum" => "sale_amount"
                        )))

You will get data like this:

year    {{all}}   10      24      14      0
2015    123.23    22.3    43.2    12.0    0
2016    123.23    22.3    43.2    21.0    12.3 

To visualize in ColumnChart you do:

ColumnChart::create(array(
    "dataSource"=>$this->dataStore('data'),
    "columns"=>array(
        "year",
        "0"=>array(
            "label"=>"VAT 0%",
        ),
        "10"=>array(
            "label"=>"VAT 10%",
        ),
        "14"=>array(
            "label"=>"VAT 14%",
        ),
        "24"=>array(
            "label"=>"VAT 24%",
        ),
    )
))
Jarmo Annunen commented on Dec 19, 2018

Now I got it to work, apart from the ColumnChart. It works if the {{all}} column is there and I use the same dataStore as for the Tabular data.

I optimized the SQL query so it be a little faster. So it groups the data instead of fetching all the rows for KoolReport to chew on.

So. With the source data:

With this code:

  $this->src("tools")->query("
                            SELECT rr.vat as vat,YEAR(r.tstamp) as year,sum(amount*price) as sale_amount 
                            FROM receipts r, receipt_row rr
                            where rr.receipt_id = r.id
                            and year(r.tstamp) in ( 2015, 2016, 2017)
                            group by year,vat
                            order by year,vat
                        ")
                        ->pipe(new ColumnMeta(array(
                            "year" => [
                                'type' => 'string',
                            ],
                            "vat" => [
                                'type' => 'string',
                            ],
                            "sale_amount"=>array(
                                'type' => 'number',
                                "suffix"=>"€",
                            ),
                        )))
                        ->pipe(new ValueMap(array(
                            'vat' => array(
                                '{func}' => function ($value) {
                                    return 'VAT ' . $value. "%";
                                },
                                "{meta}" => array(
                                    "type" => "string"
                                ),
                            )
                        )))
                        ->pipe(new Cube([
                            "row" => "year",
                            "column" =>"vat",
                            "sum" => "sale_amount",
                        ]))
                        ->saveTo($nodeForColumnChart)
                        ->pipe(new ColumnMeta(array(
                            "{{all}}" => array(
                                "label" => _("Total")
                            )    
                        )))
                        ->saveTo($nodeReady);

                        $nodeReady
                        ->pipe($this->dataStore('salescube'));

                        Table::create(array(
                            "dataStore" => $this->dataStore('salescube'),
                            'cssClass' => array('table' => 'table-condensed')
                        ));

                        $nodeForColumnChart
                        ->pipe(new RemoveColumn(array(
                            "{{all}}"
                        )))
                        ->pipe($this->dataStore("salescubeNoAll"));

                     ColumnChart::create(array(
                    "dataStore"=>  $this->dataStore("salescube"),
                    "options" => [
                        "isStacked" => true
                    ],
                     "clientEvents"=>array(
                        "itemSelect"=>"function(params){
                            saleDrillDown.next({year:params.selectedRow[0]});
                        }",
                    )
                ));

I get end result:

Now the only problem is that when I try do change the dataSource to 'salescubeNoAll' which is created like this:

 $nodeForColumnChart
                        ->pipe(new RemoveColumn(array(
                            "{{all}}"
                        )))
                        ->pipe($this->dataStore("salescubeNoAll"));

The ColumnChart doesn't show a chart but gives this error message: no data available in chart

Jarmo Annunen commented on Dec 19, 2018

And the answer seems to be little strange:

I have to prepare my dataStores BEFORE showing any of the tables/charts.

If I do this, it fails:

Prepare salescube
Show table
Prepare salescubeNoAll
Show ColumnChart

But this works:

Prepare salescube
Prepare salescubeNoAll
Show table
Show ColumnChart

Do you have any insight why that happens?

Jarmo Annunen commented on Dec 19, 2018

Thanks for the help =) Highly appreciated!

KoolReport commented on Dec 19, 2018

Thank you very much for your tips. Really appreciated!

About your last question, after your call run() the data will be piped then end to render view. So basically no piping in view. That's the reason why the "salescubeNoAll" is empty. If you want to further process in the view. You need to use the process() function of DataStore to do additional process like RemoveColumn.

DataStore also has some powerful data process of itself such as except() function which works the same like RemoveColumn. It will return new data store excluded some columns.

If you have use Laravel before, you may consider DataStore as Laravel's Collection class. The idea of those methods available in DataStore is to reduce to complexity of coding in data processing phase. Manytimes, several charts/tables share the same datastore ( like in your case) but there is only slightly different requirement in data supply so we only need to prepare a common datastore then for each charts or tables we add a little further process. Like in your case, you may need only "salecube" datastore and later in the column chart you can do:

ColumnChart::create(array(
    "dataSource"=>$this->dataStore('salecube')->except("{{all}}")
))

I am very happy that you have done report by yourself, I did very little to assist. There is little learning curve to start with KoolReport but once you get there, you will feel very much comfortable and flexible.

Thank you for your tips again :)

Build Your Excellent Data Report

Let KoolReport help you to make great reports. It's free & open-source released under MIT license.

Download KoolReport View demo
help needed
solved

Cube