Is it possible to smoothly change (like a photoshop gradient) the color of a plotted curve as a function of distance from a given point? - python-3.x

Suppose one has a plot like this, for which the peak is at (x,y) = (0,0.40). The distribution is plotted in blue. Is it possible to edit the color scheme of the distribution plot in such a way that the color is a gradient - the farther from x (or y or independently for both) the more the color changes - like this?
I've searched SO for help with this, but only found solutions in which line segments were different colors. But, I want the color transition to be smooth (like this but not 3-D) instead of rough, and I want the color to depend on its distance from a particular value rather than pre-determined "randomly". A different SO post did something similar (not quite what I want though), but could only do so as a scatter plot, which only works for changing colors based on x-value if the peak is at x=0 - I'd prefer it be generalized. As an example, the further from x=0 the redder the curve gets. Ideally, there's a way to do this with a matplotlib colormap.

Related

How to convert x and y coordinates into a heat map in excel?

I currently have a data set of x and y coordinates (position of an animal in an arena) over a period of time. I just used the coordinates to plot a scatter plot of what that looks like. However, instead of having every single coordinate as a separate point, i was wondering if there was a way to create a heat map of the points? So, the higher the likelihood of the animal in a specific area/ similar coordinates, the warmer the color? Hoping for the final product to be a depiction of the arena with a gradient of colors based on the likelihood the animal explores those regions?
Well with that many points, I don't know if Excel is the right choice if wanting to color-coordinate. The site https://app.rawgraphs.io/ has some really cool graphing capabilities. I use this when needing sankey's or something unusual that Excel cannot easily handle.
Here I used 1500 x/y points between 0 and 20. Then I selected the graph type called "Contour Plot".
Would this work?
Or here's a Hexagonal Binning chart of the same data...

How to represent density information on a matplotlib 3-D scatter plot

I am trying to plot the r,g,b channels in an image as a 3-D scatter plot.
This works well when i have a black and white image as i get a scatter plot with just two distinct clusters at two ends of the scatter plot.
However for color images the scatter plot does not make much sense visually because there are r,g,b values corresponding to many points in the color space in the image.
So i end up with something like the image shown below -
What i would like to achieve is somehow represent density information. For example if the number of points corresponding to (255,255,255) are 1000 and the number of points corresponding to (0,0,0) are only 500 then i want (255,255,255) to be dark red and (0,0,0) to be yellow/orangish
How do i achieve this in matplotlib? I am okay with some sort of bubble effect as well where the (255,255,255) is represented as a bigger bubble compared to (0,0,0) although i feel density information encoded as color information would be more visually appealing
Here's an attempt using Gaussian KDE. It's still far from perfect and the result largely depends on the estimation parameters (bw_method). There is perhaps a simpler way, maybe something using np.unique to get the frequency of each unique colour.
The idea is to estimate color density distribution as a multivariate gaussian mixture and use that as a colormap for the scatter plot.
It's a bit slow for anything serious but I think it gives nice results with small enough images. Maybe some FFT+convolution based estimation method could be faster.
Let's see some code. Nothing fancy: it flattens and reshapes image data the way gaussian_kde likes it and return RGB and density components. You can play with bw_method and see how the results change, the bigger, the smoother density you'll get.
from scipy.stats import gaussian_kde
def img_to_rgbk(img, bw=0.1):
rgb = img.reshape(-1, 3).T
k = gaussian_kde(rgb, bw_method=bw)(rgb)
r, g, b = rgb
return r, g, b, k
Here's the results with a toy image
img = chelsea()[100:200, 100:200]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r, g, b, k = img_to_rgbk(img, bw=0.5)
ax.scatter(r, g, b, c=k, alpha=0.2)
Notice c=k is used to set map marker color to the density information, alpha is needed to see a bit through the cloud.
Chelsea
Random colors
Gradient
Note here you can see how the wrong choice of bandwidth can be misleading. A small enough bw_method should reveal essentially a single color per column, repeated along rows. So every dot should have the same color (and it will with the right bandwidth).
Gradient + noise
Here with a better bandwidth and some noise to spread the colors. Notice the bigger density around the white-ish area where the discontinuity in the no-noise plot becomes a density maximum.

Interpolated curves between existing curves do not look correct

I have a chart that has several existing curves on it that I have tried to interpolate new curves in between. I have used linear interpolation in the form of y = ((x - x1)(y2 - y1) / (x2 - x1)) + y1, however the new curves look out of place.
You can see in the picture that every second line (from the bottom) is the interpolated line. While the very second line data points are exactly centered between the first and third data points in the y axis, the third line data points are not centered between the second and fourth y data points, making the graph look skew.
So I am thinking linear interpolation may not be what I am after here. Can someone recommend another method that would create curves between the existing ones, but replicates the same form?
Sudden changes in gradient are hard to interpolate. When you're at the point where you want an interpolated line to suddenly change gradient, there is no information from the points in close proximity that give information as to where the sudden change in gradient should occur.
To replicate the pattern, you actually need to copy the gradient of the line below then smoothly transition to the gradient of the line above. Visually we can see that it should occur half way between the change in gradients for the lines above and below on either side, but detecting the locations of those changes is not trivial.
The points where the sudden change in gradient are occurring are separated by a large change in the x-axis by only a small change in the y-axis. When calculating y-values for x-values in between the the changes in gradient you get the aberrations. I suggest trying to interpolate x-values based on y-values instead. For each curve, for each small arbitrary step in the y-axis, find/calculate the closest x-values from the curve on either side and take the average to plot your interpolation.
An unconventional approach may be a piece-meal style of interpolation. It may be possible to model the 3 regions of different gradients separately.
Start by identifying the 2 lines that would be drawn through the 2 sets of kinks, creating 3 regions of space. The vertical line would stop at the horizontal line near the bottom right corner of the graph.
For each region (and potentially for each value of x in each region) determine the gradient of the lines. When you're doing your interpolation of a new line, for each starting point (x1, y1), look at which region it falls in. Use the gradient of that region as a significant factor when determining the next point. Keep doing this until you reach a region boundary. When the interpolated point crosses into a different region, then use the gradient of that region as a significant factor to interpolate the next point.
It will be quite pointy if you did this strictly, so graph with some smoothing (or incorporate a smoothing factor using weighted averages of the gradients as you transition between regions, but this could be a whole lot of effort without necessarily closer results!)

how to choose a range for filtering points by RGB color?

I have an image and I am picking colors by RGB (data sampling). I select N points from a specific region in the image which has the "same" color. By "same" I mean, that part of the image belongs to an object, (let's say a yellow object). Each picked point in the RGB case has three values [R,G,B]. For example: [120,150,225]. And the maximum and minimum for each field are 255 and 0 respectively.
Let's assume that I picked N points from the region of the object in the image. The points obviously have different RGB values but from the same family (a gradient of the specific color).
Question:
I want to find a range for each RGB field that when I apply a color filter on the image the pixels related to that specific object remain (to be considered as inliers). Is it correct to find the maximum and minimum from the sampled points and consider them as the filter range? For example if the max and min of the field R are 120 ,170 respectively, can it be used as a the range that should be kept.
In my opinion, the idea is not true. Because when choosing the max and min of a set of sampled data some points will be out of that range and also there will be some point on the object that doesn't fit in this range.
What is a better solution to include more points as inliers?
If anybody needs to see collected data samples, please let me know.
I am not sure I fully grasp what you are asking for, but in my opinion filtering in RGB is not the way to go. You should use a different color space than RGB if you want to compare pixels of similar color. RGB is good for representing colors on a screen, but you actually want to look at the hue, saturation and intensity (lightness, or luminance) for analysing visible similarities in colors.
For example, you should convert your pixels to HSI or HSL color space first, then compare the different parameters you get. At that point, it is more natural to compare the resulting hue in a hue range, saturation in a saturation range, and so on.
Go here for further information on how to convert to and from RGB.
What happens here is that you implicitly try to reinvent either color indexing or histogram back-projection. You call it color filter but it is better to focus on probabilities than on colors and color spaces. Colors of course not super reliable and change with lighting (though hue tends to stay the same given non-colored illumination) that's why some color spaces are better than others. You can handle this separately but it seems that you are more interested in the principles of calculating "filtering operation" that will do segmentation of the foreground object from background. Hopefully.
In short, a histogram back-projection works by first creating a histogram for R, G, B within object area and then back-projecting them into the image in the following way. For each pixel in the image find its bin in the histogram, calculate its relative weight (probability) given overall sum of the bins and put this probability into the image. In such a way each pixel would have probability that it belongs to the object. You can improve it by dividing with probability of background if you want to model background too.
The result will be messy but somewhat resemble an object segment plus some background noise. It has to be cleaned and then reconnected into object using separate methods such as connected components, grab cut, morphological operation, blur, etc.

Draw axis thru x=0 and y=0

I have a set of data that I'm plotting as a scatter graph which has both positive and negative values on both axis. When I plot this in Flot, the axis are draw at the bottom and the left by default. Is there a way to make it draw the axis through the center of the graph? #X=0 and Y=0?
In other words, instead of this:
I want something like this:
That isn't possible in the default flot. I'm sure it could be hacked in if you wanted to dig into the source, but flot by itself only supports left/right for the y-axis, and top/bottom for the x-axis.
In case anybody else comes across the same need, I created a plugin for Flot and put it here:
https://github.com/burlandm/Flot-Origin-Axis
It does what I need, but I won't make any promises that it'll fit your particular scenario. If I have time, I might try and update it to cover more scenarios.

Resources