1

I would like to generate usage bar (like this one): enter image description here

I dont know where to start.. is it possible to do it with TikZ ? Any example will help a lot.

Thank you

1
  • 3
    It is possible with TikZ (and pgplots may be more convenient). The very least you may want to do is to at least specify the way you want to set the data, and provide a sample set of data.
    – user230294
    Dec 10, 2020 at 19:53

1 Answer 1

7

The weights are automatically standardized.

(Somehow I confused the name with "progress bar", please ignore this mistake)

enter image description here

\documentclass{article}
\usepackage{xcolor}
\usepackage{expl3}
\usepackage{tikz}
\usepackage{amsmath, amssymb}
\usepackage[inline]{enumitem}

\usetikzlibrary{positioning,shapes.misc}



\ExplSyntaxOn

\clist_new:N \g_pb_colors_clist
% these are the colors used by the progress bar
% number of items should not exceed the number of colors here
% the last color will always be used for the last item in the bar
\clist_gset:Nn \g_pb_colors_clist {
    6495ed,
    006400,
    00008b,
    b03060,
    ff4500,
    ffd700,
    7fff00,
    00ffff,
    ff00ff,
    ffdab9,
    a0a0a0
}

% the dimensions of progress bar (in cm)
\fp_new:N \g_pb_width_fp
\fp_new:N \g_pb_height_fp
\fp_gset:Nn \g_pb_width_fp {5.0}
\fp_gset:Nn \g_pb_height_fp {0.5}

% radius of rounded corners (in cm)
\fp_new:N \g_pb_corner_radius_fp
\fp_gset:Nn \g_pb_corner_radius_fp {0.2}

% helper function to get names of colors
\cs_set:Npn \pb_color_name:n #1 {
    pb-internal-color-\int_to_alph:n{#1}
}

\cs_set_eq:NN \color_define:nnn \definecolor
\cs_generate_variant:Nn \color_define:nnn {xnx}

% declare all colors
\int_step_inline:nn {\clist_count:N \g_pb_colors_clist} {
    \tl_set:Nn \l_tmpa_tl {\clist_item:Nn \g_pb_colors_clist {#1}}
    \color_define:xnx {\pb_color_name:n {#1}}{HTML}{\l_tmpa_tl}
}

% the last color
\tl_new:N \g_pb_last_color_tl
\tl_gset:Nx \g_pb_last_color_tl {\pb_color_name:n {\clist_count:N \g_pb_colors_clist}}


\cs_set:Npn \__pb_node_template:nnn #1#2#3 {
    \node[pbnode,#1]~at~(#2~cm,#3~cm)~{};
}

\cs_set:Npn \__pb_draw_left:nn #1#2 {
    \fill[#1]
      (0~cm,0~cm) --
      ++(#2~cm,0~cm)  --
      ++(0,-\fp_use:N \g_pb_height_fp~cm) {[rounded~corners=\fp_use:N \g_pb_corner_radius_fp~cm] --
      ++(-#2~cm,0~cm) --
      cycle}
      {};
}

\cs_set:Npn \__pb_draw_middle:nn #1#2 {
    \fill[#1]
      (0~cm,0~cm) --
      ++(#2~cm,0~cm)  --
      ++(0,-\fp_use:N \g_pb_height_fp~cm) --
      ++(-#2~cm,0~cm) --
      cycle
      {};
}

\cs_set:Npn \__pb_draw_right:nn #1#2 {
    \fill[#1]
      (0~cm,0~cm) {[rounded~corners=\fp_use:N \g_pb_corner_radius_fp~cm] --
      ++(#2~cm,0~cm)  --
      ++(0,-\fp_use:N \g_pb_height_fp~cm)} --
      ++(-#2~cm,0~cm) --
      cycle
      {};
}

\cs_set:Npn \__pb_draw_both:nn #1#2 {
    \fill[#1, rounded~corners=\fp_use:N \g_pb_corner_radius_fp~cm]
      (0~cm,0~cm) --
      ++(#2~cm,0~cm)  --
      ++(0,-\fp_use:N \g_pb_height_fp~cm) --
      ++(-#2~cm,0~cm) --
      cycle
      {};
}


% helper function to get the correct color
\cs_set:Npn \pb__fetch_color:nN #1#2 {
    \int_compare:nNnTF {#1} = {\clist_count:N #2} {
        \g_pb_last_color_tl
    } {
        \pb_color_name:n {#1}
    }
}

\clist_new:N \l_pb_tmpa_clist
\clist_new:N \l_pb_tmpb_clist
\clist_new:N \l_pb_tmpc_clist
\seq_new:N \l_pb_tmpa_seq
\fp_new:N \l_pb_tmpa_fp
\fp_new:N \l_pb_tmpb_fp
\fp_new:N \l_pb_tmpc_fp
\tl_new:N \l_pb_tmpa_tl
\tl_new:N \l_pb_tmpb_tl
\int_new:N \l_pb_tmpa_int
\int_new:N \l_pb_tmpb_int

\cs_set:Npn \pb_progress_bar:nn #1#2 {
    \clist_set:Nn \l_pb_tmpa_clist {#1}
    \clist_set:Nn \l_pb_tmpb_clist {#2}
    \int_compare:nNnF {\clist_count:N \l_pb_tmpa_clist} = 
        {\clist_count:N \l_pb_tmpb_clist} {
        \GenericError{}{progress~bar~error}
            {}{number~of~items~does~not~match~the~number~of~weights}
    }
    \int_compare:nNnT {\clist_count:N \l_pb_tmpa_clist} > 
        {\clist_count:N \g_pb_colors_clist} {
        \GenericError{}{progress~bar~error}
            {}{number~of~progress~bar~items~exceeds~number~of~colors}
    }
    % compute total weights
    \fp_set:Nn \l_pb_tmpa_fp {0.0}
    \clist_map_inline:Nn \l_pb_tmpb_clist {
        \fp_add:Nn \l_pb_tmpa_fp {##1}
    }
    \fp_set:Nn \l_pb_tmpc_fp {0.0}
    
    % determine drawing range
    \int_set:Nn \l_pb_tmpa_int {1}
    \int_set:Nn \l_pb_tmpb_int {\clist_count:N \l_pb_tmpa_clist}
    
    \clist_map_inline:Nn \l_pb_tmpb_clist {
      \fp_compare:nNnT {##1} > {0} {
        \clist_map_break:
      }
      \int_incr:N \l_pb_tmpa_int
    }
    
    \clist_set_eq:NN \l_pb_tmpc_clist \l_pb_tmpb_clist
    \clist_reverse:N \l_pb_tmpc_clist
    \clist_map_inline:Nn \l_pb_tmpc_clist {
      \fp_compare:nNnT {##1} > {0} {
        \clist_map_break:
      }
      \int_decr:N \l_pb_tmpb_int
    }
    
    % draw progress bar
    \begin{tikzpicture}
        \int_compare:nNnTF {\l_pb_tmpa_int} = {\l_pb_tmpb_int} {
            \fp_set:Nn \l_pb_tmpb_fp {
                \g_pb_width_fp
            }
            \tl_set:Nn \l_pb_tmpa_tl {
                color=\pb__fetch_color:nN {\l_pb_tmpa_int} \l_pb_tmpa_clist,
            }
            \exp_args:NV \__pb_draw_both:nn \l_pb_tmpa_tl {\fp_use:N \l_pb_tmpb_fp}
        } {
        \int_step_inline:nnn {\l_pb_tmpa_int} {\l_pb_tmpb_int} {
                % compute width
                \fp_set:Nn \l_pb_tmpb_fp {
                    \clist_item:Nn \l_pb_tmpb_clist {##1} / \l_pb_tmpa_fp * \g_pb_width_fp
                }
                \tl_set:Nn \l_pb_tmpa_tl {
                    color=\pb__fetch_color:nN {##1} \l_pb_tmpa_clist,
                    xshift=\fp_use:N\l_pb_tmpc_fp~cm,
                }
                % call corresponding drawing command
                \int_case:nnF {##1} {
                    {\l_pb_tmpa_int} {
                        \exp_args:NV \__pb_draw_left:nn \l_pb_tmpa_tl {\fp_use:N \l_pb_tmpb_fp}
                    }
                    {\l_pb_tmpb_int} {
                        \exp_args:NV \__pb_draw_right:nn \l_pb_tmpa_tl {\fp_use:N \l_pb_tmpb_fp}
                    }
                } {
                    \exp_args:NV \__pb_draw_middle:nn \l_pb_tmpa_tl {\fp_use:N \l_pb_tmpb_fp}
                }
                % update offset
                \fp_add:Nn \l_pb_tmpc_fp {\l_pb_tmpb_fp}
            }
        }
    \end{tikzpicture}
    % construct legend
    \seq_clear:N \l_pb_tmpa_seq
    \int_step_inline:nn {\clist_count:N \l_pb_tmpa_clist} {
        \seq_put_right:Nx \l_pb_tmpa_seq {
            \exp_not:N\item
            [\exp_not:N\textcolor{\pb__fetch_color:nN {##1} \l_pb_tmpa_clist}{$\exp_not:N\blacksquare$}] {
                \clist_item:Nn \l_pb_tmpa_clist {##1}
            }
        }
    }
    \par\begin{itemize*}
        \seq_use:Nn \l_pb_tmpa_seq {}
    \end{itemize*}
}

\newcommand{\progressbar}[2]{
    \pb_progress_bar:nn {#1}{#2}
}

\ExplSyntaxOff


\begin{document}

\begin{minipage}{6cm}
\centering
\progressbar{E, A, Media, Apps, Photos, Other, B, C, D}{0, 0, 1,2,3,4, 0, 0, 0}
\end{minipage}

\begin{minipage}{6cm}
\centering
\progressbar{A,B,C,D,E}{0,0,1,0,0}
\end{minipage}

\begin{minipage}{6cm}
\centering
\progressbar{lorem,ipsum,dolor,sit,amet,consectetur,adipiscing,elit,sed,do,eiusmod}
    {4, 5, 7, 1, 2, 5, 7, 9, 3, 6, 4}
\end{minipage}


\end{document}
6
  • Hi .. there is a small bug in code.. if the first argument is 0, then the left border is not rounded.. can you fix that ?
    – Anya93
    Dec 16, 2020 at 10:09
  • @Anya93 updated.
    – Alan Xiang
    Dec 16, 2020 at 17:27
  • Thank you now its almost perfect :) .. the right border is not rounded in some cases.. for example \progressbar{a,b,c,d}{0,8,0,0}
    – Anya93
    Dec 16, 2020 at 19:08
  • @Anya93 Well, it is a special case when there is essentially only one bar. In that case, you only need to draw a rounded rectangle. Do you want me to fix it?
    – Alan Xiang
    Dec 16, 2020 at 22:26
  • If it is not a problem for you.. that would be perfect.. thank you
    – Anya93
    Dec 19, 2020 at 14:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .