I'm trying to plot some Meteorological fields from a Grib2 file and I have a problem. How can I cross Antimeridian 180° in Matplotlib ? When I set the first lon = 160 and second lon = -40, Python returns me an error:
TypeError: Input z must be at least a (2, 2) shaped array, but has shape (101, 0)
Does anyone know how to solve that problem ? Thanks.
Related
I have:
1D vector containing hourly start times:
>> timez=np.arange(0, 84600, 3600)
>> timez.shape: (24,)
1D vector containing frequency values from 0.5 to 50Hz:
>> len(freqs): 70200
>> freqs.shape: (70200,)
2D array containing 24 rows corresponding to the 24 start times of 70200 amplitude values that correspond to the 70200 values of the frequency vector
>> data.shape: (24, 70200)
>> len(data): 24
>> len(data[0]: 70200
So, data[0] maps to timez[0], data[1] to timez[1], etc. and the frequency values in freqs map to the amplitude values in each data row.
I've tried:
fig, axes=plt.subplots(figsize=(16,9), nrows=2, ncols=1)
axes[1].pcolormesh(timez, freqs, data, shading='auto')
Gives error:
TypeError: Dimensions of C (24, 70200) are incompatible with X (24) and/or Y (70200); see help(pcolormesh)
I've reviewed:
pcolormesh tutorial
Which lead me to set shading='auto'
And, pcolormesh documentation
Which I'm confused by because it states that the data vector should be a 2D array, which it is.
Do I need to alter my data structures to fit into pcolormesh ? Am I thinking about this incorrectly?
I was trying to compute the value of a 600x400x100 tensor A divided by 600x400 matrix B along the 3rd axis. You can imagine a video clip of 100 frames, and each 600x400 frames is doing an element-wise division. My code is like:
A/B
And the error message says:
ValueError: operands could not be broadcast together with shapes (600,400,129) (600,400)
What's wrong with my codes?
Just add an empty axis to B, making it (600, 400, 1). Broadcasting will take over the rest.
A = np.random.rand(600, 400, 100)
B = np.random.rand(600, 400)
A / B[..., None]
So I think I might be absolutely on the wrong track here, but basically
I have a 3-d meshgrid, I find all of the distances to a testpoint at all of the points in that grid
import numpy as np
#crystal_lattice structure
x,y,z = np.linspace(-2,2,5),np.linspace(-2,2,5),np.linspace(-2,2,5)
xx,yy,zz = np.meshgrid(x,y,z)
#testpoint
point = np.array([1,1,1])
d = np.sqrt((point[0]-xx)**2 + (point[1]-yy)**2 + (point[2]-zz)**2)
#np.shape(d) = (5, 5, 5)
Then I am trying to find the coordinates of he gridpoint that is the closest to that test point.
My idea was to sort d (flatten then search), get the index of the lowest value.
low_to_hi_d = np.sort(d, axis=None) # axis=0 flattens the d, going to flatten the entire d array and then search
lowest_val = low_to_hi_d[0]
index = np.where(d == lowest_val)
#how do I get the spatial coordinates of my index, not just the position in ndarray (here the position in ndarray is (3,3,3) but the spatial position is (1,1,1), but if I do d[3,3,3] I get 0 (the value at spatial position (1,1,1))
Use that index on my 3d grid to find the point coordinates (not the d value at that point). I am trying something like this, and I am pretty sure I am overcomplicating it. How can I get the (x,y,z) of the 3-d gridpoint that is closest to my test point?
If you just want to find the coordinates of the closest point you are right, you're on the wrong track. There is no point in generating a meshgrid and calculate the distance on so many duplicates. You can do it in every dimension easily and independently:
import numpy as np
x,y,z = np.linspace(-2,2,5),np.linspace(-2,2,5),np.linspace(-2,2,5)
p=np.array([1,1,1])
closest=lambda x,p: x[np.argmin(np.abs(x-p))]
xc,yc,zc=closest(x,p[0]),closest(y,p[1]),closest(z,p[2])
I'm not completely sure that this is what you want.
You can find the index of the minimum d with:
idx = np.unravel_index(np.argmin(d), d.shape)
(3, 3, 3)
and use this to index your meshgrid:
xx[idx], yy[idx], zz[idx]
(1.0, 1.0, 1.0)
The planned annotation box does not appear on my plot, however, I've tried a wide range of values for its coordinates.
What's wrong with that?!
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def f(s,t):
a = 0.7
b = 0.8
Iext= 0.5
tau = 12.5
v = s[0]
w = s[1]
dndt = v - np.power(v,3)/3 - w + Iext
dwdt = (v + a - b * w)/tau
return [dndt, dwdt]
t = np.linspace(0,200)
s0=[1,1]
s = odeint(f,s0,t)
plt.plot(t,s[:,0],'b-', linewidth=1.0)
plt.xlabel(r"$t(sec.)$")
plt.ylabel(r"$V (volt)$")
plt.legend([r"$V$"])
annotation_string = r"$I_{ext}=0.5$"
plt.text(15, 60, annotation_string, bbox=dict(facecolor='red', alpha=0.5))
plt.show()
The coordinates to plt.text are data coordinates by default. This means in order to be present in the plot they should not exceed the data limits of your plot (here, ~0..200 in x direction, ~-2..2 in y direction).
Something like plt.text(10,1.8) should work.
The problem with that is that once the data limits change (because you plot something different or add another plot) the text item will be at a different position inside the canvas.
If this is undesired, you can specify the text in axes coordinates (ranging from 0 to 1 in both directions). In order to place the text always in the top left corner of the axes, independent on what you plot there, you can use e.g.
plt.text(0.03,0.97, annotation_string, bbox=dict(facecolor='red', alpha=0.5),
transform=plt.gca().transAxes, va = "top", ha="left")
Here the transform keyword tells the text to use Axes coordinates, and va = "top", ha="left" means, that the top left corner of the text should be the anchor point.
The annotation is appearing far above your plot because you have given a 'y' coordinate of 60, whereas your plot ends at '2' (upwards).
Change the second argument here:
plt.text(15, 60, annotation_string, bbox=dict(facecolor='red', alpha=0.5))
It needs to be <=2 to show up on the plot itself. You may also want to change the x coorinate (from 15 to something less), so that it doesn't obscure your lines.
e.g.
plt.text(5, 1.5, annotation_string, bbox=dict(facecolor='red', alpha=0.5))
Don't be alarmed by my (5,1.5) suggestion, I would then add the following line to the top of your script (beneath your imports):
rcParams['legend.loc'] = 'best'
This will choose a 'best fit' for your legend; in this case, top left (just above your annotation). Both look quite neat then, your choice though :)
I'm looking to create a chart much like nltk's lexical dispersion plot, but am drawing a blank how to construct this. I was thinking that scatter would be my best geom, using '|' as markers, and setting the alpha, but I am running into all sorts of issues setting the parameters. An example of this is below:
I have the dataframe arranged with a datetime index, freq='D', over a 5 year period, and each column represents the count of a particular word used that date.
For example:
tst = pd.DataFrame(index=pd.date_range(datetime.datetime(2010, 1, 1), end=datetime.datetime(2010, 2, 1), freq='D'), data=[[randint(0, 5), randint(0, 1), randint(0, 2)] for x in range(32)])
Currently I'm trying something akin to the following:
plt.figure()
tst.plot(kind='scatter', x=tst.index, y=tst.columns, marker='|', color=sns.xkcd_rgb['dodger blue'], alpha=.05, legend=False)
yticks = plt.yticks()[0]
plt.yticks(yticks, top_words)
the above code yields a KeyError:
KeyError: "['2009-12-31T19:00:00.000000000-0500' '2010-01-01T19:00:00.000000000-0500'\n '2010-01-02T19:00:00.000000000-0500' '2010-01-03T19:00:00.000000000-0500'\n '2010-01-04T19:00:00.000000000-0500' '2010-01-05T19:00:00.000000000-0500'\n '2010-01-06T19:00:00.000000000-0500' '2010-01-07T19:00:00.000000000-0500'\n '2010-01-08T19:00:00.000000000-0500' '2010-01-09T19:00:00.000000000-0500'\n '2010-01-10T19:00:00.000000000-0500' '2010-01-11T19:00:00.000000000-0500'\n '2010-01-12T19:00:00.000000000-0500' '2010-01-13T19:00:00.000000000-0500'\n '2010-01-14T19:00:00.000000000-0500' '2010-01-15T19:00:00.000000000-0500'\n '2010-01-16T19:00:00.000000000-0500' '2010-01-17T19:00:00.000000000-0500'\n '2010-01-18T19:00:00.000000000-0500' '2010-01-19T19:00:00.000000000-0500'\n '2010-01-20T19:00:00.000000000-0500' '2010-01-21T19:00:00.000000000-0500'\n '2010-01-22T19:00:00.000000000-0500' '2010-01-23T19:00:00.000000000-0500'\n '2010-01-24T19:00:00.000000000-0500' '2010-01-25T19:00:00.000000000-0500'\n '2010-01-26T19:00:00.000000000-0500' '2010-01-27T19:00:00.000000000-0500'\n '2010-01-28T19:00:00.000000000-0500' '2010-01-29T19:00:00.000000000-0500'\n '2010-01-30T19:00:00.000000000-0500' '2010-01-31T19:00:00.000000000-0500'] not in index"
Any help would be appreciated.
With help, I was able to produce the following:
plt.plot(tst.index, tst, marker='|', color=sns.xkcd_rgb['dodger blue'], alpha=.25, ms=.5, lw=.5)
plt.ylim([-1, 20])
plt.yticks(range(20), top_words)
Unfortunately, it only appears that the upper bars will show up when there is a corresponding bar to be built on top of. That's not how my data looks.
I am not sure you can do this with .plot method. However, it is easy to do it straightly in matplotlib:
plt.plot(tst.index, tst, marker='|', lw=0, ms=10)
plt.ylim([-0.5, 5.5])
If you can install seaborn, try stripplot():
import seaborn as sns
sns.stripplot(data=tst, orient='h', marker='|', edgecolor='blue');
Note that I changed your data to make it look a bit more interesting:
tst = pd.DataFrame(index=pd.date_range(datetime.datetime(2010, 1, 1), end=datetime.datetime(2010, 2, 1), freq='D'),
data=(150000 * np.random.rand(32, 3)).astype('int'))
More information on seaborn:
http://stanford.edu/~mwaskom/software/seaborn/tutorial/categorical.html