Skip to content

Commit

Permalink
Merge pull request piermorel#27 from Nicholas-Schaub/master
Browse files Browse the repository at this point in the history
Added geom_polygons()
  • Loading branch information
piermorel authored Apr 19, 2017
2 parents 3f15667 + 4f14600 commit a7572d0
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 4 deletions.
8 changes: 6 additions & 2 deletions @gramm/draw.m
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,11 @@

hold on

%Draw polygons before plotting data, so data isn't covered up
if obj.polygon.on
draw_polygons(obj);
end


%Store all the X used for the current facet (useful for
%correct spacing of dodged bars and boxplots when
Expand Down Expand Up @@ -886,7 +891,7 @@
obj.plot_lim.maxx(obj.plot_lim.minx==obj.plot_lim.maxx)=obj.plot_lim.maxx(obj.plot_lim.minx==obj.plot_lim.maxx)+0.01;
obj.plot_lim.maxz(obj.plot_lim.minz==obj.plot_lim.maxz)=obj.plot_lim.maxz(obj.plot_lim.minz==obj.plot_lim.maxz)+0.01;


if ~obj.polar.is_polar % XY Limits are only useful for non-polar plots

%Set axes limits logic according to facet_scale and
Expand Down Expand Up @@ -1222,7 +1227,6 @@

end


end
end

Expand Down
128 changes: 128 additions & 0 deletions @gramm/geom_polygon.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
function obj=geom_polygon(obj,varargin)
% geom_polygon Create reference polygons in each facet
%
% This function allows to draw polygons in the background of each facet.
% Inputs are given as 'name',value pairs:
%
% 'x' Cell array of vectors containing x coordinates
% 'y' Cell array of vectors containing y coordinates
%
% When both 'x' and 'y' are provided, the lenght of each cell array should
% correspond to the number of desired polygons n_polygons. The i_th cell of each cell array
% should contain equally-sized vectors which correspond to the coordinates of
% the vertices of the i_th polygon.
%
% When only 'x' (or only 'y') is given, geom_polygon() draws vertical (or
% horizontal) rectangles that span the whole plot. In that case, 'x' (or 'y') should be a cell array which
% length corresponds to the number of desired polygons n_polygons. Each cell of the
% cell array should contain a vector of length 2 with the horizontal (or
% vertical) start and end coordinates of the polygons.
%
% Optional inputs (defaults) can be specified for all polygons in the call
% at once or specifically for each polygon:
%
% 'alpha' (0.2) fill alpha (length 1 or n_polygons)
% 'color' ([0 0 0]) RGB fill color of the polygon ( 1 x 3 or
% n_polygons x 3 ). Or color index with automatic colors (1 x
% 1 or n_polygons x 1 integers)
% 'line_color' ([0 0 0]) RGB line color of the polygon ( 1 x 3 or
% n_polygons x 3 ). Or color index with automatic colors (1 x
% 1 or n_polygons x 1 integers)
% 'line_style' ({'none'}) line style of the polygon (length 1 or n_polygons)
%


% created: 2017-Mar-03
% author: Nicholas J. Schaub, Ph.D.
% email: [email protected]
%
% modified: 2017-Mar-12, 2017-Apr-18, Pierre Morel


% Parse inputs and set defaults

p=inputParser;

my_addParameter(p,'x',{});
my_addParameter(p,'y',{});
my_addParameter(p,'alpha',0.2);
my_addParameter(p,'color',[0 0 0]);
my_addParameter(p,'line_color',[0 0 0]);
my_addParameter(p,'line_style',{'none'});
my_addParameter(p,'extent',2);
parse(p,varargin{:});

temp_results=p.Results;


% Check inputs
if isempty(temp_results.x) && isempty(temp_results.y)
warning('Both x and y are not provided. Will not draw polygons.')
return
end

if ~iscell(temp_results.x) || ~iscell(temp_results.y)
warning('Either x or y is not a cell. Will not draw polygons.')
return
end

%If one of the xy input is omitted, we fill it with an cell full of empty
%arrays
if isempty(temp_results.x)
N=length(temp_results.y);
temp_results.x=repmat({[]},N,1);
elseif isempty(temp_results.y)
N=length(temp_results.x);
temp_results.y=repmat({[]},N,1);
else
N=length(temp_results.x);
end


if length(temp_results.x) ~= length(temp_results.y)
warning('The number of elements in x does not match y. Will not draw polygons.')
return
end

%Check number of vertices
nvx=cellfun(@length,temp_results.x);
nvy=cellfun(@length,temp_results.y);

%Which cases are allowed for omitted inputs
to_complete = (nvx==2 & nvy==0) | (nvx==0 & nvy==2);

if ~isequal(nvx(~to_complete),nvy(~to_complete))
warning('The number of x-coords does not match the number of y-coords for each polygon. Will not draw polygons.')
return
end




%Expand the inputs for which single entries were given to the number of
%polygons
to_adjust={'alpha','color','line_color','line_style','extent'};
for k=1:length(to_adjust)
if size(temp_results.(to_adjust{k}),1)==1
temp_results.(to_adjust{k}) = repmat(temp_results.(to_adjust{k}),N,1);
end
end

% Add polygon settings to object, used when draw() is called
to_fill=fieldnames(temp_results);
for obj_ind=1:numel(obj)

obj(obj_ind).polygon.on = true;
for k=1:length(to_fill)
obj(obj_ind).polygon.(to_fill{k})=vertcat(obj(obj_ind).polygon.(to_fill{k}),temp_results.(to_fill{k})) ;
end


% Include these options to be compatible with get_colormap
% * could be changed to give increased control of polygon coloring
color_opts=fieldnames(obj(obj_ind).color_options);
for k=1:length(color_opts)
obj(obj_ind).polygon.color_options.(color_opts{k})= obj(obj_ind).color_options.(color_opts{k});
end
end
end
14 changes: 13 additions & 1 deletion @gramm/gramm.m
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@
'fun',[],...
'extent',[])

%structure containing polygon parameters - Nicholas Schaub 2017-Mar-07
polygon = struct('on',false,...
'x',{[]},...
'y',{[]},...
'color_options',{[]},...
'line_style',{[]},...
'color',[],...
'line_color',[],...
'alpha',[],...
'extent',[]);

datetick_params={} %cell containng datetick parameters
current_row %What is the currently drawn row of the subplot
current_column %What is the currently drawn column of the subplot
Expand All @@ -80,7 +91,7 @@

continuous_color_colormap=[];

color_options %Structure holding color options
color_options %Structure holding color options

order_options %Structure holding order options

Expand Down Expand Up @@ -210,6 +221,7 @@
obj=geom_count(obj,varargin)
obj=geom_jitter(obj,varargin)
obj=geom_abline(obj,varargin)
obj=geom_polygon(obj,varargin)
obj=geom_vline(obj,varargin)
obj=geom_hline(obj,varargin)
obj=geom_funline(obj,varargin)
Expand Down
55 changes: 55 additions & 0 deletions @gramm/private/draw_polygons.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
function draw_polygons(obj)
% draw_polygons
%
% Handles the actual drawing of polygons when the draw() function is
% called.

% created: 2017-Mar-03
% author: Nicholas J. Schaub, Ph.D.
% email: [email protected]
%
% modified: 2017-Mar-12, Pierre Morel

%If we get indices for color or line_color, use get_line_colormap to get actual line_colors
if size(obj.polygon.color,2)==1
cmap=get_colormap(max(obj.polygon.color),1,obj.polygon.color_options);
obj.polygon.color=cmap(obj.polygon.color,:);
end

if size(obj.polygon.line_color,2)==1
cmap=get_colormap(max(obj.polygon.line_color),1,obj.polygon.color_options);
obj.polygon.line_color=cmap(obj.polygon.line_color,:);
end

for poly_ind = 1:length(obj.polygon.x)

tmp_x=obj.polygon.x{poly_ind};
tmp_y=obj.polygon.y{poly_ind};

%Handle cases of omitted x or y values
if isempty(tmp_x)
tmp_xl=[obj.var_lim.minx obj.var_lim.maxx];
tmp_extent=(tmp_xl(2)-tmp_xl(1))*obj.polygon.extent(poly_ind)/2;
xl=[mean(tmp_xl)-tmp_extent mean(tmp_xl)+tmp_extent];
tmp_y=[tmp_y(1) tmp_y(2) tmp_y(2) tmp_y(1)];
tmp_x=[xl(1) xl(1) xl(2) xl(2)];
end
if isempty(tmp_y)
tmp_yl=[obj.var_lim.miny obj.var_lim.maxy];
tmp_extent=(tmp_yl(2)-tmp_yl(1))*obj.polygon.extent(poly_ind)/2;
yl=[mean(tmp_yl)-tmp_extent mean(tmp_yl)+tmp_extent];
tmp_x=[tmp_x(1) tmp_x(2) tmp_x(2) tmp_x(1)];
tmp_y=[yl(1) yl(1) yl(2) yl(2)];
end

p = patch(tmp_x,tmp_y,obj.polygon.color(poly_ind,:),...
'Parent',obj.facet_axes_handles(obj.current_row,obj.current_column),...
'FaceColor',obj.polygon.color(poly_ind,:),...
'FaceAlpha',obj.polygon.alpha(poly_ind),...
'EdgeColor',obj.polygon.line_color(poly_ind,:),...
'LineStyle',obj.polygon.line_style{poly_ind});

end

end

40 changes: 39 additions & 1 deletion examples.m
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,6 @@
plot(g.results.stat_cornerhist(2).child_axe_handle,[-2 -2],[0 50],'k:','LineWidth',2)
%set([g.results.stat_cornerhist.child_axe_handle],'XTick',[])


%% Graphic and normalization options in stat_violin()

clear g
Expand Down Expand Up @@ -1111,6 +1110,45 @@
figure('Position',[100 100 800 600]);
g.draw();

%% Decorate plot backgrounds with geom_polygon()

clear g
g=gramm('x',cars.Model_Year,'y',cars.MPG,'color',cars.Cylinders,'subset',cars.Cylinders~=3 & cars.Cylinders~=5);
g.facet_grid([],cars.Origin_Region);
g.geom_point();
g.stat_glm('geom','line');
g.set_names('column','','x','Year of production','y','Fuel economy (MPG)','color','# Cylinders');

g(1,2)=copy(g(1));
g(2,1)=copy(g(1));
g(2,2)=copy(g(1));

% Color mapping for the polygons
cmap = [1 0.5 0.5; % red (bad gas mileage)
1 1 0.5; % yellow (reasonable gas mileage)
0.5 1 0.5]; % green (good gas mileage)

% Standard geom_polygon call, 'x' and 'y' are used to provide polygons vertex coordinates, Possibility to manually set fill, color, style and alpha.
g(1,1).geom_polygon('x',{[50 90 90 50] ; [50 90 90 50] ; [50 90 90 50]},'y',{[5 5 20 20]; [20 20 30 30]; [30 30 50 50]},'color',cmap,'alpha',0.3);

% Simplified geom_polygon call, 'x' was omitted and only pairs of 'y' values are provided,
% specifying lower and upper limits of horizontal areas.
g(1,2).geom_polygon('y',{[5 20]; [20 30]; [30 50]},'color',cmap);

%Possibility to set color and fill by indices (using a column vector of
%integers. Colormap generated between 1 and max(vector))
g(2,1).geom_polygon('y',{[5 20]; [20 30]; [30 50]},'color',[1 ; 3; 2]);

% Single fill, alpha, color and styles are automatically extended to all polygons in the call
g(2,2).geom_polygon('y',{[5 20]; [30 50]},'color',[1 0 0],'line_style',{'--'},'line_color',[0 0 0.5]);
% Possibility to do multiple calls
g(2,2).geom_polygon('x',{[72 80 76]},'y',{[22 22 28]}); %Default is grey

g.set_title('Decorate plot backgrounds with geom_polygon()');

figure('Position',[100 100 800 600]);
g.draw();


%% Advanced customization of gramm figures
% The options for the geom_ and stat_ methods, as well as the
Expand Down

0 comments on commit a7572d0

Please sign in to comment.