Plot curve with varying opacity with matplotlib - python

I have a plot with several curves that looks like this:
These curves start from the top right corner and finish around the point (0.86, 0.5).
I want to focus attention on the end point. If I zoom on this region, it is still not very easy to distinguish the different lines because they overlap several times.
My idea is then to add a gradient of opacity so that the curves would be transparent at their start point and then, the opacity would increasing as we get closer to the end point.
How would you do that with matplotlib?
Currently, I just basically do for the three curves:
plt.plot( r, l )
with r, l being two arrays.

You could always break down your x and y arrays into smaller arrays that you plot separately. This would give you the opportunity to modify alpha for each segment.
See example below:
import numpy as np
import matplotlib.pyplot as plt
N_samp=1000
x=np.arange(N_samp)
y=np.sin(2*np.pi*x/N_samp)
step=10
[plt.plot(x[step*i:step*(i+1)],y[step*i:step*(i+1)],alpha=np.min([0.1+0.01*i,1]),color='tab:blue',lw=1) for i in range(int(N_samp/step))]
plt.show()

Related

How to plot a zero-one 2d matrix that will look like a scatter?

Might be a strange question, but I am wondering if it's possible to replace a 2d matrix made up of ones and zeros with a scatter plot of say, black dots where all the ones are but nothing for zeros:
Unfortunately I don't have the best reproducible answer, but I have a 2D array made up for zeros and ones (size 275 and 357):
I am hoping to basically cover the areas that are made up of ones with small black dots (assuming in the form of a scatter plot which will later be overlayed on another contour plot):
The original contour plot is on the left and the idea I'm going for is on the right (picture more black dots just on the areas made up of ones):
I tried making a reproducible array here:
#array of ones and zeros
array = np.array(([0,0,0,0,0,0,1,1,0,0,0,1,1,1], [0,1,0,0,0,1,0,0,0,0,0,1,0,1]))
plt.pcolormesh(array)
I tried using this as an example and apply it to the 2D array, but getting some errors?
# as an example, borrowed from: https://stackoverflow.com/questions/41133419/how-to-do-the-scatter-plot-for-the-lists-or-2d-array-or-matrix-python
X=[[0,3,4,0,1,1],
[0,0,0,5,1,1],
[6,7,0,8,1,1],
[3,6,1,5,6,1]]
Y=[12,15,11,10]
x_arr = np.array(X)
y = np.array(Y)
fig, ax = plt.subplots()
#colors=list('bgrcmykw')
for i, x in enumerate(x_arr.T):
ax.scatter(x,y, c='k',s=5)
plt.show()
My goal is to basically convert this 2d matrix made up of ones and zeros to a scatter plot or some sort of graph where the ones are made up of black dots and the zeros have nothing. This will later be overlaid on another contour plot. how might I go about setting the ones to a scatter plot made up of black dots?
Here's what I would do. I didn't plot all the points to reduce the computational demand of creating the figure. you might want to do that if you have a lot of points to plot. either way, you can change that according to your need.
import numpy as np
from matplotlib import pyplot as plt
np.random.seed(0)
mask = np.random.randint(0, 2, (20, 20))
ys, xs = np.where(mask.astype(bool))
plt.imshow(mask)
plt.scatter(xs[::2], ys[::2])
output:

How to label multiple arrows in the same quiver plot using python

I am working on a visualization script for a linear algebra class at the university and I am trying to show multiple vectors using the quiver function in python. I am trying to plot vectors coming from a 2x2 matrix in one quiver function, however, now that I am trying to label them I would like to access each vector individually.
import numpy as np
import matplotlib.pyplot as plt
A = np.array([[1,3], [2,2]])
# create figure
fig = plt.figure()
# creates variable containing current figure
ax = fig.gca()
baseArrow = ax.quiver(*origin, A[0,:], A[1,:], color=['r','g']', angles='xy', scale_units='xy', scale=1)
ax.quiverkey(baseArrow,.85,.85,0.8,'i-hat',labelcolor='k',labelpos='S', coordinates = 'figure')
# display grid
plt.grid()
# display figure
plt.show()
This alows me to label the first vector with the respective color (red). Now what I would like to do is label the second vector in green with a different label?
Maybe something like:
ax.quiverkey(baseArrow**[2]**,.85,.85,0.8,'i-hat',labelcolor='k',labelpos='S', coordinates = 'figure')
Is there any way to pull out each vector by itself or would it be better to plot them individually instead of as a vector? I looked at the following question but it doesn't really solve my issue. Matplotlib Quiver plot matching key label color with arrow color
My feeling is that the quiver function is better suited/intended to plot numerous vectors as you would find in a graph depicting magnetic forces, vortices (sic) or gradients (see meshgrid for example). And it's API reflects that, in that it accepts end and start coordinates separately: i.e. you need to split the components of your vectors as you have done above.
May I suggest you look into the plot or arrow functions which will give you greater control over your visualization (e.g. vector-independent labels) and will also provide greater clarity in your code, as you will be able to declare vectors (as np.arrays of course) and use them directly.
Finally note that you can obtain fig and ax in one call: fib, ax = plt.subplots().
Hope this helps!

How to control the cell size of a pyplot pcolor heatmap?

I have a pair of lists of numbers representing points in a 2-D space, and I want to represent the y/x ratios for these points as a 1-dimensional heatmap, with a diverging color map centered around 1, or the logs of my ratios, with a diverging color map centered around 0.
How do I do that?
My current attempt (borrowing somewhat from Heatmap in matplotlib with pcolor?):
from matplotlib import numpy as np
import matplotlib.pyplot as plt
# There must be a better way to generate arrays of random values
x_values = [np.random.random() for _ in range(10)]
y_values = [np.random.random() for _ in range(10)]
labels = list("abcdefghij")
ratios = np.asarray(y_values) / np.asarray(x_values)
axis = plt.gca()
# I transpose the array to get the points arranged vertically
heatmap = axis.pcolor(np.log2([ratios]).T, cmap=plt.cm.PuOr)
# Put labels left of the colour cells
axis.set_yticks(np.arange(len(labels)) + 0.5, minor=False)
# (Not sure I get the label order correct...)
axis.set_yticklabels(labels)
# I don't want ticks on the x-axis: this has no meaning here
axis.set_xticks([])
plt.show()
Some points I'm not satisfied with:
The coloured cells I obtain are horizontally-elongated rectangles. I would like to control the width of these cells and obtain a column of cells.
I would like to add a legend for the color map. heatmap.colorbar = plt.colorbar() fails with RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).
One important point:
matplotlib/pyplot always leaves me confused: there seems to be a lot of ways to do things and I get lost in the documentation. I never know what would be the "clean" way to do what I want: I welcome suggestions of reading material that would help me clarify my very approximative understanding of these things.
Just 2 more lines:
axis.set_aspect('equal') # X scale matches Y scale
plt.colorbar(mappable=heatmap) # Tells plt where it should find the color info.
Can't answer your final question very well. Part of it is due to we have two branches of doing things in matplotlib: the axis way (axis.do_something...) and the MATLAB clone way plt.some_plot_method. Unfortunately we can't change that, and it is a good feature for people to migrate into matplotlib. As far as the "Clean way" is concerned, I prefer to use whatever produces the shorter code. I guess that is inline with Python motto: Simple is better than complex and Readability counts.

Line markers density

I plot a couple of lines in log scale with a huge amount of points. I plot them in black using different line styles/markers. I use "markevery" property to decrease amount of markers. X-values change at even intervals.
The issue I have is that markers distributed unevenly - less of them near 0, and more near the right end of each line.
Is there are any way to get around this issue without nitpicking x-values, so that they will be "evenly" distributed on log-scale?
You can give the index of points you want to plot. In logscale these points should be non-uniformly distributed. You can try logspace to achieve it.
import pylab as plt
import numpy as np
x=np.arange(1,1e5)
# Normal plot
#plt.plot(x,x,'o-')
# Log plot
idx=np.logspace(0,np.log10(len(x)),10).astype('int')-1
plt.plot(x[idx],x[idx],'o-')
plt.xscale('log')
plt.yscale('log')
plt.show()
generates:

Draw connecting line to points with a zero ordinate on a log scale with matplotlib?

Is it possible to plot the connecting line to points whose y value is zero on a log scale in matplotlib?
I have some data that I want to plot with a log scale on the y-axis. The y values for some of the data lie at zero. I realize it's not possible for matplotlib to plot these points on a log scale, but I really wish it would draw the connecting line from the previous point or to the next point (if either are non-zero).
One solution would be to simply replace all zeros with some TINY number. I'd rather not do this.
What matplotlib draws:
What I'd like it to draw:
I'd be looking to solve this by using the 'symlog' option on the y axis instead of 'log'. There's then a linthreshy arg which lets you specify
"The range within which the plot is linear (to avoid having the plot
go to infinity around zero).".
In fact it's exactly this sort of issue the option seems designed to deal with. It can look a bit goofy having this weird linear zone along the bottom of your log scale plot, but you can make it pretty small.
You could always appened an extra point to the bottom of the graph by pulling out the coordinates from your current figure:
import numpy as np
import pylab as plt
# Create some sample data like yours
X = np.linspace(0,3,100)
Y = np.exp(-X)
def semilogy_to_bottom(X,Y):
# Plot once to move axes and remove plot
P, = plt.semilogy(X,Y)
plt.gca().lines.remove(P)
# Find the bottom of the graph
y_min = plt.gca().get_ylim()[0]
# Add a new point
X2 = np.concatenate((X,[X[-1]]))
Y2 = np.concatenate((Y,[y_min]))
plt.semilogy(X2,Y2)
semilogy_to_bottom(X,Y)
plt.xlim(0,5)
plt.show()

Categories

Resources