I am trying to plot some precipitation data. The code I'm using is modified slightly from this code here.
The code works fine when I plot using the data from the site used in the link, but when I use a different dataset I have, it doesn't plot. The biggest difference between this dataset and the dataset used in the link's example, is my dataset is global data. The dataset I am using is also netcdf, is not masked, and I am loading it the same way as the example.
I am familiar with the data and know for a fact I should be seeing something and the contour values used in the example are reasonable for this other set of data I am using.
My code is the same, expect for some changes in the section that plots the figure (below) which I have modified so it will plot a specific area instead of CONUS like in the example (using ax.set_extent).
When I do not set the extent it appears to plot the data, but then none of the boundaries (coastlines, state lines, etc.) do not plot. Based on this, I'm guessing it's something with either the dataset itself, something with set_extent, or a combination of things that is causing it to go wrong. I am not getting back any kind of errors when I plot it, either way. However, there might be something else I'm missing with it.
In the end, I'm actually comparing my dataset to the dataset used in the example link, so I would like them in the same projection.
Thanks for any insight and let me know if you need more information about the data itself!
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1, projection=proj)
ax.set_extent((x1,x0,y0,y1))
# draw coastlines, state and country boundaries, edge of map.
ax.coastlines()
ax.add_feature(cfeature.BORDERS)
ax.add_feature(cfeature.STATES)
cs1 = ax.contourf(ym, xm, data1, clevs, cmap=cmap, norm=norm)
# add colorbar.
cbar = plt.colorbar(cs1, orientation='horizontal')
#cbar.set_label(data1.units)
#ax.set_title(prcpvar.long_name + ' for period ending ' + nc.creation_time)
plt.show()
plt.savefig('ncep_model')
Results when extent is not included in code above:
Edit 1:
I'll add that I was able to successfully plot the data with this code below (from a default template I made). I tried to change the projection to stereographic, but I was having trouble getting it to plot correctly using basemap because I've never used it before. As an alternative, if you can't figure out the error with the code above and could instead help with changing the projection for the code below, I would also take that. At this point I just want my data to plot correctly in the correct projection I want!
(I also included the results for the code below to confirm that the data should be showing up in this location)
LLlat = 40.
LLlon = 263.
URlat = 44.
URlon = 270.
lat = xm
lon = ym
%matplotlib inline
plt.figure(1,figsize=(10, 8),)
plt.title('Convective Precipitation 8/28/2018 0Z (in) Valid July 2018')
map = Basemap(projection='cyl',\
llcrnrlat=LLlat,urcrnrlat=URlat,\
llcrnrlon=LLlon,urcrnrlon=URlon,\
rsphere=6371200.,resolution='i')
map.drawcoastlines(linewidth=0.5) # Draw some coastlines
map.drawstates(linewidth=0.5) # Draw some coastlines
map.drawrivers(color='#000000')
map.drawparallels(np.arange(-90.,91.,30),labels=[1,0,0,0]) # Drawing lines of latitude
map.drawmeridians(np.arange(0.,330.,60),labels=[0,0,0,1]) # Drawing lines of longitude
lons,lats = map(lon,lat) # Setting up the grid in cylindrical coords.
cs = plt.contourf(lons,lats,data1[:,:], clevs,cmap=cmap, norm=norm)
cb = plt.colorbar(cs,orientation='horizontal')
plt.show()
Edit 2:
I've added the resulting plot when I don't include the set_extent in the first chunk of code (Don't know if that will help at all, but thought I'd include it as well)
So it'd be really useful to have more information on your data, like a link to sample file, but my guess is that your data do not give coordinates in a stereographic projection, unlike the original data. When plotting with Cartopy, if you do not specify otherwise, all plot commands assume that the x,y values given are in the projection specified for the axes (for the original code this was ccrs.Stereographic). If this is not the case, such as when plotting lon/lats, you need to specify this by passing transform to the plotting command, as below where I specify that the x,y values are lat/lons:
data_proj = ccrs.PlateCarree()
cs1 = ax.contourf(ym, xm, data1, clevs, cmap=cmap, norm=norm,
transform=data_proj)
Related
I am starting to play around with creating polar plots in Matplotlib that do NOT encompass an entire circle - i.e. a "wedge" plot - by setting the thetamin and thetamax properties. This is something I was waiting for for a long time, and I am glad they have it done :)
However, I have noticed that the figure location inside the axes seem to change in a strange manner when using this feature; depending on the wedge angular aperture, it can be difficult to fine tune the figure so it looks nice.
Here's an example:
import numpy as np
import matplotlib.pyplot as plt
# get 4 polar axes in a row
fig, axes = plt.subplots(2, 2, subplot_kw={'projection': 'polar'},
figsize=(8, 8))
# set facecolor to better display the boundaries
# (as suggested by ImportanceOfBeingErnest)
fig.set_facecolor('paleturquoise')
for i, theta_max in enumerate([2*np.pi, np.pi, 2*np.pi/3, np.pi/3]):
# define theta vector with varying end point and some data to plot
theta = np.linspace(0, theta_max, 181)
data = (1/6)*np.abs(np.sin(3*theta)/np.sin(theta/2))
# set 'thetamin' and 'thetamax' according to data
axes[i//2, i%2].set_thetamin(0)
axes[i//2, i%2].set_thetamax(theta_max*180/np.pi)
# actually plot the data, fine tune radius limits and add labels
axes[i//2, i%2].plot(theta, data)
axes[i//2, i%2].set_ylim([0, 1])
axes[i//2, i%2].set_xlabel('Magnitude', fontsize=15)
axes[i//2, i%2].set_ylabel('Angles', fontsize=15)
fig.set_tight_layout(True)
#fig.savefig('fig.png', facecolor='skyblue')
The labels are in awkward locations and over the tick labels, but can be moved closer or further away from the axes by adding an extra labelpad parameter to set_xlabel, set_ylabel commands, so it's not a big issue.
Unfortunately, I have the impression that the plot is adjusted to fit inside the existing axes dimensions, which in turn lead to a very awkward white space above and below the half circle plot (which of course is the one I need to use).
It sounds like something that should be reasonably easy to get rid of - I mean, the wedge plots are doing it automatically - but I can't seem to figure it out how to do it for the half circle. Can anyone shed a light on this?
EDIT: Apologies, my question was not very clear; I want to create a half circle polar plot, but it seems that using set_thetamin() you end up with large amounts of white space around the image (especially above and below) which I would rather have removed, if possible.
It's the kind of stuff that normally tight_layout() takes care of, but it doesn't seem to be doing the trick here. I tried manually changing the figure window size after plotting, but the white space simply scales with the changes. Below is a minimum working example; I can get the xlabel closer to the image if I want to, but saved image file still contains tons of white space around it.
Does anyone knows how to remove this white space?
import numpy as np
import matplotlib.pyplot as plt
# get a half circle polar plot
fig1, ax1 = plt.subplots(1, 1, subplot_kw={'projection': 'polar'})
# set facecolor to better display the boundaries
# (as suggested by ImportanceOfBeingErnest)
fig1.set_facecolor('skyblue')
theta_min = 0
theta_max = np.pi
theta = np.linspace(theta_min, theta_max, 181)
data = (1/6)*np.abs(np.sin(3*theta)/np.sin(theta/2))
# set 'thetamin' and 'thetamax' according to data
ax1.set_thetamin(0)
ax1.set_thetamax(theta_max*180/np.pi)
# actually plot the data, fine tune radius limits and add labels
ax1.plot(theta, data)
ax1.set_ylim([0, 1])
ax1.set_xlabel('Magnitude', fontsize=15)
ax1.set_ylabel('Angles', fontsize=15)
fig1.set_tight_layout(True)
#fig1.savefig('fig1.png', facecolor='skyblue')
EDIT 2: Added background color to figures to better show the boundaries, as suggested in ImportanteOfBeingErnest's answer.
It seems the wedge of the "truncated" polar axes is placed such that it sits in the middle of the original axes. There seems so be some constructs called LockedBBox and _WedgeBbox in the game, which I have never seen before and do not fully understand. Those seem to be created at draw time, such that manipulating them from the outside seems somewhere between hard and impossible.
One hack can be to manipulate the original axes such that the resulting wedge turns up at the desired position. This is not really deterministic, but rather looking for some good values by trial and error.
The parameters to adjust in this case are the figure size (figsize), the padding of the labels (labelpad, as already pointed out in the question) and finally the axes' position (ax.set_position([left, bottom, width, height])).
The result could then look like
import numpy as np
import matplotlib.pyplot as plt
# get a half circle polar plot
fig1, ax1 = plt.subplots(1, 1, figsize=(6,3.4), subplot_kw={'projection': 'polar'})
theta_min = 1.e-9
theta_max = np.pi
theta = np.linspace(theta_min, theta_max, 181)
data = (1/6.)*np.abs(np.sin(3*theta)/np.sin(theta/2.))
# set 'thetamin' and 'thetamax' according to data
ax1.set_thetamin(0)
ax1.set_thetamax(theta_max*180./np.pi)
# actually plot the data, fine tune radius limits and add labels
ax1.plot(theta, data)
ax1.set_ylim([0, 1])
ax1.set_xlabel('Magnitude', fontsize=15, labelpad=-60)
ax1.set_ylabel('Angles', fontsize=15)
ax1.set_position( [0.1, -0.45, 0.8, 2])
plt.show()
Here I've set some color to the background of the figure to better see the boundary.
I have a compiled data frame of sp500 stock data that I am trying to find correlations with using df.corr(), but it is labeling all data as having a '1' correlation when I run the program, and when I use a heat map to visualize the data it shows an entire green chart, when there should be many many different positive and negative correlations.
Using Python 3.6 and Spyder
here is the code I am using:
def visualize_data():
df = pd.read_csv('sp500_joined_closes.csv')
pd.options.display.float_format = '{:.5f}'.format
#df['AAPL'].plot()
#plt.show()
df_corr = df.corr() #creates a correlation table of our data frame. Generates correlation values
print(df_corr.head())
data1 = df_corr.values #gets inner values of our data frame
fig1 = plt.figure() #specify our figures
ax1 = fig1.add_subplot(1,1,1) #defined axis 1 by 1 plot 1
heatmap1 = ax1.pcolor(data1, cmap=plt.cm.RdYlGn) #sets the color paramater of heat map (negative,neutral,positive)
fig1.colorbar(heatmap1)
ax1.set_xticks(np.arange(data1.shape[0]) + 0.5, minor=False) #sets x ticks for heat map, arranging ticks at every 0.5(half-mark)
ax1.set_yticks(np.arange(data1.shape[1]) + 0.5, minor=False) #sets y ticks for heat map
ax1.invert_yaxis() #removes random gap from the top of graph
ax1.xaxis.tick_top() #moves x axis ticks to the top (meant to look more like a table)
column_labels = df_corr.columns
row_labels = df_corr.index
ax1.set_xticklabels(column_labels)
ax1.set_yticklabels(row_labels)
plt.xticks(rotation=90)
heatmap1.set_clim(-1,1)
plt.tight_layout()
#plt.savefig("correlations.png", dpi = (300))
plt.show()
visualize_data()
The interesting thing is that I searched all over for anyone having a similar error, and I cannot seem to find any answers. Could it be that the ticker symbols could be considered categorical and therefore something is getting skewed? I'm not quite sure here, to be honest.
Even when I tried to plot the correlations for one single company against all the data as seen by #df['AAPL'].plot() and #plt.show() the same exact thing happened where the data is only registering a correlation value of 1.0000 to all of the data.
I initially thought it was a rounding error due to significant figures, so I put in pd.options.display.float_format = '{:.5f}'.format but that didn't work and i still am receiving the skewed correlation.
Here is a screenshot of the issue and the subsequent heat map
Here is a screenshot of part of the data, confirming that it isn't all the same or that is has become corrupted in some measure
The issue was with sourcing the data through the google finance api. There seemed to have been an error downloading one of the dates to one of the sp500 companies and when I compiled all of the data including those few missing dates it could only produce one line of data for some reason. This lead to a correlation of '1' since all the data was exactly the same. I found the specific dates and added them in manually and now the program runs as it should. Thank you.
I am plotting my data into a contour map. The computations work on the translated values, so I need to put it back to its original value. On the fourth line of the code, is the re-translation process.
However, when I plotted it the colorbar shows the relative values, and just a note of the shift value at the top of the color bar. It is just weird that I checked the matrix values, and it contains the original values.
How can I show the colorbar, with the original values displayed?
fig=plt.figure()
v=np.linspace(-180,180,25)
x,y = np.meshgrid(v,v)
z = np.add(z,-shift)
z = z.reshape(25,25).T
plt.contourf(x,y,z,25)
fig.suptitle(AA(prefix)+' Input Data Contour Map')
plt.xlabel('$\phi$ (deg)')
plt.ylabel('$\psi$ (deg)')
plt.xticks(np.arange(-180, 181, 30))
plt.yticks(np.arange(-180, 181, 30))
plt.colorbar()
UPDATE: I used set_ticklabels() for a temporary fix, where labels is a list of custom labels.
But I am still looking for a better way to solve this problem.
plt.colorbar().set_ticklabels(labels)
updated contour map
Matplotlib doesn't know about your shift variable. It is choosing to plot it that way because the changes you are trying to visualize are 10^(-6) of the background value.
You can force the colorbar to have tick marks at specific locations as they do in this pylab example using:
cbar = fig.colorbar(cax, ticks=[-1, 0, 1])
cbar.ax.set_yticklabels(['< -1', '0', '> 1']) # vertically oriented colorbar
However, doing so will make the scale very difficult to read.
I have the code below:
fig, ax = pyplot.subplots()
graph = ax.pcolorfast(data, cmap='viridis', vmin = min, vmax = max)
pyplot.colorbar(graph)
pyplot.show()
and it plots what I wanted, however it is sideways. Is there a good way of rotating it -90 or 270 degrees? I have tried a.T, which returns the original plot. I have also tried ndimage.rotate(graph, -90|270), ndimage.interpolation.rotate(graph, -90|270), and numpy.rot90(data,3). The first two return errors for invalid rotation planes and the second appears to shove the graph off the edge, losing a majority of my data points.
If anyone has some thoughts, I would be very grateful. Even if it's that I put in the wrong arguments. I am at a loss here.
Is a supposed to be equal to data in your example? Tried your code with a random 2D array, and np.transpose(a) as well as a.T seem to properly rotate the figure, as opposed to what you indicate here ('returns the original plot'). If this is not the case for you, I think we need more information.
I'm using matplotlib to plot 5 sets of approx. 400,000 data points each. Although each set of points is plotted in a different color, I need different markers for people reading the graph on black and white print-outs. The issue I'm facing is that almost all of the possible markers available in the documentation at http://matplotlib.org/api/markers_api.html take too much time to plot and render while displaying. I could only find two markers which plot and render quickly, these are '-' and '--'. Here's my code:
plt.plot(series1,'--',label='Label 1',lw=5)
plt.plot(series2,'-',label='Label 2',lw=5)
plt.plot(series3,'^',label='Label 3',lw=5)
plt.plot(series4,'*',label='Label 4',lw=5)
plt.plot(series5,'_',label='Label 5',lw=5)
I tried multiple markers. Series 1 and series 2 plot quickly and render in no time. But series 3, 4, and 5 take forever to plot and AGES to display.
I'm not able to figure out the reason behind this. Does someone know of more markers that plot and render quickly?
The first two ('--' and '-') are linestyles not markers. Thats why they are rendered faster.
It doesn't make sense to plot ~400,000 markers. You wont be able to see all of them... However, what you could do is to only plot a subset of the points.
So add the line with all your data (even though you could probably also subsample that too) and then add a second "line" with only the markers.
for that you need an "x" vectors, which you can subsample too:
# define the number of markers you want
nrmarkers = 100
# define a x-vector
x = np.arange(len(series3))
# calculate the subsampling step size
subsample = int(len(series3) / nrmarkers)
# plot the line
plt.plot(x, series3, color='g', label='Label 3', lw=5)
# plot the markers (using every `subsample`-th data point)
plt.plot(x[::subsample], series3[::subsample], color='g',
lw=5, linestyle='', marker='*')
# similar procedure for series4 and series5
Note: The code is written from scratch and not tested