Skip to content

Commit

Permalink
Directly draw confidence intervals, improved dodging
Browse files Browse the repository at this point in the history
- User-provided confidence intervals can now be represented with
geom_interval()
- Improved dodging: now takes in account the number of colors per x
value
- Dodging supported in geom_point(), geom_line(), geom_jitter(),
geom_bar()
- Improved geom_bar() stacking
  • Loading branch information
piermorel committed May 16, 2016
1 parent 4e2e526 commit 94c6bce
Show file tree
Hide file tree
Showing 49 changed files with 506 additions and 185 deletions.
90 changes: 57 additions & 33 deletions @gramm/draw.m
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,9 @@
return
end

temp_aes=validate_aes(obj.aes);
obj.aes=validate_aes(obj.aes);

% Create replacement row_facet and color_facet if they were
% empty
if isempty(obj.row_facet)
obj.row_facet=ones(size(temp_aes.subset));
end

if isempty(obj.col_facet)
obj.col_facet=ones(size(temp_aes.subset));
end

temp_row_facet=obj.row_facet(temp_aes.subset);
temp_col_facet=obj.col_facet(temp_aes.subset);

temp_aes=select_aes(temp_aes,temp_aes.subset);
temp_aes=select_aes(obj.aes,obj.aes.subset);

%Find min and max of x and y to have homogenous scales
nonemptycell=@(c)~cellfun(@isempty,c);
Expand Down Expand Up @@ -126,14 +113,23 @@
obj.var_lim.minx=min(min(temp_aes.x));
end

%Depending on whether ymin of ymax are present we change what to pick for
%limit computation
if ~isempty(temp_aes.ymin) && ~isempty(temp_aes.ymax)
tmp_y_for_min=temp_aes.ymin;
tmp_y_for_max=temp_aes.ymax;
else
tmp_y_for_min=temp_aes.y;
tmp_y_for_max=temp_aes.y;
end

if iscell(temp_aes.y)
nonempty=nonempty & nonemptycell(temp_aes.y);

obj.var_lim.maxy=cellmax(temp_aes.y);
obj.var_lim.miny=cellmin(temp_aes.y);
obj.var_lim.maxy=cellmax(tmp_y_for_max);
obj.var_lim.miny=cellmin(tmp_y_for_min);
else
obj.var_lim.maxy=max(max(temp_aes.y));
obj.var_lim.miny=min(min(temp_aes.y));
obj.var_lim.maxy=max(max(tmp_y_for_max));
obj.var_lim.miny=min(min(tmp_y_for_min));
end

if ~isempty(temp_aes.z)
Expand All @@ -149,8 +145,6 @@
end

temp_aes=select_aes(temp_aes,nonempty);
temp_row_facet=temp_row_facet(nonempty);
temp_col_facet=temp_col_facet(nonempty);

%Handles the multiple gramm case: we set up subtightplot so
%that it restricts the drawing (using margins) to a portion of
Expand All @@ -171,8 +165,8 @@
mysubplot_wrap=@(ncol,col)mysubtightplot(ceil(ncol/obj.wrap_ncols),obj.wrap_ncols,col,[0.09 0.03],[0.1 0.2],[0.1 0.2]);

%Find uniques in aesthetics and sort according to options
uni_row=unique_and_sort(temp_row_facet,obj.order_options.row);
uni_column=unique_and_sort(temp_col_facet,obj.order_options.column);
uni_row=unique_and_sort(temp_aes.row,obj.order_options.row);
uni_column=unique_and_sort(temp_aes.column,obj.order_options.column);
uni_linestyle=unique_and_sort(temp_aes.linestyle,obj.order_options.linestyle);
uni_marker=unique_and_sort(temp_aes.marker,obj.order_options.marker);
uni_lightness=unique_and_sort(temp_aes.lightness,obj.order_options.lightness);
Expand Down Expand Up @@ -218,12 +212,12 @@
uni_marker=num2cell(uni_marker);
end

%Correct empty facet_grids
%Correct empty facets when wrapping
if obj.wrap_ncols>length(uni_column)
obj.wrap_ncols=length(uni_column);
end

%The plot minumums and maximums arrays the size of the
%The plot minimums and maximums arrays the size of the
%number of subplots
n_columns=length(uni_column);
n_rows=length(uni_row);
Expand Down Expand Up @@ -271,27 +265,34 @@
%Index in the loops
obj.result_ind=1;

%Initialize facet axes handles
if obj.updater.first_draw
if obj.handle_graphics
if obj.handle_graphics %Post 2014b we return objects
obj.facet_axes_handles=gobjects(length(uni_row),length(uni_column));
else
obj.facet_axes_handles=zeros(length(uni_row),length(uni_column));
end
end

%Set the dodge width across all facets
draw_data.dodge_avl_w=min(diff(unique(comb(temp_aes.x))));
if isempty(draw_data.dodge_avl_w) || draw_data.dodge_avl_w==0
draw_data.dodge_avl_w=1;
end


%% draw() looping
%Loop over rows
for ind_row=1:length(uni_row)

sel_row=multi_sel(temp_row_facet,uni_row{ind_row});
sel_row=multi_sel(temp_aes.row,uni_row{ind_row});

obj.current_row=ind_row;

%Loop over columns
for ind_column=1:length(uni_column)

sel_column=sel_row & multi_sel(temp_col_facet,uni_column{ind_column});
sel_column=sel_row & multi_sel(temp_aes.column,uni_column{ind_column});

obj.current_column=ind_column;

Expand All @@ -311,14 +312,14 @@
obj.plot_lim.minx(obj.current_row,obj.current_column));
end
if iscell(temp_aes.y(sel_column))
obj.plot_lim.maxy(obj.current_row,obj.current_column)=max(cellmax(temp_aes.y(sel_column)),...
obj.plot_lim.maxy(obj.current_row,obj.current_column)=max(cellmax(tmp_y_for_max(sel_column)),...
obj.plot_lim.maxy(obj.current_row,obj.current_column));
obj.plot_lim.miny(obj.current_row,obj.current_column)=min(cellmin(temp_aes.y(sel_column)),...
obj.plot_lim.miny(obj.current_row,obj.current_column)=min(cellmin(tmp_y_for_min(sel_column)),...
obj.plot_lim.miny(obj.current_row,obj.current_column));
else
obj.plot_lim.maxy(obj.current_row,obj.current_column)=max(max(temp_aes.y(sel_column)),...
obj.plot_lim.maxy(obj.current_row,obj.current_column)=max(max(tmp_y_for_max(sel_column)),...
obj.plot_lim.maxy(obj.current_row,obj.current_column));
obj.plot_lim.miny(obj.current_row,obj.current_column)=min(min(temp_aes.y(sel_column)),...
obj.plot_lim.miny(obj.current_row,obj.current_column)=min(min(tmp_y_for_min(sel_column)),...
obj.plot_lim.miny(obj.current_row,obj.current_column));
end
if ~isempty(temp_aes.z)
Expand Down Expand Up @@ -400,6 +401,9 @@
%missing data).
draw_data.facet_x=temp_aes.x(sel_column);

%Store data for advanced dodging
[dodge_data.fallback,dodge_data.x,dodge_data.color,dodge_data.lightness,dodge_data.ind,dodge_data.n]=dodge_comp(temp_aes.x(sel_column),temp_aes.color(sel_column),temp_aes.lightness(sel_column),uni_color,uni_lightness);

%Loop over point shapes
for ind_marker=1:length(uni_marker)

Expand Down Expand Up @@ -435,6 +439,19 @@
uni_group=num2cell(uni_group);
end

%Select dodging parameters for current color
%and lightness
if obj.continuous_color
sel_dodge=true(size(dodge_data.color));
else
sel_dodge=multi_sel(dodge_data.color,uni_color{ind_color}) & multi_sel(dodge_data.lightness,uni_lightness{ind_lightness});
end

draw_data.dodge_fallback=dodge_data.fallback;
draw_data.dodge_x=dodge_data.x(sel_dodge);
draw_data.dodge_ind=dodge_data.ind(sel_dodge);
draw_data.dodge_n=dodge_data.n(sel_dodge);

%Loop over groups
for ind_group=1:length(uni_group)

Expand Down Expand Up @@ -468,6 +485,13 @@
%individual geoms
draw_data.x=temp_aes.x(sel);
draw_data.y=temp_aes.y(sel);
if ~isempty(temp_aes.ymin) && ~isempty(temp_aes.ymax)
draw_data.ymin=temp_aes.ymin(sel);
draw_data.ymax=temp_aes.ymax(sel);
else
draw_data.ymin=[];
draw_data.ymax=[];
end
if ~isempty(temp_aes.z)
draw_data.z=temp_aes.z(sel);
else
Expand Down
17 changes: 5 additions & 12 deletions @gramm/facet_grid.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@

%Handle case where facet_grid is called after update()
if obj.updater.updated
if isnumeric(obj.row_facet) && isnumeric(obj.col_facet) && all(obj.row_facet==1) && all(obj.col_facet==1)
if isempty(obj.row_facet) && isempty(obj.col_facet)
if isnumeric(obj.aes.row) && isnumeric(obj.aes.column) && all(obj.aes.row==1) && all(obj.aes.column==1)
if isempty(obj.aes.row) && isempty(obj.aes.column)
%User probably tried to update all the data
obj.updater.facet_updated=0;
else
Expand All @@ -57,15 +57,8 @@
end
end

if iscategorical(row)
obj.row_facet=shiftdim(cellstr(row));
else
obj.row_facet=shiftdim(row);
end
if iscategorical(col)
obj.col_facet=shiftdim(cellstr(col));
else
obj.col_facet=shiftdim(col);
end
obj.aes.row=shiftdim(row);
obj.aes.column=shiftdim(col);

obj.wrap_ncols=-1;
end
13 changes: 5 additions & 8 deletions @gramm/facet_wrap.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

%Handle case where facet_wrap is called after update()
if obj.updater.updated
if isnumeric(obj.row_facet) && isnumeric(obj.col_facet) && all(obj.row_facet==1) && all(obj.col_facet==1)
if isempty(obj.row_facet) && isempty(obj.col_facet)
if isnumeric(obj.aes.row) && isnumeric(obj.aes.column) && all(obj.aes.row==1) && all(obj.aes.column==1)
if isempty(obj.aes.row) && isempty(obj.aes.column)
%User probably tried to update all the data
obj.updater.facet_updated=0;
else
Expand All @@ -42,10 +42,7 @@
end

obj.wrap_ncols=p.Results.ncols;
if iscategorical(col)
obj.col_facet=shiftdim(cellstr(col));
else
obj.col_facet=shiftdim(col);
end
obj.row_facet=[];
obj.aes.column=shiftdim(col);
obj.aes.row=[];

end
23 changes: 12 additions & 11 deletions @gramm/geom_bar.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
p=inputParser;
my_addParameter(p,'width',0.80);
my_addParameter(p,'stacked',false);
my_addParameter(p,'dodge',0);
parse(p,varargin{:});

obj.geom=vertcat(obj.geom,{@(dd)my_bar(obj,dd,p.Results)});
Expand All @@ -31,33 +32,33 @@

%Problem with stacked bar when different x values are used
if obj.firstrun(obj.current_row,obj.current_column)
obj.extra.stacked_bar_height=zeros(1,length(x));
%Store heights at the level of dodge x
obj.extra.stacked_bar_height=zeros(1,length(draw_data.dodge_x));
obj.plot_lim.minx(obj.current_row,obj.current_column)=min(x)-width;
obj.plot_lim.maxx(obj.current_row,obj.current_column)=max(x)+width;
%obj.firstrun(obj.current_row,obj.current_column)=0;
end

x_stack_ind=arrayfun(@(xin)find(abs(draw_data.dodge_x-xin)<1e-10,1),x);

hndl=patch([x-width/2 ; x+width/2 ; x+width/2 ; x-width/2],...
[obj.extra.stacked_bar_height ; obj.extra.stacked_bar_height ; obj.extra.stacked_bar_height+y ; obj.extra.stacked_bar_height+y],...
[obj.extra.stacked_bar_height(x_stack_ind) ; obj.extra.stacked_bar_height(x_stack_ind) ; obj.extra.stacked_bar_height(x_stack_ind)+y ; obj.extra.stacked_bar_height(x_stack_ind)+y],...
draw_data.color,'EdgeColor','k');

obj.extra.stacked_bar_height=obj.extra.stacked_bar_height+y;
obj.results.geom_bar_handle{obj.result_ind,1}=hndl;

obj.extra.stacked_bar_height(x_stack_ind)=obj.extra.stacked_bar_height(x_stack_ind)+y;
if obj.plot_lim.maxy(obj.current_row,obj.current_column)<max(obj.extra.stacked_bar_height)
obj.plot_lim.maxy(obj.current_row,obj.current_column)=max(obj.extra.stacked_bar_height);
end

else

if min(x+(draw_data.color_index/(draw_data.n_colors+1)-0.5)*width-width/(draw_data.n_colors+1))<obj.plot_lim.minx(obj.current_row,obj.current_column)
obj.plot_lim.minx(obj.current_row,obj.current_column)=min((draw_data.color_index/(draw_data.n_colors+1)-0.5)*width-width/(draw_data.n_colors+1));
end
if max(x+(draw_data.color_index/(draw_data.n_colors+1)-0.5)*width+width/(draw_data.n_colors+1))>obj.plot_lim.maxx(obj.current_row,obj.current_column)
obj.plot_lim.maxx(obj.current_row,obj.current_column)=max(x+(draw_data.color_index/(draw_data.n_colors+1)-0.5)*width+width/(draw_data.n_colors+1));
end

hndl=plotci(obj,x,y,[y y],draw_data,'edge_bar',params.dodge,params.width);
obj.results.geom_bar_handle{obj.result_ind,1}=hndl.bar_handle;

hndl=bar(x+(draw_data.color_index/(draw_data.n_colors+1)-0.5)*width,y,width/(draw_data.n_colors+1),'faceColor',draw_data.color,'EdgeColor','none');
end

obj.results.geom_bar_handle{obj.result_ind,1}=hndl;

end
47 changes: 47 additions & 0 deletions @gramm/geom_interval.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
function obj = geom_interval( obj,varargin )

p=inputParser;
my_addParameter(p,'geom','area');
my_addParameter(p,'dodge',[]);
my_addParameter(p,'width',[]);
parse(p,varargin{:});

obj.geom=vertcat(obj.geom,{@(dd)my_ci(obj,dd,p.Results)});
obj.results.geom_interval={};

end

function hndl=my_ci(obj,draw_data,params)

if isempty(draw_data.ymin) || isempty(draw_data.ymax)
error('No ymin or ymax data for geom_ci');
end

%Advanced defaults
if isempty(params.dodge)
if sum(strcmp(params.geom,'bar'))>0 && draw_data.n_colors>1 %If we have a bar as geom, we dodge
params.dodge=0.6;
else
params.dodge=0;
end
end

if isempty(params.width) %If no width given
if params.dodge>0 %Equal to dodge if dodge given
params.width=params.dodge*0.8;
else
params.width=0.5;
end
end

if iscell(draw_data.x)
for k=1:length(draw_data.x)
plotci(obj,draw_data.x{k},draw_data.y{k},[draw_data.ymin{k} draw_data.ymax{k}],draw_data,params.geom,params.dodge,params.width);
end
else
hndl=plotci(obj,draw_data.x,draw_data.y,[draw_data.ymin draw_data.ymax],draw_data,params.geom,params.dodge,params.width);
end

obj.results.geom_interval{obj.result_ind,1}=hndl;

end
3 changes: 3 additions & 0 deletions @gramm/geom_jitter.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
p=inputParser;
my_addParameter(p,'width',0.2);
my_addParameter(p,'height',0.2);
my_addParameter(p,'dodge',0);
parse(p,varargin{:});

obj.geom=vertcat(obj.geom,{@(dd)my_jitter(obj,dd,p.Results)});
Expand All @@ -18,6 +19,8 @@

function hndl=my_jitter(obj,draw_data,params)

draw_data.x=dodger(draw_data.x,draw_data,params.dodge);

draw_data.x=draw_data.x+rand(size(draw_data.x))*params.width-params.width/2;
draw_data.y=draw_data.y+rand(size(draw_data.y))*params.height-params.height/2;

Expand Down
Loading

0 comments on commit 94c6bce

Please sign in to comment.