Plot line transparency and color gradient

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')

Transparent HG2 plot lines

Transparent HG2 plot lines

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)

HG2 plot line color, transparency gradient

HG2 plot line color, transparency gradient

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 :-)

Categories: Handle graphics, Medium risk of breaking in future versions, Stock Matlab function, Undocumented feature

Tags: , , , ,

Bookmark and SharePrint Print

30 Responses to Plot line transparency and color gradient

  1. Paul says:

    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:

    >> x = plot(X, Y, 'o', 'MarkerFaceColor', [0.5, 0.5, 0.5]);
    >> x.Color(4) = 0.1;
    >> x.MarkerFaceColor(4) = 0.5;
    While setting the 'MarkerFaceColor' property of Line:
    Color value must be a 3 element numeric vector

    I’m using 2013b, maybe it’s different in later versions?

  2. Yaroslav says:

    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!

  3. Pingback: Plot markers transparency and color gradient | Undocumented Matlab

  4. Leslie says:

    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

    • Yair Altman says:
      [~, hContour] = contourf(peaks(20), 10);
      hFaces = hContour.FacePrims;
      for faceIdx = 1 : numel(hFaces)
         hFaces(faceIdx).ColorType = 'truecoloralpha';  % default = 'truecolor'
         hFaces(faceIdx).ColorData(4) = 150;   % default=255
      end
    • Leslie says:

      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…

    • Leslie says:

      Yes, it does. Thanks again.

  5. matt dash says:

    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?

  6. Evaluate says:

    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.

  7. James says:

    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.

    • James says:

      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!

    • Yair Altman says:

      @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.

    • James says:

      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.

  8. Sebastian says:

    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:

    figure
    i = 25000;  % Will not work if changed to 25001 (at least on my computer)
    h = plot(rand(i,1));
    c = uint8(randi(255,4,i));
    drawnow % Will not work, if this command is not issued
    set(h.Edge,'ColorBinding','interpolated','ColorData',c)
  9. Moshe says:

    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:

    close all
    t = linspace(0,2*pi,10);
    h = plot(t, sin(t), '-', 'LineWidth',10);
    drawnow;
    transp = 100*ones(size(t)); %abs(round(cos(t)*255));
    transp(1:5) = 200;
    h.Edge.ColorData
    newColor = repmat(h.Edge.ColorData, 1, numel(transp));
    newColor(4,:) = transp';
    newColor = uint8(newColor);
    set(h.Edge, 'ColorBinding','interpolated', 'ColorData',newColor);
    drawnow;

    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.

    • growl says:

      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.

  10. John Thompson says:

    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:

    hold on
    for i = 1:3
         tractHandle = plot3(tctData{tmpTctID}(:,1),tctData{tmpTctID}(:,2),tctData{tmpTctID}(:,3));
         colorMat = uint8([transpose(tctColor{tmpTctID})*255 ; repmat(aValue,1,size(tctColor{tmpTctID},1))]);
         set(tractHandle.(['ti',num2str(ti)]).Edge, 'ColorBinding', 'interpolated', 'ColorData', colorMat)
    end
    • @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.

  11. davion says:

    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.

    xlim([1,5]);
    hold('on');
    cd=uint8([255,200,250,50,0; 0,50,250,150,200; 0,0,0,100,150; 179,150,200,70,50]);
    h2b = plot(2:6,  15:-1:11, '.-r', 'LineWidth',8, 'DisplayName',' 0.7'); 
    set(h2b.Edge, 'ColorBinding','interpolated', 'ColorData',cd , 'ColorType', 'truecoloralpha');

    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.

    set(h2b.Edge, 'ColorBinding','interpolated', 'ColorData',cd , 'ColorType', 'truecoloralpha');

    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.

  12. Jerry says:

    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.

    xlim([1,5]);
    hold('on');
    cd = uint8([255,200,250,50,0; 0,50,250,150,200; 0,0,0,100,150; 179,150,200,70,50]);
    h2b = plot(2:6,  15:-1:11, '.-r', 'LineWidth',8, 'DisplayName',' 0.7'); 
    set(h2b.Edge, 'ColorBinding','interpolated', 'ColorData',cd , 'ColorType','truecoloralpha');

    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.

  13. vince says:

    Is it possible to fade a cluster of points held in two arrays x,y?

    h = plot(x,y,'.g')
    h.Color(4) = 0.5?
    • @Vince – yes:

      hLine = plot(x,y,'.g');
      hLine.MarkerHandle.FaceColorType = 'truecoloralpha';  % enable transparency
      hLine.MarkerHandle.EdgeColorData(4) = 128;  % 255 = opaque (default), 0 = fully trasparent
      drawnow
  14. Pingback: Colored longitudinal river profiles « TopoToolbox

Leave a Reply


Your email address will not be published. Required fields are marked *