How to plot a graph with logscale over a background image? - python

I want to plot a curve over a background image with the x and y axis in logscale. However, when I try to do so, the image is stretched by the logscale. I obtain this figure
This is the code I wrote.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(low=0, high=10**6, size=(100,))
y = np.random.uniform(low=10**(-14), high=10**(-10), size=(100,))
x.sort()
y.sort()
xm = len(x)
ym = len(y)
img = plt.imread("quiverplot.png")
fig, ax2 = plt.subplots()
plt.plot(x, y)
ax2.set_xscale('log')
ax2.set_yscale('log')
ax1 = ax2.twinx()
img = ax1.imshow(img, zorder=0, extent=[x[0], x[xm-1], y[0], y[ym-1]], aspect='auto')
fig.tight_layout()
plt.show()
Thanks for any advices you can give me.

Don't use twinx(), but create a new axes with matplotlib.pyplot.axes().
You can do like this controlling the frame(background), x/y axis, and z-order.
fig, ax2 = plt.subplots()
ax2.plot(x, y)
ax2.set_xscale('log')
ax2.set_yscale('log')
ax2.set_frame_on(False)
ax2.zorder = 1
ax1 = plt.axes(ax2.get_position(True))
ax1.set_frame_on(False)
ax1.set_axis_off()
ax1.imshow(img, extent=[x[0], x[xm-1], y[0], y[ym-1]], aspect='auto')
...
It will be simpler if you change the order of plotting like this.
fig, ax2 = plt.subplots()
ax2.imshow(img, extent=[x[0], x[xm-1], y[0], y[ym-1]], aspect='auto')
ax2.set_axis_off()
ax1 = plt.axes(ax2.get_position(True))
ax1.set_frame_on(False)
ax1.set_xscale('log')
ax1.set_yscale('log')
ax1.plot(x, y)
...

Related

Python colorbar with errorbar

I am trying to plot x vs y data and trying to see the variation of x and y with respect to z using a colorbar.
x = [1,2,3,4,5]
x_err = [0.1,0.2,0.3,0.4,0.5]
y = [5,6,7,8,9]
y_err = [0.5,0.6,0.7,0.8,0.9]
z = [3,4,5,6,7]
fig, ax = plt.subplots()
ax.errorbar(x, y, x_err, y_err, fmt='*', elinewidth = 0.9, ecolor='black')
scatter = ax.scatter(x, y, c=z, s=5)
cbar = fig.colorbar(scatter,cmap='viridis')
cbar.set_label('z')
I need the errorbar to have the same color as that of the datapoint.
You could compute the ecolor from the same cmap. Not sure there aren't any solution to do that for you, but it doesn't cost much
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
x = [1,2,3,4,5]
x_err = [0.1,0.2,0.3,0.4,0.5]
y = [5,6,7,8,9]
y_err = [0.5,0.6,0.7,0.8,0.9]
z = [3,4,5,6,7]
fig, ax = plt.subplots()
# Rest of your code is yours. Only this line is added (and next line modified to use this "col" as ecolor
col=cm.viridis((np.array(z)-min(z))/(max(z)-min(z))) # RGBA colors from z
ax.errorbar(x, y, x_err, y_err, ecolor=col, fmt='*', elinewidth = 0.9)
scatter = ax.scatter(x, y, c=z, s=5)
cbar = fig.colorbar(scatter,cmap='viridis')
cbar.set_label('z')
plt.show()
Result

Properly displaying pyplot scatter plot with X/Y histograms and a colorbar

I saw this tutorial on how to make a scatter plot with a histogram for the x and y axes and I thought it would be neat to also tack on a colorbar for an extra dimension of information. To do this, I utilized "the make_axes_locatable" function, like so:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# generating fake data
tx = np.random.randn(1000)
ty = np.random.randn(1000)
tz = np.random.randn(1000)
fig = plt.figure(figsize=(5, 5))
gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4),
left=0.1, right=0.9, bottom=0.1, top=0.9,
wspace=0.05, hspace=0.05)
# Create the Axes.
ax = fig.add_subplot(gs[1, 0])
ax_histx = fig.add_subplot(gs[0, 0], sharex=ax)
ax_histy = fig.add_subplot(gs[1, 1], sharey=ax)
def scatter_hist_and_colorbar(x, y, c, ax, ax_histx, ax_histy,label):
# no labels
ax_histx.tick_params(axis="x", labelbottom=False)
ax_histy.tick_params(axis="y", labelleft=False)
# the scatter plot:
sc=ax.scatter(x,y,marker='o',label=label,c=c)
# now determine nice limits by hand:
binwidth = 0.25
xlim = (int(np.max(np.abs(x))/binwidth) + 1) * binwidth
ylim = (int(np.max(np.abs(y))/binwidth) + 1) * binwidth
xbins = np.arange(-xlim, xlim + binwidth, binwidth)
ybins = np.arange(-ylim, ylim + binwidth, binwidth)
ax_histx.hist(x, bins=xbins)
ax_histy.hist(y, bins=ybins, orientation='horizontal')
return sc
sc1= scatter_hist_and_colorbar(tx,ty,tz, ax, ax_histx, ax_histy,label='data')
ax.set_ylabel('x data')
ax.set_xlabel('y data')
ax.legend()
divider = make_axes_locatable(ax)
cax = divider.append_axes('left', size='5%', pad=1)
cbar=fig.colorbar(sc1, cax=cax, orientation='vertical')
cbar.ax.set_ylabel('z data',rotation=90,labelpad=5)
cbar.ax.yaxis.set_ticks_position("left")
plt.savefig('example.png')
plt.show()][2]][2]
This almost works except the "ax_histx" axis is now stretched and doesn't properly line up due to the addition of the colorbar. Is there a way to resize the "ax_histx" axis or is there a better way to add a colorbar to the "ax" subplot so that it wouldn't affect the "ax_histx" or "ax_histy" axes?
After getting a suggestion form #r-beginners , I tried tweaking this code to place a colorbar in the upper right, perpendicular to the histogram axes. This way, it doesn't distort the width/heights of the other shared axes:
# some random data
tx = np.random.randn(1000)
ty = np.random.randn(1000)
tz = np.random.randn(1000)
fig = plt.figure(figsize=(5, 5))
gs = fig.add_gridspec(2, 2, width_ratios=(4, 1), height_ratios=(1, 4),
left=0.1, right=0.9, bottom=0.1, top=0.9,
wspace=0.05, hspace=0.05)
# Create the Axes.
ax0 = fig.add_subplot(gs[0, 1])
ax = fig.add_subplot(gs[1, 0])
ax_histx = fig.add_subplot(gs[0, 0], sharex=ax)
ax_histy = fig.add_subplot(gs[1, 1], sharey=ax)
def scatter_hist_and_colorbar(x, y, c, ax, ax_histx, ax_histy,label):
# no labels
ax_histx.tick_params(axis="x", labelbottom=False)
ax_histy.tick_params(axis="y", labelleft=False)
# the scatter plot:
sc=ax.scatter(x,y,marker='o',label=label,c=c)
# now determine nice limits by hand:
binwidth = 0.25
xymax = max(np.max(np.abs(x)), np.max(np.abs(y)))
lim = (int(xymax/binwidth) + 1) * binwidth
xlim = (int(np.max(np.abs(x))/binwidth) + 1) * binwidth
ylim = (int(np.max(np.abs(y))/binwidth) + 1) * binwidth
xbins = np.arange(-xlim, xlim + binwidth, binwidth)
ybins = np.arange(-ylim, ylim + binwidth, binwidth)
ax_histx.hist(x, bins=xbins)
ax_histy.hist(y, bins=ybins, orientation='horizontal')
return sc
sc1= scatter_hist_and_colorbar(tx,ty,tz, ax, ax_histx, ax_histy,label='data')
ax.set_ylabel('x data')
ax.set_xlabel('y data')
ax.legend()
divider = make_axes_locatable(ax)
divider = make_axes_locatable(ax0)
ca = divider.append_axes('left', size='50%')
ax0.axis('off')
cbar=fig.colorbar(sc1, cax=ca, orientation='vertical')
cbar.ax.set_ylabel('z data',rotation=270,labelpad=5)
cbar.ax.yaxis.set_ticks_position("right")
gs.tight_layout(fig,pad=1)
plt.savefig('example.png')
plt.show()

matplotlib: how to get 2 y axises with the same scale, and how to show the y axises label?

I'm trying to get the same scale for the y axises, however the label on the second y axis doesn't show. Any help to show it pls ?
x = np.array(lisTxIndices)
y1 = np.array(lisTxCreationTime)
y2 = np.array(lisTxAppendTimeToBC)
fig, ax1 = plt.subplots()
#ax2 = ax1.twinx()
ax2 = ax1.twiny()
a,b = 0,10
ax1.set_ylim(a,b)
ax2.set_ylim(a,b)
ax1.plot(x, y1, 'g-')
ax2.plot(x, y2, 'b-')
ax1.set_xlabel('TxIndex')
ax1.set_ylabel('TxCreationTime (sec)', color='g')
ax2.set_ylabel('TxAppendTimeToBC (sec)', color='b')
plt.show()
Thanks in advance.

Stacked horizontal plots with multiple Y axis varying in scale

Hi I am trying to create:
horizontally stacked plots
Have secondary axis on both plots
Have different scales on axis - unfortunately, both my Y axis currently have the same scale per subplot... :(
Current code:
# Create axes
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.suptitle("XYZ")
fig.set_figheight(5)
fig.set_figwidth(15)
# First graph
ax1.scatter(
df_PTA_clip_pstar["start_time"],
df_PTA_clip_pstar["pstar"],
s=5,
c="black",
label="P*",
)
plt.ylabel("P*")
ax1.scatter(df_PTA_clipkh["start_time"], df_PTA_clipkh["kh"], s=2, c="cyan", label="Kh")
ax1.secondary_yaxis("right")
plt.ylabel("Kh")
# Second graph - will add the correct data to this once first graph fixed
ax2.scatter(x, y, s=5, c="Red", label="P*")
ax2.scatter(x, z, s=5, c="Green", label="Kh")
ax2.secondary_yaxis("right")
plt.tight_layout()
plt.legend()
plt.show()
Current progress:
You can use .twinx() method on each ax object so you can have two plots on the same ax object sharing x-axis:
import matplotlib.pyplot as plt
import numpy as np
# Create axes
fig, (ax1, ax2) = plt.subplots(1, 2)
## First subplot
x = np.random.random_sample(100)
y = np.random.random_sample(100)
ax1.set_xlim(0, 2)
ax1.scatter(x, y,
s=5,
c="black")
ax11 = ax1.twinx()
x = 1 + x
y = 1 + np.random.random_sample(100)
ax11.scatter(x, y,
s=5,
c="red")
## Second subplot
x = 2 * np.random.random_sample(100) - 1
y = np.random.random_sample(100)
ax2.set_xlim(-1, 2)
ax2.scatter(x, y,
s=5,
c="blue")
ax21 = ax2.twinx()
x = 1 + x
y = 10 + np.random.random_sample(100)
ax21.scatter(x, y,
s=5,
c="orange")
plt.show()

With MatPlotLib, how do I apply autoscaled axes from one graph to a separate graph?

So I have a dataset I want to plot. In this case, I want to plot all the data on the same graph, and then graph each point in the set on its own graph, but keep the axis scale/limits the same for each graph.
So what I need to do is find the values of the autoscaled axis limits that were set for the full set of data, and apply those limits to the graph for each individual points.
I am and have been reading the mpl docs to see if theres any kind of function I can use that will return the axis limits values, but I haven't found anything so far.
Im using Python 3.4 with matplotlib
Thanks,
evamvid
Although it is possible to find the limits with
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
and set them on another axes with
ax2.set_xlim(xmin, xmax)
ax2.set_ylim(ymin, ymax)
it might be easier to use plt.subplots with sharex=True and sharey=True:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2015)
N = 5
x, y = np.random.randint(100, size=(2,N))
fig, axs = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True)
colors = np.linspace(0, 1, N)
axs[0,0].scatter(x,y, s=200, c=colors)
for i, ax in enumerate(axs.ravel()[1:]):
ax.scatter(x[i], y[i], s=200, c=colors[i], vmin=0, vmax=1)
plt.show()
Another option is to pass an axes to sharex and sharey:
ax3 = subplot(313, sharex=ax1, sharey=ax1)
For example,
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import itertools as IT
np.random.seed(2015)
N = 6
x, y = np.random.randint(100, size=(2,N))
colors = np.linspace(0, 1, N)
gs = gridspec.GridSpec(4, 2)
ax = plt.subplot(gs[0, :])
ax.scatter(x, y, s=200, c=colors)
for k, coord in enumerate(IT.product(range(1,4), range(2))):
i, j = coord
ax = plt.subplot(gs[i, j], sharex=ax, sharey=ax)
ax.scatter(x[k], y[k], s=200, c=colors[k], vmin=0, vmax=1)
plt.tight_layout()
plt.show()

Categories

Resources