How to build “Star Rating” report in BigQuery (or sparklines, or color gradients)

后端 未结 5 1164
忘了有多久
忘了有多久 2021-02-03 14:44

Suppose I have the followng sample input:

WITH Ratings AS (
    (SELECT \'A\' name, 2 score) UNION ALL
    (SELECT \'B\' name, 0 score) UNION ALL
    (SELECT \'C         


        
相关标签:
5条回答
  • 2021-02-03 15:09

    We can build star rating as a string using two Unicode characters:

    ★ - Unicode code point 9733 
    ☆ - Unicode code point 9734
    

    We can use CODE_POINTS_TO_STRING function to build the stars, and REPEAT function to produce the right number of stars

    Combined together the solution for sample input will be:

    WITH Ratings AS (
    (SELECT 'A' name, 2 score) UNION ALL
    (SELECT 'B' name, 0 score) UNION ALL
    (SELECT 'C' name, 5 score) UNION ALL
    (SELECT 'D' name, 1 score))
    
    SELECT 
      name, 
      CONCAT(
        REPEAT(CODE_POINTS_TO_STRING([9733]), score),
        REPEAT(CODE_POINTS_TO_STRING([9734]), 5-score)) score
    FROM Ratings
    

    It will produce the following result:

    name    score
    A       ★★☆☆☆
    B       ☆☆☆☆☆
    C       ★★★★★
    D       ★☆☆☆☆
    
    0 讨论(0)
  • 2021-02-03 15:26

    Adding more-less generic option for producing time-series/sparklines type of report

    #standardSQL
    CREATE TEMP FUNCTION sparklines(arr ARRAY<INT64>) AS ((
      SELECT STRING_AGG(CODE_POINTS_TO_STRING([code]), '') 
      FROM UNNEST(arr) el, 
      UNNEST([(SELECT MAX(el) FROM UNNEST(arr) el)]) mx, 
      UNNEST([(SELECT MIN(el) FROM UNNEST(arr) el)]) mn
      JOIN UNNEST([9602, 9603, 9605, 9606, 9607]) code WITH OFFSET pos
      ON pos = CAST(IF(mx = mn, 1, (el - mn) / (mx - mn)) * 4 AS INT64) 
    )); 
    WITH series AS (
      SELECT 1 id, [3453564, 5343333, 2876345, 3465234] arr UNION ALL
      SELECT 2, [5743231, 3276438, 1645738, 2453657] UNION ALL
      SELECT 3, [1,2,3,4,5,6,7,8,9,0] UNION ALL
      SELECT 4, [3245876, 2342879, 5876324, 7342564]  
    )  
    SELECT 
      id, TO_JSON_STRING(arr) arr, sparklines(arr) sparklines 
    FROM series 
    

    with result as below

    Row id  arr                                 sparklines   
    1   1   [3453564,5343333,2876345,3465234]   ▃▇▂▃     
    2   2   [5743231,3276438,1645738,2453657]   ▇▅▂▃     
    3   3   [1,2,3,4,5,6,7,8,9,0]               ▂▃▃▅▅▆▆▇▇▂   
    4   4   [3245876,2342879,5876324,7342564]   ▃▂▆▇       
    

    Adding Mosha's version (taken from his comments below)

    #standardSQL
    CREATE TEMP FUNCTION barchart(v ARRAY<FLOAT64>, MIN FLOAT64, MAX FLOAT64) AS ( 
      IF(
        MIN = MAX, 
        REPEAT(CODE_POINTS_TO_STRING([9603]), ARRAY_LENGTH(v)), 
        (
        SELECT STRING_AGG(CODE_POINTS_TO_STRING([9601 + CAST(ROUND(y) AS INT64)]), '') 
        FROM ( 
          SELECT SAFE_DIVIDE(e-min, MAX - MIN) * 7 y 
          FROM UNNEST(v) e)
        )
      )
    ); 
    CREATE TEMP FUNCTION vbar(v ARRAY<FLOAT64>) AS ( 
      barchart(v, (SELECT MIN(a) FROM UNNEST(v) a), (SELECT MAX(a) FROM UNNEST(v) a)) 
    );
    WITH numbers AS (
      SELECT 1 id, [3453564., 5343333., 2876345., 3465234.] arr UNION ALL
      SELECT 2, [5743231., 3276438., 1645738., 2453657.] UNION ALL
      SELECT 3, [1.,2,3,4,5,6,7,8,9,0] UNION ALL
      SELECT 4, [3245876., 2342879, 5876324, 7342564]  
    )  
    SELECT 
      id, TO_JSON_STRING(arr) arr, vbar(arr) sparklines 
    FROM numbers  
    

    if applied to same dummy data as above versions - produces below

    Row id  arr                                 sparklines   
    1   1   [3453564,5343333,2876345,3465234]   ▃█▁▃     
    2   2   [5743231,3276438,1645738,2453657]   █▄▁▂     
    3   3   [1,2,3,4,5,6,7,8,9,0]               ▂▃▃▄▅▆▆▇█▁   
    4   4   [3245876,2342879,5876324,7342564]   ▂▁▆█      
    
    0 讨论(0)
  • 2021-02-03 15:27

    Fitting vertical bar chart into single character is challenging because there are only 8 different heights we could use. But horizontal bar charts don't have this limitation, we can scale horizontal chart by arbitrary length. Example below uses 30, and it shows number of births per day of week as horizontal bar chart. Data is based on public dataset:

    create temp function hbar(value int64, max int64) as (
      repeat('█', cast(30 * value / max as int64))
    );
    select 
      ['sunday', 'monday', 'tuesday', 'wednesday',
       'thursday', 'friday', 'saturday'][ordinal(wday)] wday, bar from (
    select wday, hbar(count(*), max(count(*)) over()) bar
    from `bigquery-public-data.samples.natality`
    where wday is not null
    group by 1
    order by 1 asc)
    

    Results in

    wday      bar
    ---------------------------------------------
    sunday    ███████████████████
    monday    ███████████████████████████
    tuesday   ██████████████████████████████
    wednesday ██████████████████████████████
    thursday  █████████████████████████████
    friday    █████████████████████████████
    saturday  █████████████████████
    
    0 讨论(0)
  • 2021-02-03 15:29

    More craziness here

    0 讨论(0)
  • 2021-02-03 15:30

    My entry does a color gradient, because sparklines only look good with certain fonts - and that's not a font that the BigQuery web UI uses.

    During a day, when is Stack Overflow the most active per tag:

    #standardSQL
    CREATE TEMP FUNCTION barchart(v ARRAY<FLOAT64>, mm STRUCT<min FLOAT64, max FLOAT64>) AS ((
        SELECT STRING_AGG(SUBSTR('                                                                    
    0 讨论(0)
提交回复
热议问题