In the past few weeks, I discussed the new HG2 axes Backdrop and Baseline properties with their associated ability to specify the transparency level using a fourth (undocumented) element in their Color.
In other words, color in HG2 can still be specified as an RGB triplet (e.g., [1,0,0] to symbolize bright red), but also via a 4-element quadruplet RGBA, where the 4th element (Alpha) signifies the opacity level (0.0=fully transparent, 0.5=semi-transparent, 1.0=opaque). So, for example, [1, 0, 0, 0.3] means a 70%-transparent red.
This Alpha element is not documented anywhere as being acceptable, but appears to be supported almost universally in HG2 wherever a color element can be specified. In some rare cases (e.g., for patch objects) Matlab has separate Alpha properties that are fully documented, but in any case nowhere have I seen documented that we can directly set the alpha value in the color property, especially for objects (such as plot lines) that do not officially support transparency. If anyone finds a documented reference anywhere, please let me know – perhaps I simply missed it.
Here is a simple visualization:
xlim([1,5]); hold('on'); h1a = plot(1:5, 11:15, '.-', 'LineWidth',10, 'DisplayName',' 0.5'); h1b = plot(1.5:5.5, 11:15, '.-', 'LineWidth',10, 'DisplayName',' 1.0', 'Color',h1a.Color); % 100% opaque h1a.Color(4) = 0.5; % 50% transparent h2a = plot(3:7, 15:-1:11, '.-r', 'LineWidth',8, 'DisplayName',' 0.3'); h2a.Color(4)=0.3; % 70% transparent h2b = plot(2:6, 15:-1:11, '.-r', 'LineWidth',8, 'DisplayName',' 0.7'); h2b.Color(4)=0.7; % 30% transparent h2c = plot(1:5, 15:-1:11, '.-r', 'LineWidth',8, 'DisplayName',' 1.0'); % 100% opaque = 0% transparent legend('show','Location','west') |
Now for the fun part: we can make color-transition (gradient) effects along the line, using its hidden Edge property:
>> h2b.Edge.get AlignVertexCenters: 'off' AmbientStrength: 0.3 ColorBinding: 'object' ColorData: [4x1 uint8] ColorType: 'truecoloralpha' DiffuseStrength: 0.6 HandleVisibility: 'off' HitTest: 'off' Layer: 'middle' LineStyle: 'solid' LineWidth: 8 NormalBinding: 'none' NormalData: [] Parent: [1x1 Line] PickableParts: 'visible' SpecularColorReflectance: 1 SpecularExponent: 10 SpecularStrength: 0.9 StripData: [1 6] Texture: [] VertexData: [3x5 single] VertexIndices: [] Visible: 'on' WideLineRenderingHint: 'software' >> h2b.Edge.ColorData %[4x1 uint8] ans = 255 0 0 179 |
The tricky part is to change the Edge.ColorBinding value from its default value of ‘object’ to ‘interpolated’ (there are also ‘discrete’ and ‘none’). Then we can modify Edge.ColorData from being a 4×1 array of uint8 (value of 255 corresponding to a color value of 1.0), to being a 4xN matrix, where N is the number of data points specified for the line, such that each data point along the line will get its own unique RGB or RGBA value. (the data values themselves are kept as a 3xN matrix of single values in Edge.VertexData).
So, for example, let’s modify the middle (30%-transparent) red line to something more colorful:
>> cd=uint8([255,200,250,50,0; 0,50,250,150,200; 0,0,0,100,150; 179,150,200,70,50]) cd = 255 200 250 50 0 0 50 250 150 200 0 0 0 100 150 179 150 200 70 50 >> set(h2b.Edge, 'ColorBinding','interpolated', 'ColorData',cd) |
As you can see, we can interpolate not only the colors, but also the transparency along the line.
Note: We need to update all the relevant properties together, in a single set() update, otherwise we’d get warning messages about incompatibilities between the property values. For example:
>> h2b.Edge.ColorBinding = 'interpolated'; Warning: Error creating or updating LineStrip Error in value of property ColorData Array is wrong shape or size (Type "warning off MATLAB:gui:array:InvalidArrayShape" to suppress this warning.)
Markers
Note how the markers are clearly seen in the transparent lines but not the opaque ones. This is because the markers have the same color as the lines in today’s example. Since the lines are wide, the markers are surrounded by pixels of the same color. Therefore, the markers are only visible when the surrounding pixels are less opaque (i.e., lighter).
As a related customization, we can control whether the markers appear “on top of” (in front of) the line or “beneath” it by updating the Edge.Layer property from ‘middle’ to ‘front’ (there is also ‘back’, but I guess you won’t typically use it). This is important for transparent lines, since it controls the brightness of the markers: “on top” (in front) they appear brighter. As far as I know, this cannot be set separately for each marker – they are all updated together.
Of course, we could always update the line’s fully-documented MarkerSize, MarkerFaceColor and MarkerEdgeColor properties, in addition to the undocumented customizations above.
Next week I will describe how we can customize plot line markers in ways that you never thought possible. So stay tuned 🙂
Have you managed to get the same working for markers? I can’t set the alpha component for MarkerFaceColor, and setting it for Color doesn’t even affect the marker edge:
I’m using 2013b, maybe it’s different in later versions?
@Paul – I plan to cover Marker customizations (including transparency) in next week’s post. Stay tuned 🙂
That’s absolutely splendid, @Yair!
All those years I used a 2×N mesh in order to make a gradient plot, and it turns out to be so simple in HG2. Keep up the good work!
[…] opens up Matlab plots to a whole new spectrum of customizations that were more difficult (although not impossible) to achieve earlier.Throughout today, we’ve kept the default FaceColorType/EdgeColorType […]
Is it possible to set the transparency of 2D contourf plot fills? I used to be able to do this before 2014b, but the latest update broke what I was using. I used allchild to get handles of the subobjects and set the FaceAlpha to less than 1
Great, many thanks for this. When I try that code, hFaces comes out as 0x0. When I insert a pause(0.05) before the hFaces = hContour.FacePrims line it works. Strange.
I assume that drawnow will also work…
Yes, it does. Thanks again.
This is great, but I find that when i set an alpha for a line color, the line smoothing goes away and i get the old fashioned pixelated lines. Have you noticed that too or is it just me?
It seems that the workaround doesn’t work on 2014a edition!
I receive “Attempt to reference field f non-structure array.”
Any comments?
Of course it doesn’t – as stated in the top paragraph, this article (which is part of a series) only discusses HG2, in other words R2014b and later. R2014a still uses the previous version of HG, which is radically different.
I’ve been able to make some beautiful figures using HG2 thanks to your help. Unfortunately, I am now unable to find a way to export to any sort of vector format that maintains my transparent lines (among other issues). I have tried export_fig, and exporting to .svg. When I do the export, I simply get the figure without my edited properties like alpha and color interpolation. Have you found any way around this? It’s driving me crazy and, from an academic standpoint, appears to make many of the advances of HG2 frustratingly useless. At this point I would put up with just about anything that would get me a super-high resolution image out.
@James – try using the opengl (rather than painters) renderer (the ‘-opengl’ parameter in
export_fig
). Note that this might take a long time, consume much memory, and generate a huge output file.Also try using bitmap output with a large resolution (the -r# parameter) – it would not be vectorized, but at least it might have a large-enough resolution to be publication quality.
Hi Yair,
Thanks for the quick response. The opengl renderer works for .png or .bmp format, yes, but when I change the resolution the output changes from my pretty figure with transparency, etc. to essentially the plot before I edit any of the color and alpha properties (still not working for vector outputs).
What I’ve gathered so far is that this may be related the necessity of using the drawnow command in between plotting the line and getting the line marker handles. For example, if I do not use drawnow after plotting the line, I am unable to access the line.MarkerHandle properties. I do not need the drawnow to do to things such as changing the grid lines (so documented properties related to the axes rather than the line). When I try to render with vector graphics or .bmp with increased resolution, I get only the changes I made that don’t rely on the drawnow (so it renders the grid lines, but not the color and alpha values based on line.MarkerHandle.EdgeColorData).
I have no current idea how to fix this. I wonder if it has to do with the way the exporter “re-renders” the figure for export, and if it’s as simple as getting it to add another drawnow in there somewhere so that it reads the MarkerHandle changes. I don’t know if export_fig would be able to deal with such a change. I guess any further advice, tips or even a solution would be greatly appreciated.
Thanks again!
@James – I suspect that you will find the same behavior with Matlab’s built-in print function, and in this case there is not much that export_fig can do since it uses print internally.
Thanks. I guess these hidden properties are unfortunately still useless when it comes to vector graphics (or even high quality non-vector formats unless you have a high-res display and effectively take a screenshot). Hopefully this gets updated soon.
Quick comment: on my Computer (Win7, Matlab 2015a) the above syntax only works for lines up to exactly 25000 data points. Also, changing the ColorBinding and setting the ColorData is only possible, if the line has already been drawn. Therefore, it is necessary to issue a drawnow before setting these parameters:
Hi Yair,
There is an issue when there are too many points in the plot as Sebastian pointed out above. Below 25000 points, everything works as expected:
Above this magic number, Matlab tries to optimize the figure by plotting only a subset of the vertices. Repeating the procedure with more points than that results in a warning and no color gradient:
To fix the issue, we need to probe the number of vertices in
hPlot.Edge
:But, if we try, say, to resize the figure, the warning reappears (though the gradient stays):
Similar unexpected behavior occurs in
zoom
,copyobj
etc.P.S, my Matlab version is R2018a, so it looks like a rather persistent problem.
There is no Edge in quiver, so this workaround will not help.
Hi Yair,
I tried to use the code for varying the transparency and for some reason the following example code does not work as expected:
I expected first 5 points to have transparency of 200 and then 5 with transparency of 100. Can you explain why the result is with same transparency all over ?
Thanks,
-Moshe.
I have the same problem.
I wrote code essentially the same as yours.
newColor(1:3,:) works as expected.
newColor(4,:) does not change transparency.
Not sure how to fix it, but I gave up trying.
Hello Yair,
Thanks for the useful tip.
I was am having trouble creating a figure with multiple lines and having the color encoding remaining in the plot.
I am plotting multiple lines in a for loop. If I dbstep through each iteration of the loop, then the color will show up, however, when the loop completes the gradient colors go away and the default uniform matlab colors remain. Any suggestions?
example code:
@John – perhaps after the loop you have some code that causes the axes to repaint and this will cause Matlab to ignore the undocumented color changes. Try to call drawnow at the very end of your plotting section and only then update the handles’ colors to the transparent values.
Hello, Yair,
I have some problem in using your code to draw a transparent line.
Here are the codes, which are mostly exactly as yours.
I wrote it in a script file, but after running it, the output figure is not transparent. I check the properties in h2b.Edge, noticing that the ‘ColorBinding’ is still ‘object’. Then I run the last sentence again in the Command Window, which is shown below.
And the figure turns to transparent. It is really confusing to me. Could you please tell me how to solve this problem?
Thanks!
PS, the version of my MATLAB is R2015a.
Hello Yair.
I used your code to draw a transparent line. But there are some problems. I wrote the below codes in a .m file.
The codes are almost exactly as yours, except that I set the ‘ColorType’ since it is ‘truecolor’ in default.
However, the line is not a transparent one. I checked the h2b.Edge and found that the ColorBinding is still ‘object’. Then I run the last sentence of the above codes in Command Window again. This time it works and the line is transparent as your results.
Could you please tell me why would this happen and how to fix it? Because I would like to use it to generate some pictures and it’s a disaster if I have to run the last sentence in Command Window each time.
Thanks!
PS, the version of my MATLAB is R2015a.
@Jerry – adding drawnow; pause(0.1) after the plot command and before setting the color should solve the problem.
Great, it works. Thanks!
I guess the reason is that when it runs the setting process, the figure is still unfinished?
yes
Is it possible to fade a cluster of points held in two arrays x,y?
@Vince – yes:
[…] I came across when reading through Yair Altman’s undocumented MATLAB blog. He reports on some undocumented line properties that were introduced with MATLAB’s new graphics engine in R2014b. I implemented the surface […]
Unfortunately it seems that the legend cannot show the corresponding line as a gradient. The line color appears to match one end of the gradient. I tried a bunch of things but wasn’t able to change the lines in the legend to gradients to match the lines in the figure.
Hello Yair,
Do you known if there is an “outline.Color” property for the “line” object? It would make 3D objects much more readable in terms of what is front and what is back (get rid of the Necker illusion). See, e.g., https://en.wikipedia.org/wiki/File:4Asterane.png
Thanks!
@Vlad – I am not aware of an outline property, but you should be able to replicate it by using two overlapping lines that have different colors/transparency levels, one line slightly wider than the other.
Correct, Yair. But you will have problems where lines meet: their extremities will look disjoined.
I don’t think the lines will look disjointed if you ensure that the endpoints are exactly the same.
Hi,
Is it possible to load the value of transparency and store it in some variable? e.g. x = h2b.Color(4).
I get the error ‘Index exceeds matrix dimensions.’ when I try this. Is there anyway to load this value?
Thanks!
You cannot get the transparency component via the Color property, you need to use the line’s edge’s ColorData property instead:
x = h2b.Edge.ColorData(4)
– this returns a uint8 number between 0-255. You can convert it into a 0-1 double value using (for example)double(h2b.Edge.ColorData(4))/255
.Hi,
I would like to define the transparency of a m_contour-plot, meaning the transparency of the contour-line. I have tried it as follows:
This doesn’t work. Is there a possibility to solve that problem?
Thanks!
@Sina – you need to access the individual contour lines, and then change the lines’ ColorType from ‘truecolor’ to ‘truecoloralpha’, as I explained multiple times on this page.
Hi-
I am wondering if anyone else has trouble saving lines made with a color gradient?
Specifically, I am trying to save a vector format (pdf, eps, or similar) with h2b-style multicolor lines. The color gradient lines don’t show up, and other programs (Illustrator) will throw an error when you open the file. Matlab itself has a problem saving to pdf that it doesn’t have with solid lines.
I am looking to get a vector graphic version of one of these figures, any help would be great!
Thanks!
Hi Yair,
I am trying to plot a line with a gradient which would be “perpendicular” to the line. For example:
N = 10;
p = plot(1:N, ones(1, N), ‘Linewidth’, 20);
cd = [uint8(jet(N)*255) uint8(ones(N, 1))].’;
drawnow
set(p.Edge, ‘ColorBinding’,’interpolated’, ‘ColorData’,cd)
This is a horizontal line with color gradient going from left to right (in the direction of the sample points). Is there a way to have a gradient going from top to bottom? (if the line is tilted, then the gradient would be still perpendicular to that line). The effect should look like the line is fading out in the perpendicular direction.
Thanks for any hints and ideas.
Hi,
Take a look at this function, it fades a plot and add new data on it.
https://www.mathworks.com/matlabcentral/fileexchange/69816-fadeit
I very much wanted this to work with Quiver, and it does as long as the number of points is not too big. Using 2018a, I get the warnings/errors above even if placed in a single call to set.
The graded color is not working for me using R2021a. The plot “HG2 plot line color, transparency gradient” looks exactly like “Transparent HG2 plot lines”.
Any chance there is a fix?
@Ben – it looks perfectly ok (with color gradient and all) on my R2022a… Perhaps you missed some of the steps (e.g. setting the ColorBinding to
'interpolated'
) or perhaps you do not have adrawnow/pause
before you modify the displayed line (i.e. you try to modify the line before Matlab has completed its on-screen rendering).Thanks Yair, it was the second. I didn’t not include the drawnow ()
Hello. I am trying to do a gradient plot for multiple functions to be displayed on the same axes and each one is colorcoded by respective colordata, using the same scaling. The sample code is below:
I am getting the error messages.
Sorry for the lengthy post. Thanks!
When you use plot() without hold(‘on’), each new plot() clears the axes and draws a new line, so your second plot() of p2 caused the first plot() line (p1) to be erased.
Add a call to hold(‘on’) before you plot to ensure that both lines are ploted and not deleted.