In MATLAB, there are many functions that create regions filled with solid colors (e.g. contourf, area, bar). To do this, a function creates "patch objects" and assigns a single color to each one. Instead of a solid fill, one often wants to fill a patch with a hatch or speckle pattern instead. MATLAB has no built-in way to do this.
The hatchfill function fills patch objects with hatching or speckling. In most cases, adding hatching to a 2D plot requires only three lines of code. For example:
[c,h] = contourf(x,y,z,[0 0]);
hp = findobj(h,'type','patch');
This fills the zero contour with hatching. Hatchfill takes additional parameters if custom patterns are desired. This package incorporates code from Rich Pawlowicz, Iram Weinstein, and Kirill Pankratov.
I just upped hatchfill2, which updates hatchfill with post-R2014b support (adds bar and surface objects) for anyone interested. The input arguments are a bit different than the original but all features are still fully intact. Linked above under Acknowledgements.
Has anyone come across this issue and found a fix:
I can fill, speckle, and outspeckle but single and cross don't work and are accompanied by the below error message:
Improper assignment with rectangular empty matrix.
Error in hatchfill (line 176)
H(j) = line(xhatch,yhatch);
All help is greatly appreciated!
For those who have problems using this for legends after 2014b update. Please consider legendflex(http://www.mathworks.com/matlabcentral/fileexchange/31092-legendflex-m--a-more-flexible--customizable-legend) for plotting.
Works like a charm.
How can I make this work in R2014b?
"findobj(h1, 'Type', 'patch')" does not see work on handles created by contourf (it returns an empty handle)
ADDENDUM/ERRATUM -- Spoke slightly too soon...
The fixup given below _does_ solve the legend handle; it for some reason I don't yet full understand trashes the patch regions in the figure, however. Best I've done to date is to add yet another conditional...replace the calls to line() w/ the conditional
H(j) = line(xhatch,yhatch);
H(j) = plot(hax,xhatch,yhatch);
Also, to prevent changes in y-scale found it necessary to clip the yhatch array returned from hatch_xy(). I put it after the call in the calling routine rather than take the time/trouble to pass the limits or handle to hatch_xy()
[xhatch,yhatch] = hatch_xy(x,y,STYL,ANGLE,SPACING);
% clip limits within the axes limits
This was necessary in my case as there were -eps or thereabouts values returned and with the lower axis at 0 for the bar chart it turned the lower axis limit to -1 instead. That's just rude... :)
Don't think it can hurt in general altho is only needed for cases like this of hatching the boundary region.
R2012b doesn't draw legends correctly; not sure about earlier releases or later.
Fails owing to use of line() primitive which can't take an axis object and uses current axes by default. Can't force legend object to be current axes.
Fixup is to turn the two line() calls
H(j) = line(xhatch,yhatch,'marker','.','linest','none', ... 'markersize',specksize,'color',linec);
H(j) = plot(hax,xhatch,yhatch,'marker','.','linest','none', ...
Still needs the fixup of twimmeh as well, of course.
It would be great if there was a mapping version of Hatchfill, perhaps "Hatchfillm" for hatching "patchm" objects? Hatchfill doesn't appear to work on map axes.
Modifications that twimmeh describes are highly recommended - thanks!
Very useful file, but I'm having some trouble with the speckling. I'd like to be able to fill a contour with dots, not just outline it. It would be nice if the function were able to do this by itself instead of the user having to, through trial and error.
After a little more editing to hatch_xy as twimmeh described, the legend looks great and the angles work fine.
Thank you very much for this, seems to work like a charm in most applications except for the legend.
I can get the hatching in the legend by doing what twimmeh said (May 2), however the angle doesn't work when hatching in the legend. I can only get horizontal or vertical lines instead of the 45 degree angle that is on my bars.
Any idea how to get the 45 degree angle in the legend?
Seems like a really great tool but unfortunately I don't manage to get it working for the problem I needed it for:
I have a 2D-matrix of linear trends (slopes) and a logical 2D-matrix of the same size telling whether the trend is significant at position xy. Now I'd like to hatch the regions of (no) significance in a contourf or pcolor plot.
Has anyone any hint why it does not work in this case although I get it working in other cases?
Would be very grateful for help.
aaaand if you want the aspect ratio of the hatch pattern to be correct you need to pass the axes handle to the hatch_xy function and replace calls to gca.
nasty, but works:
gca = hax;
(and of course updating the relevant hatch_xy call line)
I _believe_ the problem with legend hatching is that the lines are being drawn on the wrong axes.
If you adjust the calls to 'line' in the function to specify the axes parent then it seems to work... at least for me (R2011b).
H(j) = line(xhatch,yhatch,'marker','.','linest','none', ...
H(j) = line(xhatch,yhatch,'parent',hax);
%My legend code:
hLegend = legend(...);
hp = findobj(hLegend, 'Type', 'patch');
This assumes you have only one patch; you need to specify hp(i) in the hatchfill call when there are multiple patches. Also, I've found you need to increase the SPACING parameter for it to look good.
I am also curious whether it is possible to get a hatch symbol in the legend. The fix Neil suggested on Jul 17 is not working for me.
Thank you Dan, I added an additional check for axes that are only one level up.
In order for this to work for my patches (created using jbfill.m, a FileExchange script), I needed to modify line 95 because the axis handle was only one level up from the patch handle. Perhaps there should be a warning issued or some kind of additional handling if the handle two levels up is not an axis (in my case it was the figure handle).
Then this worked great! Thank you for a terrific m file!
How do I use this for 'bar'?
@Neil and Matt: It still does not work! How do I get a hatched patch symbol in the legend?
Matt - you could try something like...
h = legend('patch1','patch2');
hp = findobj(h,'type','patch');
The legend doesn't work they way i'd like. for example:
h = patch(rand(4,1),rand(4,1),'b');
can you get a little hatched patch symbol in the legend?
Great script, the latest update functions perfectly for my needs. Thank you.
Thanks Dmytro. I fixed this bug.
f = figure;
MyColor2fade = 0.6*[1 1 1];
x0d = 3;
ulims = [1 2];
p(1) = patch([x0d,x0d,1,1],[ulims(1),ulims(2),ulims(2), ulims(1)], MyColor2fade,'EdgeColor', 'none','Parent',gca);
Result: only the left top part of the patch is hatched
Added additional check for axes that are only one level up. (Suggested by Dan K.)
Consolidated code into single file.
Fixed bug reported by Dmytro Lituiev.
Minor bug fix.
Now is compatible with logarithmic axes.
Polished the examples/documentation a little.
A little housecleaning...