4
$\begingroup$

I have an array of 128x256 data points in a rectilinear array. For each point there is a 2D vector quantity and a scalar quantity (normalised to -1 <= x <= 1).

I very much like the ListLineIntegralConvolutionPlot function for plotting the vector field, I think the fine detail is wonderfully captured. I also think the ListContourPlot function with the "TemperatureMap" ColorFunction does a great job of showing the structure of the scalar field.

I have experimented using ListStreamPlot over the contour plot and had reasonable results. See the image (a few extra graphics items are placed over the top as well).

Desired effect with streamlines

My wish is to create a similar plot with the line integral convolution plot in place of the stream lines. To prevent the LIC plot completely obscuring the underlying contour plot I was hoping to have the noise that is to be convolved made transparent based on each pixels value (blackness) such that white pixels are completely transparent and black pixels are completely opaque, with the in-between greys mapping linearly between them.

For example, the noise image here:

Noise before transparency

Would become this (but convolved by the vector field.)

Non-convolved GIMP mock up of the desired end result.

I've tried supplying the transparent noise as an image to the LIC routine without success and I feel there must be a smarter, more Mathematica, solution to this problem.

If anyone can suggest one, I would be very thankful.

As an added challenge I will be producing ~150 of these plots. The LIC is already a slow process so I don't want to add to this time. More performant solutions would be even better!

EDIT:

Many thanks to LLlAMnYP. I tweaked the contrast on the LIC image a little to get a 'better' contrast between the light and dark areas. My final Plotting function is (simplified...):

licplot[scal_, vec_] := Show[{ 
  ListContourPlot[
   scal,
   ColorFunction -> "TemperatureMap", 
   PlotRange -> {{-5, 5}, {-2.5, 2.5}, {-1, 1.0}}, AspectRatio -> 0.5,
     ClippingStyle -> {Blue, Darker[Red]}, BaseStyle -> {14}],

  ListLineIntegralConvolutionPlot[vec, AspectRatio -> 0.5, 
    ColorFunction -> (RGBColor[#5, #5, #5] &), RasterSize -> 720, 
    LineIntegralConvolutionScale -> 3] 
/. {r_, g_, b_} -> {r^2, g^2, b^2, 1 - (1/(1 + Exp[-20*(r - 0.5)]))}

]

Giving the very nice result of:

Final LIC Plot.

$\endgroup$
  • $\begingroup$ Welcome to Mathematica.SE! I hope you will become a regular contributor. To get started, 1) take the introductory Tour now, 2) when you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge, 3) remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign, and 4) give help too, by answering questions in your areas of expertise. $\endgroup$ – bbgodfrey Jun 2 '15 at 11:45
  • $\begingroup$ A careful use of ColorFunction should do the trick, I think. $\endgroup$ – LLlAMnYP Jun 2 '15 at 11:47
  • $\begingroup$ Do you mean ListStreamPlot rather than ListStreamLinePlot? $\endgroup$ – bbgodfrey Jun 2 '15 at 11:51
  • $\begingroup$ I did. I've edited to reflect this. $\endgroup$ – JamesFurness Jun 2 '15 at 12:46
  • $\begingroup$ Why not turn the plot into an image and use SetAlphaChannel[] with the noise image setting the transparency? Or, use ImageCompose[] for an overlay, after setting the alpha channel of the noise image appropriately… $\endgroup$ – J. M. is away Jun 2 '15 at 12:54
2
$\begingroup$

Apparently, the problem is with LineIntegralConvolutionPlot generating a Graphics object with Raster[{{{rgb},{rgb},{rgb}...}},...] irrespective of the underlying image or the color specifications or whatever. My solution is to modify the resulting graphics object.

First let's generate some fake data:

cp = ContourPlot[
 1/Sqrt[y^2 + (x - 2)^2] - 1/Sqrt[y^2 + (x + 2)^2], {x, -5, 
  5}, {y, -3, 3}, AspectRatio -> Automatic, 
 ColorFunction -> "TemperatureMap", PlotRange -> {-3, 3}, 
 Contours -> 20]

licp = LineIntegralConvolutionPlot[{-y, x - 2}/(
   y^2 + (x - 2)^2) + {y, -x - 2}/(y^2 + (x + 2)^2), {x, -5, 
   5}, {y, -3, 3}, RasterSize -> 300, 
  LineIntegralConvolutionScale -> 3, AspectRatio -> Automatic, 
  ColorFunction -> (RGBColor[#5, #5, #5] &)]

Then use a replacement rule to add transparency

licp /. {r_, g_, b_} -> {r, g, b, (1-r)^(1/2)}

This is because the InputForm of licp looks like Graphics[{Raster[{{{rgb},{rgb},{rgb}...}}...] even if we explicitly specify some opacity in the color function. We need to convert the rgb triplets to lists of four numbers where the last is opacity. As you want black to be fully opaque and we're getting a grayscale image, I just use 1-Red to get a value for the opacity.

And show everything:

Show[cp, %]

Result

The tl;dr is that you need to create the alpha channel yourself after the LineIntegralConvolutionPlot has been generated.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.