Consider the following code
import matplotlib.pyplot as plt
import numpy as np
time=np.arange(-100,100,01)
val =np.sin(time/10.)
time=-1.0*time
plt.figure()
plt.plot(time,val)
plt.xlim([70,-70])
plt.savefig('test.pdf')
when I open the pdf in inkscape, I can select (with F2) the entire data, it's just invisible outside of the specified xlim interval:
The problem seems to be the line
time=-1.0*time
If I omit this line, everything works perfectly.. no idea why this is. I often need such transformations because I deal with paleo-climate data which are sometimes given in year B.C. and year A.D., respectively.
The problem I see with this behavior is that someone could in principle get the data outside the range which I want to show.
Has someone a clue how to solve this problem (except for an slice of the arrays before plotting)?
I use matplotlib 1.1.1rc2
You can mask your array when plotting according to the limits you choose. Yes, this also requires changes to the code, but maybe not as extensive as you might fear. Here's an updated version of your example:
import matplotlib.pyplot as plt
import numpy as np
time=np.arange(-100,100,01)
val =np.sin(time/10.)
time=-1.0*time
plt.figure()
# store the x-limites in variables for easy multi-use
XMIN = -70.0
XMAX = 70.0
plt.plot(np.ma.masked_outside(time,XMIN,XMAX),val)
plt.xlim([XMIN,XMAX])
plt.savefig('test.pdf')
The key change is using np.ma.masked_outside for your x-axis value (note: the order of XMIN and XMAX in the mask-command is not important).
That way, you don't have to change the array time if you wanted to use other parts of it later on.
When I checked with inkscape, no data outside of the plot was highlighted.
Related
I'm building a python application to keep track of the BTC values over time through a graph that updates in realtime; in the x axis there is time and in the y axis the value of the corresponding BTC. my problem is that at the beginning the BTC values in the y axis are correct as in the first figure, but after some data received, the graph decides to "zoom" and express all the data in a different notation, as in the second figure (open imgur link).
https://imgur.com/a/spogs9G
I tried these two lines of code but without success:
plt.autoscale(enable=False, axis='y')
ax.get_yaxis().get_major_formatter().set_scientific(False)
If it can help, i am using:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
If you would like to see all or part of the code, please ask.
Thank you in advance.
Fix the y-axis by using (as an example):
ax.set_ylim(0,1000)
and define the lower and upper bound accordign to your problem.
ax.set_ylim(lower_bound,upper_bound)
I am using bqplot to create a live line graph on jupyter-notebook + VOILA
from bqplot import pyplot as plt2
import datetime
x_values = [] #array of datetimes
y_values = [] #array of 10+ digit numbers
plt2.show()
def functionThatIsCalledRepeatedly(x_val, y_val):
x_values.append(x_val)
y_values.append(y_val)
plt2.plot(x_values, y_values)
Part of the Resulting Plot
My question is, how do I remove the scientific notation from the y-axis. It's a simple task but I have tried a lot of things.
I tried using axes.tick_format property of the graph but I think that only works if you have axes objects which I cannot have because they require the mandatory Scale property which I cannot use because the graph is live and the x and y scales need to be generated/recalibrated while it runs.
I tried changing y_values.append(y_val) to y_values.append("{:.2f}".format(y_val)) but that converts to a string and bqplot doesn't process it as a number so it ends up with negative numbers on top of the 0 sometimes.
I tried converting to a numpy array and then doing np.set_printoptions(suppress=True) which (obviously) didn't work.
Basically tried a lot of things and I think it comes down to some bqplot property that may or may not exist. Have been stuck for a while. Thank you!
You can provide axes options with the tick format you want to the plot method:
plt2.plot(x_values, y_values, axes_options={
y=dict(tick_format='0.2f')
})
You can see examples of this axes_options (using a scatter plot, but that should work the same) in this notebook: https://github.com/bqplot/bqplot/blob/master/examples/Marks/Pyplot/Scatter.ipynb
I am using Python 2.7 and need to draw a time series using matplotlib library. My y axis data is numeric and everything is ok with it.
The problem is my x axis data which is not numeric, and matplotlib does not cooperate in this case. It does not draw me a time series even though it is not supposed to affect the correctness of the plot, because the x axis data is arranged by a given order anyway and it's order does not affect anything logically.
For example let's say the x data is ["i","like","python"] and the y axis data is [1,2,3].
I did not add my code because I've found that the code is ok, it works if I change the data to all numeric data.
Please explain me how can I use matplotlib to draw the time series, without making me to convert the x values to numeric stuff.
I've based my matplotlib code on following answers: How to plot Time Series using matplotlib Python, Time Series Plot Python.
Matplotlib requires someway of positioning those labels. See the following example:
import matplotlib.pyplot as plt
x = ["i","like","python"]
y = [1,2,3]
plt.plot(y,y) # y,y because both are numeric (you could create an xt = [1,2,3]
plt.xticks(y,x) # same here, the second argument are the labels.
plt.show()
, that results in this:
Notice how I've put the labels there but had to somehow say where they are supposed to be.
I also think you should put a part of your code so that it's easier for other people to suggest upon.
I would like to plot a set of points using pyplot in matplotlib but have none of the points be on the edge of my axes. The autoscale (or something) sets the xlim and ylim such that often the first and last points lie at x = xmin or xmax making it difficult to read in some situations.
This is more often problematic with loglog() or semilog() plots because the autoscale would like xmin and xmax to be exact powers of ten, but if my data contains only three points, e.g. at xdata = [10**2,10**3,10**4] then the first and last points will lie on the border of the plot.
Attempted Workaround
This is my solution to add a 10% buffer to either side of the graph. But is there a way to do this more elegantly or automatically?
from numpy import array, log10
from matplotlib.pyplot import *
xdata = array([10**2,10**3,10**4])
ydata = xdata**2
figure()
loglog(xdata,ydata,'.')
xmin,xmax = xlim()
xbuff = 0.1*log10(xmax/xmin)
xlim(xmin*10**(-xbuff),xmax*10**(xbuff))
I am hoping for a one- or two-line solution that I can easily use whenever I make a plot like this.
Linear Plot
To make clear what I'm doing in my workaround, I should add an example in linear space (instead of log space):
plot(xdata,ydata)
xmin,xmax = xlim()
xbuff = 0.1*(xmax-xmin)
xlim(xmin-xbuff,xmax+xbuff))
which is identical to the previous example but for a linear axis.
Limits too large
A related problem is that sometimes the limits are too large. Say my data is something like ydata = xdata**0.25 so that the variance in the range is much less than a decade but ends at exactly 10**1. Then, the autoscale ylim are 10**0 to 10**1 though the data are only in the top portion of the plot. Using my workaround above, I can increase ymax so that the third point is fully within the limits but I don't know how to increase ymin so that there is less whitespace at the lower portion of my plot. i.e., the point is that I don't always want to spread my limits apart but would just like to have some constant (or proportional) buffer around all my points.
#askewchan I just succesfully achieved how to change matplotlib settings by editing matplotlibrc configuration file and running python directly from terminal. Don't know the reason yet, but matplotlibrc is not working when I run python from spyder3 (my IDE). Just follow steps here matplotlib.org/users/customizing.html.
1) Solution one (default for all plots)
Try put this in matplotlibrc and you will see the buffer increase:
axes.xmargin : 0.1 # x margin. See `axes.Axes.margins`
axes.ymargin : 0.1 # y margin See `axes.Axes.margins`
Values must be between 0 and 1.
Obs.: Due to bugs, scale is not correctly working yet. It'll be fixed for matplotlib 1.5 (mine is 1.4.3 yet...). More info:
axes.xmargin/ymargin rcParam behaves differently than pyplot.margins() #2298
Better auto-selection of axis limits #4891
2) Solution two (individually for each plot inside the code)
There is also the margins function (for put directly in the code). Example:
import numpy as np
from matplotlib import pyplot as plt
t = np.linspace(-6,6,1000)
plt.plot(t,np.sin(t))
plt.margins(x=0.1, y=0.1)
plt.savefig('plot.png')
Obs.: Here scale is working (0.1 will increase 10% of buffer before and after x-range and y-range).
A similar question was posed to the matplotlib-users list earlier this year. The most promising solution involves implementing a Locator (based on MaxNLocator in this case) to override MaxNLocator.view_limits.
I am a new user to the python & matplotlib, this might be a simple question but I searched the internet for hours and couldn't find a solution for this.
I am plotting precipitation data from which is in the NetCDF format. What I find weird is that, the data doesn't have any negative values in it.(I checked that many times,just to make sure). But the value in the colorbar starts with a negative value (like -0.0000312 etc). It doesnt make sense because I dont do any manipulations to the data, other that just selecting a part of the data from the big file and plotting it.
So my code doesn't much to it. Here is the code:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
from netCDF4 import Dataset
cd progs
f=Dataset('V21_GPCP.1979-2009.nc')
lats=f.variables['lat'][:]
lons=f.variables['lon'][:]
prec=f.variables['PREC'][:]
la=lats[31:52]
lo=lons[18:83]
pre=prec[0,31:52,18:83]
m = Basemap(width=06.e6,height=05.e6,projection='gnom',lat_0=15.,lon_0=80.)
x, y = m(*np.meshgrid(lo,la))
m.drawcoastlines()
m.drawmapboundary(fill_color='lightblue')
m.drawparallels(np.arange(-90.,120.,5.),labels=[1,0,0,0])
m.drawmeridians(np.arange(0.,420.,5.),labels=[0,0,0,1])
cs=m.contourf(x,y,pre,50,cmap=plt.cm.jet)
plt.colorbar()
The output that I got for that code was a beautiful plot, with the colorbar starting from the value -0.00001893, and the rest are positive values, and I believe are correct. Its just the minimum value thats bugging me.
I would like to know:
Is there anything wrong in my code? cos I know that the data is right.
Is there a way to manually change the value to 0?
Is it right for the values in the colorbar to change everytime we run the code, cos for the same data, the next time I run the code, the values go like this " -0.00001893, 2.00000000, 4.00000000, 6.00000000 etc"
I want to customize them to "0.0, 2.0, 4.0, 6.0 etc"
Thanks,
Vaishu
Yes, you can manually format everything about the colorbar. See this:
import matplotlib.colors as mc
import matplotlib.pyplot as plt
plt.imshow(X, norm=mc.Normalize(vmin=0))
plt.colorbar(ticks=[0,2,4,6], format='%0.2f')
Many plotting functions including imshow, contourf, and others include a norm argument that takes a Normalize object. You can set the vmin or vmax attributes of that object to adjust the corresponding values of the colorbar.
colorbar takes the ticks and format arguments to adjust which ticks to display and how to display them.