Overlaying a scatter plot on background image and changing axes ranges - python

I have a set of x,y map coordinates that I want plotted on an background image of the map.
I use the following code to display my map:
import matplotlib.pyplot as plt
im=plt.imread('map.gif')
implot=plt.imshow(im,origin='lower')
Now the ranges for the x and y axes are the pixel values of the image. In my case, these are:
im.shape[0]
545
im.shape[1]
1011
So the x-axis of the plot goes from 0 to 1011 and the y-axis from 0 to 545.
The map actually covers a range from -100 to +100 in the x-axis and -50 to 50 in the y-axis and my x,y coordinate values are on the same system.
How can I get the x-axis of the plot going from -100 to +100 and not 0 to 1011? and then overplot my x,y scatter plot.

The following code, from the matplotlib site, shows a plot that goes from -3 to 3, check it out:
#!/usr/bin/env python
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
delta = 0.025
x = y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = Z2-Z1 # difference of Gaussians
im = plt.imshow(Z, interpolation='bilinear', cmap=cm.gray,
origin='lower', extent=[-3,3,-3,3])
plt.show()
The important part is the 'extent' argument of 'imshow'.

Related

weird 3d bar plot for given data using matplotlib

I am trying to 3d plot below data, with height being the respecitive joint probability from probability mass function. The idea is to visualize covariance. I had to go 3D because, the probabilities varies for different combinations of sample. The bars or boxes overlap each other in weird ways that I am unable to infer a proper 3d perspective in different angles. If you look at below gif you will know (box suddenly grows over each other at few angles out of nowhere). Kindly help how to resolve this issue. Also alpha is not working.
Issues:
1. Weird 3d boxes rendering
2. Alpha also not working
Problematic output:
MWE (jupyter):
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from itertools import product
from mpl_toolkits.mplot3d import Axes3D
X , Y = [100,250], [0,100,200]
xb, yb = 175, 125
import pandas as pd
matrix = np.array([
[0.20, 0.10, 0.20],
[0.05, 0.15, 0.30]
])
df = pd.DataFrame(matrix, columns=Y)
df.index = [100, 250]
top = 1
fig = plt.figure(figsize=(15,5))
ax1 = fig.add_subplot(121)
for xy in product(X,Y):
x,y = xy[0], xy[1]
z = df.loc[x,y]
d1, d2 = xb - x, yb - y
color = 'green' if d1*d2 > 0 else 'red'
ax1.add_patch(patches.Rectangle((x, y), d1, d2, alpha=z, facecolor=color))
ax1.scatter(x,y,color='black')
ax1.axvline(x=Xb, ls=':', color='blue')
ax1.axhline(y=Yb, ls=':', color='blue')
ax1.set_xticks(X)
ax1.set_yticks(Y)
ax1.set_xlim([min(X)-50,max(X)+50])
ax1.set_ylim([min(Y)-50,max(Y)+50])
ax2 = fig.add_subplot(122, projection='3d')
ax2.view_init(elev=30., azim=-50)
for xy in product(X,Y):
x ,y = xy[0], xy[1]
z = df.loc[x,y]
# print(x, y, z)
width = x - 175
depth = y - 125
pro = width*depth
top = z
bottom = np.zeros_like(top)
if pro > 0: #positive
color='#B9F6CA'
else:
color='#EF9A9A'
ax2.bar3d(x, y, bottom, -width, -depth, top, color=color)
ax2.scatter(x, y, z, color='blue')
def rotate(angle):
ax2.view_init(azim=angle)
from matplotlib import animation
ani = animation.FuncAnimation(fig, rotate, frames=np.arange(0,362,2),interval=100)
from IPython.display import HTML
plt.close()
HTML(ani.to_jshtml())
Related math problem:

Scatter plot coloring of data under the region of a function in Matplotlib

I need to plot bunch of points and also on the same graph plot a function cosx. The idea is to see the points that fall under the curve.
I have graph of cosx:
x = np.linspace(0, np.pi) #x range between 0 and pi
y = np.cos(x)
plt.plot(x, y)
plt.show()
Now I need to plot x = [2, 0.9, 2.6, 3.1] and y = [0.1, 0.4, 0.5, 0.2]
I can plot them as scatter plot but how would I combine both and preferably color code the points that fall under the curve?
You can seperate the scatter points into two lists, one for points under the line and one for points over the line. Then you can plot both lists.
Your data would be inserted instead of the random numbers in points_x and points_y
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, np.pi) #x range between 0 and pi
y = np.cos(x)
N = 100
points_x = np.random.rand(N)*np.pi
points_y = np.random.rand(N)*2.-1.
points_over = [(xi,yi) for xi,yi in zip(points_x,points_y) if np.cos(xi) < yi]
points_under = [(xi,yi) for xi,yi in zip(points_x,points_y) if np.cos(xi) >= yi]
plt.plot(x, y)
plt.scatter(*zip(*points_over),c='g')
plt.scatter(*zip(*points_under),c='r')
plt.show()
Producing something like:

Align and share X axis in Matplotlib contour 2D and 1D plot with colourbar legend [duplicate]

This question already has answers here:
How to have one colorbar for all subplots
(13 answers)
Closed 4 years ago.
I am trying to include a 1D path through a 2D contour plot as a separate plot below the contour plot. Ideally these will have a shared and aligned X axis to guide the reader through the features of the plot, and will include a colour bar legend.
I have made this minimal example to show my attempt and the problem.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
# Generating dummy data
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z = np.outer(np.cos(y), np.cos(3*x))
# Configure the plot
gs = gridspec.GridSpec(2,1,height_ratios=[4,1])
fig = plt.figure()
cax = fig.add_subplot(gs[0])
# Contour plot
CS = cax.contourf(X, Y, Z)
# Add line illustrating 1D path
cax.plot([-3,3],[0,0],ls="--",c='k')
cbar = fig.colorbar(CS)
# Simple linear plot
lax = fig.add_subplot(gs[1],sharex=cax)
lax.plot(x, np.cos(3*x))
lax.set_xlim([-3,3])
plt.show()
This gives the following image as a result:
Clearly the colour bar being included in the subplot area is throwing off the align.
I the process of writing this question I found a work around by including the colour bar as it's own axis, such that the grid spec is now a 2x2 subplot grid.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z = np.outer(np.cos(y), np.cos(3*x))
# Gridspec is now 2x2 with sharp width ratios
gs = gridspec.GridSpec(2,2,height_ratios=[4,1],width_ratios=[20,1])
fig = plt.figure()
cax = fig.add_subplot(gs[0])
CS = cax.contourf(X, Y, Z)
cax.plot([-3,3],[0,0],ls="--",c='k')
lax = fig.add_subplot(gs[2],sharex=cax)
lax.plot(x, np.cos(3*x))
lax.set_xlim([-3,3])
# Make a subplot for the colour bar
bax = fig.add_subplot(gs[1])
# Use general colour bar with specific axis given.
cbar = plt.colorbar(CS,bax)
plt.show()
This gives the desired result.
I would still be interested if there are any more elegant solutions though.

change dash style of negative values in a default contour - matplotlib

I am trying to plot contours with matplotlib and I have negative values in the data and I want them to be dashed(which matplotlib does by default) however, I want to (1) control the dash style (on,off) and (2) change the color for the negative contours alone. I tried the answer in link: How can I set the dash length in a matplotlib contour plot
But this sets all the lines in the contour to dashes which I do not want. I need to hack the negative contour line styles alone!
A part of my code:
from pylab import *
import matplotlib
import numpy as np
matplotlib.rcParams['contour.negative_linestyle']= 'dashed'
CS = ax1.contour(xi, yi, W_t, levels=levels, colors='k', linewidths=0.05)
for c in CS.collections:
c.set_dashes([(0, (2.0, 2.0))])
You can loop though the line collections created by the CS object and for any non solid lines (from get_linetype with value [(None, None)]) set them however you want. As a minimal example,
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
#Dummy data
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10.0 * (Z2 - Z1)
CS = plt.contour(X, Y, Z, 20, colors='k')
for line in CS.collections:
if line.get_linestyle() == [(None, None)]:
print("Solid Line")
else:
line.set_linestyle([(0, (12.0, 3.0))])
line.set_color('red')
plt.show()

Getting pixel location for matplotlib contour plot

I have a contour plot application that I'd like to know the pixel location of the axes origin. I've read through the Transformation Tutorial, but it doesn't seem to be working properly.
Here's the code, adapted from the Contour Demo program:
#!/usr/bin/env python
"""
Illustrate simple contour plotting, contours on an image with
a colorbar for the contours, and labelled contours.
See also contour_image.py.
"""
import matplotlib
matplotlib.use('Agg')
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
# difference of Gaussians
Z = 10.0 * (Z2 - Z1)
# Create a simple contour plot with labels using default colors. The
# inline argument to clabel will control whether the labels are draw
# over the line segments of the contour, removing the lines beneath
# the label
plt.figure()
CS = plt.contour(X, Y, Z)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')
print "Origin:\t", plt.gca().transData.transform((-3.0, -2.0))
plt.savefig("cdemo.png")
The output is:
Origin: [ 80. 48.]
And the following image:
However, when I look at this with an editor that shows the cursor position in pixels (GIMP) it shows the origin location as (100,540). I understand that Matplotlib's origin is lower left, and GIMP counts from upper left, so adjusting for this with the image size of (800, 600) that gives me a translated location of (100,60).
Any ideas? Here's the image with the approximate location of (80, 48) marked in red at the lower left.
Using matplotlib 1.4.3
Thanks!
tcaswell nailed it - the problem was a mismatch in dpi between the figure object, and the saved image file. figure() defaults to 80 dpi, while savefig() defaults to 100 dpi
So you can fix it two ways...
Change the dpi of the figure() call to match the savefig() default:
plt.figure(dpi=100)
Or you can change the dpi of the savefig() call to match the figure() default:
plt.savefig("cdemo.png", dpi=80)

Categories

Resources