How to make a groupedbar plot with several stacked bars

It’s really hard to explain in words what I would like to do, so here is a picture:
Screenshot%20from%202019-08-08%2011-38-03

The black lines represent “levels” - each level has a stacked bar in it.

I know how this was done in Matlab, I just need help translating it to Julia. Say for example that for a particular x value I have 3 levels, and 2 different values in each level, then to plot this you plot the bar as a vector, but you specify the colors in the bar for each level. You also don’t show the legend, and just create the legend yourself, since otherwise Matlab (and, I imagine, Plots) get confused.

Assuming I use groupedbar from StatsPlots to do this, what I would like to know is:

  • How to specify colours for each segment of a bar in the graph
  • How to make a custom legend (i.e. a text box) with square boxes for colours next to the legend entry.

Matlab code is below:

% sort the generation matrix by technology

logInd_TN = ismember(p.plant.portfolio(:,1),[1]);

logInd_ST = ismember(p.plant.portfolio(:,1),[2:14,33:42,50]);

logInd_ST_coal = ismember(p.plant.portfolio(:,1),[5:7,36:38]);

logInd_ST_lignite = ismember(p.plant.portfolio(:,1),[2:4,33:35]);

logInd_ST_oil = ismember(p.plant.portfolio(:,1),[11:12,41]);

logInd_ST_gas = ismember(p.plant.portfolio(:,1),[8:9,39,50]);

logInd_CCGT = ismember(p.plant.portfolio(:,1),[15:18,43:45]);

logInd_CCGT_small = ismember(p.plant.portfolio(:,1),[15:18,43:45]) & p.plant.portfolio(:,4) <= 150; %

logInd_CCGT_large = ismember(p.plant.portfolio(:,1),[15:18,43:45]) & p.plant.portfolio(:,4) > 150; %

logInd_GT = ismember(p.plant.portfolio(:,1),[19:25,46:49,51]);

logInd_IC = ismember(p.plant.portfolio(:,1),[26:32]);

reserves_prob = [];

for rr = 1:u.plant.reservelevels

  reserves_prob = [reserves_prob;

    r.plant.spreserve_up_levels(logInd_TN,:,rr);

    r.plant.spreserve_up_levels(logInd_ST,:,rr);

    r.plant.spreserve_up_levels(logInd_CCGT,:,rr);

    r.plant.nspreserve_up_levels(logInd_GT,:,rr);

    r.plant.spreserve_up_levels(logInd_GT,:,rr);

    r.plant.nspreserve_up_levels(logInd_IC,:,rr);

    r.transactions.reserve_levels(:,rr,1)';

    r.plant.reserve_up_shed(:,1,rr)'];

end

 

pwd;

currentFolder = pwd;

fpath = [strcat(currentFolder,'\',i.resultstring)]; % it is saved in the result folder

figure('units','normalized','outerposition',[0 0 1 1]) % make the figure full screen

h1 = bar(reserves_prob','stacked','BarWidth',1,'EdgeColor','none','EdgeAlpha',0); hold on

% set(h,'EdgeColor','black');

aa = sum(logInd_TN);

bb = sum(logInd_ST);

cc = sum(logInd_CCGT);

dd = sum(logInd_GT)*2;

ee = sum(logInd_IC);

ff = 1;

gg = 1;

rr = aa+bb+cc+dd+ee+ff+gg;

for ll = 1:u.plant.reservelevels

set(h1((ll-1)*rr+1:(ll-1)*rr+aa),'FaceColor','b');

set(h1((ll-1)*rr+aa+1:(ll-1)*rr+aa+bb),'FaceColor','r');

set(h1((ll-1)*rr+aa+bb+1:(ll-1)*rr+aa+bb+cc),'FaceColor','g');

set(h1((ll-1)*rr+aa+bb+cc+1:(ll-1)*rr+aa+bb+cc+dd),'FaceColor','c');

set(h1((ll-1)*rr+aa+bb+cc+dd+1:(ll-1)*rr+aa+bb+cc+dd+ee),'FaceColor','m');

set(h1((ll-1)*rr+aa+bb+cc+dd+ee+1:(ll-1)*rr+aa+bb+cc+dd+ee+ff),'FaceColor',[255,127,0]/256);

set(h1((ll-1)*rr+aa+bb+cc+dd+ee+ff+1:(ll-1)*rr+aa+bb+cc+dd+ee+ff+gg),'FaceColor',[0.5 0.5 0.5]);

end

 

annotation('textbox','Position',[0.8 0.85 0.08 0.03],'String','RR shed','Color',[0.5 0.5 0.5],'FontSize',12,'FontWeight','bold');

annotation('textbox','Position',[0.8 0.82 0.08 0.03],'String','RES','Color',[255,127,0]/256,'FontSize',12,'FontWeight','bold');

annotation('textbox','Position',[0.8 0.79 0.08 0.03],'String','IC     (NSR)','Color','m','FontSize',12,'FontWeight','bold');

annotation('textbox','Position',[0.8 0.76 0.08 0.03],'String','GT    (NSR)','Color','c','FontSize',12,'FontWeight','bold');

annotation('textbox','Position',[0.8 0.73 0.08 0.03],'String','CCGT (SR)','Color','g','FontSize',12,'FontWeight','bold');

annotation('textbox','Position',[0.8 0.70 0.08 0.03],'String','ST       (SR)','Color','r','FontSize',12,'FontWeight','bold');

annotation('textbox','Position',[0.8 0.67 0.08 0.03],'String','TN       (SR)','Color','b','FontSize',12,'FontWeight','bold');

 for tt = 1:s.period

  for ss = 1:s.reserve

    i_opt = ceil(tt/(s.solopt));

    if rem(tt,s.solopt) == 0; t_opt = s.solopt; else t_opt = rem(tt,s.solopt); end

    RR_up(tt,:) = sum(p.reserve.levels(i_opt,:,t_opt,1,:,r.scenario_branch),5)';                      % upward reserves requirement [MW]

    RR_down(tt,:) = sum(p.reserve.levels(i_opt,:,t_opt,2,:,r.scenario_branch),5)';                    % downward reserves requirement [MW]

    end

end

 for ll = 1:u.plant.reservelevels

   plot(sum(RR_up(:,1:ll),2),'b','LineWidth',2)

end

 

str1 = sprintf([i.read.useroptions{2,2} '-RR-FINAL          ' i.resultstring]);

str2 = sprintf('RSF: %g h  RSR: %g h  RPCD: %g h  RPF: %g h  PH: %g h  SULT: %g  RR option: %g  RR levels: %g  Tol.: %g %%',u.time.reservesfreq,u.time.RRresolution,u.time.reservescd,u.time.opt,u.time.opt+u.time.optseq,u.plant.suleadtimes,u.plant.reserve,u.plant.reservelevels,round(u.solver.tol,2));

title({str1,str2},'interpreter','none')

% ax = gca; ax.XTick = [1,6,12,18,24]; get(gca,'XTick'); set(gca,'FontSize',12)

ylabel('Operational reserves (MW)','FontSize',12)

xlabel(['Timestep (' num2str(s.timestep) ' h)'],'FontSize',12)

The groupedbar recipe in StatsPlots.jl should do the trick.

Thanks, but I was more wondering how to specify colours and make the custom legend.

This is based on the Plots.jl library, so the same way you do there.

using StatsPlots

m = rand(5,3)

groupedbar(m, 
    label = ["first thing" "second thing" "third thing"],
    color = [:green :lightgrey :purple] # can also use Colors.jl or ColorBrewer.jl
    )

Note: I’m on mobile so I can’t guarantee that works, but something like that. Check out the docs for Plots.jl. each individual set (color) is called a “series”.

1 Like

I think I wasn’t clear with what I wanted to do. In any case, here’s my code in it’s entirety to show what I ended up doing. It’s not a minimal working example, it’s just there as guidance for anyone else who wants to try doing this.

My main things to solve my problems were:

  1. The series colour repeats, so if you have 30 series and 6 colours then you will get 6 colours repeated 5 times in the order you specify
  2. I used an empty plot to make a custom legend

You can find an example picture at the bottom.

GRP = gep.GRP; P = gep.P; T = gep.T; L⁺ = gep.L⁺
    nRP = length(GRP) # Number of reserve providers
    nL = length(L⁺)

    rL⁺ = gep[:rL⁺].data
    curtL⁺ = gep[:curtL⁺].data
    LSL⁺ = reshape(gep[:LSL⁺].data, (1,size(gep[:LSL⁺])...))
    reserves = cat(rL⁺, curtL⁺, LSL⁺; dims=1)
    y = fill(0.0, length(L⁺)*length(GRP), length(P), length(T))
    y2 = fill(0.0, length(L⁺), length(P), length(T)) # Reserve level line plots
    for p = P
        for t = T
            for l = L⁺
                for g = 1:nRP
                    y[(l-1)*nRP+g,p,t] = reserves[g,l,p,t]
                end
            end
            for l = L⁺[2:end]
                y2[l,p,t] = y2[l-1,p,t] + sum(reserves[:,l,p,t])
            end
        end
    end

    seriescolor = [:red :blue :orange :yellow :green :purple]

    # Shorten depending on number of reserve providers
    seriescolor = seriescolor[:,1:nRP]

    # Plot the differentiated reserves
    p1 = groupedbar(y[:,p,:]', legend=:none, bar_width=1, bar_position=:stack, seriescolor=seriescolor, xlabel="Timestep", ylabel="Reserves (MW)", linewidth=0)

    # Plot the reserve level lines
    plot!(p1, T, y2[:,p,:]', seriescolor=:black, linewidth=2)

    # Do some hacky shit for the legend
    empty = fill(0.0, 1, nRP)
    p2 = plot(1, empty, lab=GRP, legend=:best, grid=false, showaxis=false, ylims=(1,2), seriescolor=seriescolor, linewidth=6)

    # Plot everyting
    l = @layout [a{0.8w} b{0.2w}]
    plot(p1, p2, layout=l)