Matplotlib questions [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Plotting with Python
I've been using Matprolib for plotting. I've found it very useful, but I dont know exactly how to use the 'fill_between()' function. I have tried several times to fix it but I cant get to the point.
I have been studying several tutorials, but I havent found very useful ones (according to my task).
My task is to fill the area that all lines have in common, just like this:
Whatitshoulddo
And this is what the system does:
Whatitshouldntdo
Is there any way to do it? Anyone knows how to use 'fill_between()' in a correct way?

You can use the where option. As in the example you can do something like:
fill_between(x, myzero, y1, where=y2>=y1, facecolor='blue', interpolate=True)
Where y2 is the line that is sometimes on top. You will have do do this for each of the lines, though.
Another option is to define a minimum of the functions and fill below that, though you will either need to know before hand that the ys are defined at the same points or use interpolation so that they are all defined at the same points.
mymin = np.minimum(y1,y2,y3)
fill_between(x, myzero, mymin)
Hope that helps.
Edit: To find the minimum from several functions which are all defined for the same x-values you can use the following:
def OverallMinimum(*ys):
mymin = y[0].copy()
for y in ys:
min = np.minimum(mymin,y)
return mymin
Then you can use the second fill_between from above to plot between zero and the minimum from that function.

Related

Multiple functions plotted as f(y) instead of f(x) in pandas

I'm new to Python so I hope you'll forgive my silly questions. I have read a dataset from excel with pandas. The dataset is composed by 3 functions (U22, U35, U55) and related same index (called y/75). enter image description here
now I would like to "turn" the graph so that the index "y/75" goes on the y-axis instead of the x-axis, keeping all the functions in the same graph. The results I want to obtain is like in the following picture enter image description here
the code I've used is
var = pd.read_excel('path.xlsx','SummarySheet', index_col=0)
norm_vel=var[['U22',"U35","U55"]]
norm_vel.plot(figsize=(10,10), grid='true')
But with this code I couldn't find a way to change the axes. Then I tried a different approach, so I turned the graph but couldn't add all the functions in the same graph but just one by one
var = pd.read_excel('path.xlsx','SummarySheet', index_col=False)
norm_vel2=var[['y/75','U22',"U35","U55"]]
norm_vel2.plot( x='U22', y='y/75', figsize=(10,10), grid='true' )
plt.title("Velocity profiles")
plt.xlabel("Normalized velocity")
plt.ylabel("y/75")
obtaining this enter image description here
I am not very familiar with dataframes plot. And to be honest, I've been stalking this question expecting that someone would give an obvious answer. But since no one has one (1 hour old questions, is already late for obvious answers), I can at least tell you how I would do it, without the plot method of the dataframe
plt.figure(figsize=(10,10))
plt.grid(True)
plt.plot(var[['U22',"U35","U55"]], var['y/75'])
plt.title("Velocity profiles")
plt.xlabel("Normalized velocity")
plt.ylabel("y/75")
When used to matplotlib, in which, you can have multiple series in both x and y, the instinct says that pandas connections (which are just useful functions to call matplotlib with the correct parameters), should make it possible to just call
var.plot(x=['U22', 'U35', 'U55'], y='y/75')
Since after all,
var.plot(x='y/75', y=['U22', 'U35', 'U55'])
works as expected (3 lines: U22 vs y/75, U35 vs y/75, U55 vs y/75). So the first one should have also worked (3 lines, y/75 vs U22, y/75 vs U35, y/75 vs U55). But it doesn't. Probably the reason why pandas documentation itself says that these matplotlib connections are still a work in progress.
So, all you've to do is call matplotlib function yourself. After all, it is not like pandas is doing much more when calling those .plot method anyway.

Matplotlib change length of legend lines [duplicate]

This question already has an answer here:
Matplotlib: Horizontal Linelength in Legend
(1 answer)
Closed 1 year ago.
I have the following code to generate the plots with a shared legend
from matplotlib.legend_handler import HandlerLine2D, HandlerTuple
import matplotlib.pyplot as pt
fig = pt.figure(figsize = (12,4))
gd = fig.add_gridspec(1,2)
p1 = fig.add_subplot(gd[0])
p2 = fig.add_subplot(gd[1])
redLine, = p1.plot([1,2,3], [4,2,5], 'r-')
greenLine, = p1.plot([1,2,3], [8,9,1], 'g--')
redDot, = p2.plot([1,2,3], [4,2,5], 'ro')
greenDot, = p2.plot([1,2,3], [8,9,1], 'gs')
leg = p2.legend([(redLine, redDot), (greenLine, greenDot)], ['Red', 'Green'], handler_map = {tuple: HandlerTuple(ndivide=None)})
Doing this however makes the legend lines a bit too short to clearly differentiate between solid line and dashed, so I'm trying to figure out how to make them longer without making the entire legend bigger.
From the documentation here https://matplotlib.org/stable/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D, it seems I should be able to do this by setting the sketch_params property. I have the following
legLines = leg.get_lines()
pt.setp(legLines, sketch_params = (1,2,3))
but this tells me it must be real number, not tuple -- contrary to what the documentation suggests. Also note the numbers in this example are arbitrary since I was just trying to understand how to use this.
I've tried a bunch of different stuff to get this shared legend to happen, and this is by far the closest I've gotten. So I was just hoping someone could help explain how I'm misusing the sketch_params attribute, since it sounds like I should be able to specify the length with that.
EDIT:
It was mentioned in the comments that to get sketch_params to work, I can simply do
for line in legLines:
line.set_sketch_params(1,2,3)
But it turns out that doesn't actually let me change the length of the lines like I wanted to. So I changed the question for more general help on how to achieve that.
Sorry for the noise, turns out the answer is quite simple, and I found it on this post How to adjust the size of matplotlib legend box? and Matplotlib: Horizontal Linelength in Legend. Just need to use the handlelength keyword. Apologies, I wasn't phrasing the question correctly when looking for it. Marking this as duplicate.

Matplotlib: cancelling the offset of axis introduced in matplotlib 2.0 [duplicate]

This question already has answers here:
How can I change the x axis in matplotlib so there is no white space?
(2 answers)
Closed 5 years ago.
Just noticed this nuance when I editing my works.
Previously, the matplotlib would look like this:
x=[1,2,3,4,5]
y=[4,5,5,2,1]
plot(x,y,'-')
But after recent upgrade I believe, the there are offset, which would return like this
It's a little bit unncessary from what I seen now. I want to know
If this offset is a good practice in data visualization? If so, I'll leave it as it is.
How to cancel out this offset?
I can manually restore the limit by plt.gca().set_xlim([1, 5]), but that wouldn't scale if I have another 20 plots. I googled around and didn't find too much info on this.
In matplotlib v2.0.x, the default axes margin has changed, from 0 to 0.05, which is the value controlling the whitespace around your data on the axes. See here for more on the reasoning behind this change.
There are several ways to revert to the previous behaviour.
1) To reset margins to 0 for a single Axes instance:
plt.margins(0)
or
ax.margins(0)
2) To reset margins to 0 for all plots in a script, use rcParams and set this at the top of your script:
plt.rcParams['axes.autolimit_mode'] = 'round_numbers'
plt.rcParams['axes.xmargin'] = 0.
plt.rcParams['axes.ymargin'] = 0.
3) To change the default value for all plots on a machine, modify your the matplotlibrc file to include these lines:
axes.autolimit_mode: round_numbers
axes.xmargin : 0.
axes.ymargin : 0.
Note that to use method (1) and truly get the old behaviour, you may also need to set plt.rcParams['axes.autolimit_mode'] = 'round_numbers'.
Guess whether its good practice is a bit of a discussion. It somehow suggest that your plot continues (but you just show a window of it), so if your plot is only defined in this region having an offset would make sense. If it actually continues but you just plot this part, then it's logical to remove it.
The scalable approach is
plt.gca().set_xlim([np.min(x), np.max(x)])

Using BOTH error bars and upper/lower limits in python

Warning: I am very new at python and know very little.
I am trying to graph (x,y) with error bars in both directions. I am able to achieve this, using:
from matplotlib import pyplot
pyplot.errorbar(x,y,yerr=y_error,xerr=xerror)
However, sometimes the error in either x or y is zero. In this case, I want the program to create an upper (x) and lower (y) limit just for those data points. The actual value of the limit doesn't matter; it just needs to show that it is such.
I've found some things suggesting to add 'lolim' and 'uplim' to the pyplot.errorbar, but it's not working. Do I need a for loop or something to add in the lower/upper limits?
Thanks.
Suggest a simple solution like so:
all the non-limits:
ind1 = y_error*x_error!=0
pyplot.errorbar(x[ind1],y[ind1],yerr=y_error[ind1],xerr=xerror[ind1],fmt='k+')
x-limits:
ind2 = x_error==0
pyplot.errorbar(x[ind2],y[ind2],yerr=y_error[ind2],fmt='k<')
y-limits:
ind3 = y_error==0
pyplot.errorbar(x[ind3],y[ind3],xerr=x_error[ind3],fmt='kv')
I'll leave it to you to decide what to do with the cases where both x and y are limits.

Plotting two functions simultaneously with matplotlib

basically I want to graph two functions
g1 = x*cos(x*pi)
g2 = 1 - 0.6x^2
and then plot the intersection, I already have a module that takes inputs close to the two lines intersections, and then converges to those points (there's four of them)
but I want to graph these two functions and their intersections using matplotlib but have no clue how. I've only graphed basic functions. Any help is greatly appreciated
Assuming you can get as far as plotting one function, with x and g1 as numpy arrays,
pylab.plot(x,g1)
just call plot again (and again) to draw any number of separate curves:
pylab.plot(x,g2)
finally display or save to a file:
pylab.show()
To indicate a special point such as an intersection, just pass in scalars for x, y and ask for a marker such 'x' or 'o' or whatever else you like.
pylab.plot(x_intersect, y_intersect, 'x', color="#80C0FF")
Alternatively, I often mark a special place along x with a vertical segment by plotting a quick little two-point data set:
pylab.plot( [x_special, x_special], [0.5, 1.9], '-b' )
I may hardcode the y values to look good on a plot for my current project, but obviously this is not reusable for other projects. Note that plot() can take ordinary python lists; no need to convert to numpy arrays.
If you can't get as far as plotting one function (just g1) then you need a basic tutorial in matplot lib, which wouldn't make a good answer here but please go visit http://matplotlib.org/ and google "matplotlib tutorial" or "matplotlib introduction".

Categories

Resources