I am trying to plot a heatmap on top of an image.
What I did:
import matplotlib.pyplot as plt
import numpy as np
import numpy.random
import urllib
#downloading an example image
urllib.urlretrieve("http://tekeye.biz/wp-content/uploads/2013/01/small_playing_cards.png", "/tmp/cards.png")
#reading and plotting the image
im = plt.imread('/tmp/cards.png')
implot = plt.imshow(im)
#generating random data for the histogram
x=numpy.random.normal(500, 100, size=1000)
y=numpy.random.normal(100, 50, size=1000)
heatmap, xedges, yedges = np.histogram2d(x, y, bins=50)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
plt.imshow(heatmap, extent=extent,alpha=.5)
plt.show()
When I plot them together, the image get's rotated, up-side down as in:
Does anyone have a solution for having the old picture back?
you need to set the origin of both the imshow instances. But, you also need to change the yedges around in your extent
implot = plt.imshow(im,origin='upper')
...
extent = [xedges[0], xedges[-1], yedges[-1], yedges[0]]
plt.imshow(heatmap, extent=extent,alpha=.5,origin='upper')
Related
I'm trying to plot an image with a Sinusoidal projection using imshow but if I use the transform=ccrs.Sinusoidal(central_longitude=128) it's not working at all and using the transform=ccrs.PlateCarree() the coastlines and image are not aligned. This is my code:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy as np
plt.figure(figsize=(8, 8))
ax = plt.axes(projection=ccrs.PlateCarree())
img_extent = (122.8109, 133.2922, 32.8286, 43.1708)
img = plt.imread('Korea.A2004004.0445.250m.jpg')
ax.coastlines(resolution='10m')
ax.imshow(img, origin='upper', extent=img_extent, transform=ccrs.PlateCarree())
plt.show()
Image is from: https://eoimages.gsfc.nasa.gov/images/imagerecords/69000/69679/Korea.A2004004.0445.250m.jpg
I have a heatmap plotted above an image (as shown on image link 1), with gaussian filter and normalize data. The main issue is that there is no value under 92 on the y axis, so the plot doesnt start on (0,0), instead start on (0,92). So, when I put together both pictures (heatmap and background image), there is an abrupt cut on the graph (as shown on 2nd link, where is the heatmap without background).
So, how can I extend the axis on the heatmap so it start on (0,0)?
Below is the code that I'm currently using to plot both images. Thanks!
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from scipy.ndimage.filters import gaussian_filter
import matplotlib.colors as mcolors
from sklearn.preprocessing import normalize
x = df['x_data']
y = df['y_data']
heatmap, xedges, yedges = np.histogram2d(x, y, bins = [800,600])
extent = [0, xedges[-1], yedges[0], yedges[-1]]
heatmap = normalize(heatmap)
heatmap = gaussian_filter(heatmap, 16)
colors = [(1,1-c,0,c) for c in np.linspace(0,1,100)]
cmapred = mcolors.LinearSegmentedColormap.from_list('mycmap', colors, N=5)
map_img = mpimg.imread('dir/to/background/image.png')
fig, ax = plt.subplots(figsize=(16.1, 9.1))
plt.imshow(map_img, extent=[0, 800, 0, 600], cmap = 'Greys_r')
plt.imshow(heatmap.T, extent = extent, origin = 'lower', cmap = cmapred, alpha = 0.7)
plt.ylim([0,600])
plt.xlim([0,800])
plt.show()
Image of heatmap + background: https://imgur.com/2vX6Bw6
Image of only heatmap: https://imgur.com/axMe7K7
You could add rows to your heat map manually. Maybe easier is to try setting the histogram bins explicitly?
bins=[np.arange(0, 800, 1), np.arange(0, 600, 1)]
heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
I am trying to explore a subplot 2 plots with square in shape rotated by 45 degree.
import matplotlib.pyplot as plt
from matplotlib import colors
import numpy as np
data = np.random.rand(10, 10) * 20
# create discrete colormap
cmap = colors.ListedColormap(['red', 'blue','green'])
bounds = [0,5,10,15]
norm = colors.BoundaryNorm(bounds, cmap.N)
fig, ax= plt.subplots(1,2)
ax[0].imshow(data, cmap=cmap, norm=norm)
# draw gridlines
ax[0].grid(which='major', axis='both', linestyle='-', color='k', linewidth=0)
ax[0].set_xticks(np.arange(-.5, 10, 1));
ax[0].set_yticks(np.arange(-.5, 10, 1));
ax[1].imshow(data, cmap=cmap, norm=norm)
# draw gridlines
ax[1].grid(which='major', axis='both', linestyle='-', color='k', linewidth=0)
ax[1].set_xticks(np.arange(-.5, 10, 1));
ax[1].set_yticks(np.arange(-.5, 10, 1));
plt.show()
Actual Result is :-
I want to rotate individual plot by 45 degree. Something like:-
I am trying to find in Matplotlib Documentation. Still not getting. Any help?
Please note this is NOT DUPLICATE OF
Is there a way to rotate a matplotlib plot by 45 degrees?
The mentioned URL is for a plot. and the solution is to rotate IMAGE. However this is pertaining to Subplot. I want to rotate PLOT not image as whole.
Based on this link and documentation about floating_axes, you can try something like this:
from mpl_toolkits.axisartist.grid_finder import DictFormatter
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
import mpl_toolkits.axisartist.floating_axes as floating_axes
from matplotlib import colors
import numpy as np
def setup_axes1(fig, rect, angle):
tr = Affine2D().scale(2, 2).rotate_deg(angle)
#We create dictionarys to keep the xticks and yticks after the rotation
dictio={i:str(val) for i,val in enumerate(np.arange(-.5, 10, 1).tolist())}
reversedictio={i:dictio[val] for i,val in enumerate(list(reversed(sorted(dictio.keys()))))}
grid_helper = floating_axes.GridHelperCurveLinear(
tr, extremes=(-0.5, 9.5,-0.5, 9.5), tick_formatter1= DictFormatter(dictio),
tick_formatter2=DictFormatter(reversedictio))
ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)
fig.add_subplot(ax1)
aux_ax = ax1.get_aux_axes(tr)
grid_helper.grid_finder.grid_locator1._nbins = 10 #Number of rows
grid_helper.grid_finder.grid_locator2._nbins = 10 #Number of columns
return aux_ax
fig1, axes=plt.subplots(2,figsize=(20,20))
plt.rcParams.update({'font.size': 27})
#We erase the first previous axes
fig1.delaxes(axes[0])
fig1.delaxes(axes[1])
data = np.random.rand(10, 10) * 20
#We create the floating_axes
ax0 = setup_axes1(fig1, 121,-45)
ax1 = setup_axes1(fig1, 122,-45)
# create discrete colormap
cmap = colors.ListedColormap(['red', 'blue','green'])
bounds = [0,5,10,15]
norm = colors.BoundaryNorm(bounds, cmap.N)
ax0.imshow(data, cmap=cmap, norm=norm,interpolation="nearest")
# draw gridlines
ax0.grid(which='major', axis='both', linestyle='-', color='k', linewidth=0)
ax1.imshow(data, cmap=cmap, norm=norm,interpolation="nearest")
# draw gridlines
ax1.grid(which='major', axis='both', linestyle='-', color='k', linewidth=0)
plt.show()
Output:
Or, as an other alternative, I found a "tricky" way to do it, and it's about catching the figures in the buffer, rotate them -45 degrees, and then merge them into a single image, and since you have the same two images, you can try something like this:
import matplotlib
import io
from PIL import Image
import matplotlib.pyplot as plt
from matplotlib import colors
import numpy as np
##PLOTING THE FIGURE##
data = np.random.rand(10, 10) * 20
# create discrete colormap
cmap = colors.ListedColormap(['red', 'blue','green'])
bounds = [0,5,10,15]
norm = colors.BoundaryNorm(bounds, cmap.N)
#We change style values to get the image with better quality
plt.rcParams.update({'font.size': 46})
plt.figure(figsize=(20,20))
plt.imshow(data, cmap=cmap, norm=norm)
# draw gridlines
plt.grid(which='major', axis='both', linestyle='-', color='k', linewidth=0)
plt.gca().set_xticks(np.arange(-.5, 10, 1));
plt.gca().set_yticks(np.arange(-.5, 10, 1));
##SAVING THE FIGURE INTO AN IMAGE##
#We save the current figure as a Image
buf = io.BytesIO()
plt.savefig(buf, format='png',bbox_inches='tight')
buf.seek(0)
im = Image.open(buf) #We open the current image saved in the buffer
#We rotate the image and fill the background with white
img_01=im.rotate(-45, Image.NEAREST, expand = 1, fillcolor = (255,255,255))
buf.close()
##MERGING THE TWO FIGURES##
new_im = Image.new('RGB', (2*img_01.size[0]+20,img_01.size[1]), 'white')
mouse_mask = img_01.convert('RGBA')
new_im.paste(img_01, (0,0))
new_im.paste(img_01, (img_01.size[0]+8,0))
new_im.save("merged_images.png", 'PNG') #Important(just to clarify): save the image, since the buffer is renewed every time you run the script
new_im.show()
Output:
I helped myself with these links:
How-to-merge-images-with-same-size-using-the-python-3-module-pillow
how-to-save-a-pylab-figure-into-in-memory-file-which-can-be-read-into-pil-image
python-pillow-rotate-image-90-180-270-degrees
specify-image-filling-color-when-rotating-in-python-with-pil-and-setting-expand
When plotting data using pcolormesh on a basemap projection (or a cartopy projection) I notice strange lines appear when I set the alpha value to less than 1.
Example code:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
plt.clf()
dpp =1 # degrees per pixel
lons = np.arange(-180,180+dpp,dpp)
lats = -1*np.arange(-90,90+dpp,dpp)
m = Basemap(projection='robin',lon_0=0)
data = np.random.random((np.size(lats), np.size(lons)))
lons, lats = np.meshgrid(lons, lats)
x, y = m(lons, lats)
im = m.pcolormesh(x, y, x, latlon=False, cmap='RdBu')
#im = m.pcolormesh(lons, lats, data, latlon=True, cmap='RdBu')
m.colorbar(im)
plt.show()
The output shows strange lines appearing:
If I instead set alpha=1 the lines disappear and the behavior is as expected:
Any ideas on how to get pcolormesh to work with a nonzero alpha value?
Use pcolor instead of pcolormesh, it is a bit slower but it does a better job with handling rasterized output. Be sure to set snap = True, this will align the grid to the pixels.
Example
import numpy as np
import matplotlib.pyplot as plt
lons, lats = np.meshgrid(np.arange(-180,180), np.arange(90,-90,-1))
im = plt.pcolor(lons, lats, lons, cmap='RdBu', alpha=0.5, snap=True)
cbar = plt.colorbar(im)
cbar.set_alpha(0.5)
plt.show()
This should work with mpl_toolkits.basemap as well.
The lines in the colorbar are caused by the open issue #1188, as far as I know there is not a work around known which does not involve manually creating the colorbar.
Since it is a global map, I got it to work using imshow instead of pcolor or pcolormesh:
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
plt.clf()
lons, lats = np.meshgrid(np.arange(-180,180), np.arange(90,-90,-1))
im = ax.imshow(lons, transform=ccrs.PlateCarree(),cmap='RdBu', alpha=0.5, extent=[-180,180,-90,90])
cbar = plt.colorbar(im)
cbar.set_alpha(0.5)
plt.show()
There is still the issue with the colorbar however.
I have need to plot point on the map, produce PNG image on that map and, output display coordinated of the plotted point.
Using cartopy I could get the map I wanted and plot a point in given lon/lat coordinates.
I cannot figure out how to get the pixel coordinates out. I tried to follow simple matplotlib tutorial https://matplotlib.org/users/transforms_tutorial.html But it does not work as expected in this situation
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
# Create Mercator projection with dateline in the middle:
from matplotlib import lines
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection=ccrs.Mercator(central_longitude=26,))
ax.set_extent([19, 33, 59.5, 70.5], crs=ccrs.PlateCarree())
LAND = cfeature.NaturalEarthFeature('physical', 'land', '50m',
edgecolor='face',
facecolor=cfeature.COLORS['land'], zorder=-1)
ax.add_feature(LAND)
ax.coastlines(resolution='50m')
ax.add_feature(cfeature.NaturalEarthFeature('cultural', 'admin_0_boundary_lines_land',
'50m', edgecolor='black', facecolor='none'))
plt.plot([26.7042], [60.8679], color='blue', linewidth=2, marker='o',
transform=ccrs.PlateCarree(),
)
fig.canvas.draw()
# print image x y coordinates of point 60.8679° N, 26.7042° E here
plt.show()