Limit the points in subplots only to zoomed in region - python

I have a set of 100 random 2D points (between 0 and 20) in a scatter plot with 2 sub plots surrounding the main. When I zoom in the main scatter plot, the range on the subplots gets shrunk, however I can see points from outside the zoom window region.
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import random
numPoints = 100
x = [random.uniform(0, 20) for i in range(numPoints)]
y = [random.uniform(0, 20) for i in range(numPoints)]
# Set up the axes with gridspec
fig = plt.figure(figsize=(6, 6), constrained_layout=True)
grid = fig.add_gridspec(ncols=2, nrows=2, width_ratios=[0.3, 5], height_ratios=[5, 0.3])
main_ax = fig.add_subplot(grid[:-1, 1:])
main_ax.plot(x, y, 'ok', markersize=3, alpha=0.2)
y_hist = fig.add_subplot(grid[:-1, 0], xticklabels=[], sharey=main_ax)
x_hist = fig.add_subplot(grid[-1, 1:], yticklabels=[], sharex=main_ax)
x_hist.plot(
x, [0 for i in x],
'ok',
color='gray'
)
x_hist.invert_yaxis()
y_hist.plot(
[0 for i in y], y,
'ok',
color='gray'
)
y_hist.invert_xaxis()
main_ax.grid(True, lw = 1, ls = '--', c = '.75')
x_hist.grid(True, axis="x", lw = 1, ls = '--', c = '.75')
y_hist.grid(True, axis="y", lw = 1, ls = '--', c = '.75')
plt.show()
I am trying to get the dots in the left and bottom sub plots of the above image to match just what you see in the main plot (3 points).
Instead they show everything in that direction. The Left subplot shows every point on the x axis between 0 and 2.5. The bottom subplot shows every point on the y axis between 10 and 12.5.

You would need to filter the data, depending on the limits of the main axes. One can connect callbacks on zoom events, see Matplotlib: Finding out xlim and ylim after zoom and connect them to a function that performs the filtering on the data.
import numpy as np
import matplotlib.pyplot as plt
numPoints = 100
x = np.random.rand(numPoints)*20
y = np.random.rand(numPoints)*20
zeros = np.zeros_like(x)
# Set up the axes with gridspec
fig = plt.figure(figsize=(6, 6), constrained_layout=True)
grid = fig.add_gridspec(ncols=2, nrows=2, width_ratios=[0.3, 5], height_ratios=[5, 0.3])
ax_main = fig.add_subplot(grid[:-1, 1:])
ax_y = fig.add_subplot(grid[:-1, 0], xticklabels=[], sharey=ax_main)
ax_x = fig.add_subplot(grid[-1, 1:], yticklabels=[], sharex=ax_main)
ax_main.plot(x, y, 'ok', markersize=3, alpha=0.2)
xline, = ax_x.plot(x, zeros, marker='o', ls="none", color='gray')
yline, = ax_y.plot(zeros, y, marker='o', ls="none", color='gray')
ax_main.grid(True, lw = 1, ls = '--', c = '.75')
ax_y.grid(True, axis="x", lw = 1, ls = '--', c = '.75')
ax_x.grid(True, axis="y", lw = 1, ls = '--', c = '.75')
def xchange(evt):
ymin, ymax = ax_main.get_ylim()
filt = (y <= ymax) & (y >= ymin)
xline.set_data(x[filt], zeros[filt])
def ychange(evt):
xmin, xmax = ax_main.get_xlim()
filt = (x <= xmax) & (x >= xmin)
yline.set_data(zeros[filt], y[filt])
ax_main.callbacks.connect('xlim_changed', ychange)
ax_main.callbacks.connect('ylim_changed', xchange)
plt.show()

Related

Gradient fill from zero till a curve

I have been using Is it possible to get color gradients under curve in matplotlib? as a reference (you can see the similarities, however i cant for the life of me figure out how to push the shading all the way down to 0 on the Y AXIS, for some reason which i cant find out, it has an upward sloping straight line cutting off the shading, i cant find anything in my data to suggest why its doing this.
for context the y axis can show positive and negative and i want to fill the scale the whole way so using gradient colour to fill from 0 to the line (positive) then fill from 0 to the negative line (see my blue example from a previous chart -same data-)
Here is my code
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.patches import Polygon
# Variables
AUM = df['#AHD_AUM'].head(104)
MM = df['#AHD_Managed_Money_Net'].head(104)
PRICE = df['#AHD_Price'].head(104)
DATES = df['DATES'].head(104)
# Date Friendly Variables for Plot
List_AUM = df['#AHD_AUM'].head(104).to_list()
List_MM = df['#AHD_Managed_Money_Net'].head(104).to_list()
List_DATES = df['DATES'].head(104).to_list()
X = 0 * df['#AHD_AUM'].head(104)
# Make a date list changing dates with numbers to avoid the issue with the plot
interpreting dates
for i in range(len(df['DATES'].head(104))):
count = i
df['count'][i] = 120 - i
# X and Y data variables changed to arrays as when i had these set as dates
matplotlib hates it
x = df['count'].head(104).to_numpy()
y = df['#AHD_Managed_Money_Net'].head(104).to_numpy()
#DD = AUM.to_numpy()
#MMM = MM.to_numpy()
def main():
for _ in range(len(DD)):
gradient_fill(x,y)
plt.show()
def gradient_fill(x,y, fill_color=None, ax=None, **kwargs):
"""
"""
if ax is None:
ax = plt.gca()
line, = ax.plot(x, y, **kwargs)
if fill_color is None:
fill_color = line.get_color()
zorder = line.get_zorder()
alpha = line.get_alpha()
alpha = 1.0 if alpha is None else alpha
z = np.empty((100, 1, 4), dtype=float)
rgb = mcolors.colorConverter.to_rgb(fill_color)
z[:,:,:3] = rgb
z[:,:,-1] = np.linspace(0, alpha, 100)[:,None]
xmin, xmax, ymin, ymax = x.min(), x.max(), y.min(), y.max()
im = ax.imshow(z, aspect='auto', extent=[xmin, xmax, ymin, ymax],
origin='lower', zorder=zorder)
xy = np.column_stack([x, y])
# xy = np.vstack([[xmin, ymin], xy, [xmax, ymin], [xmin, ymin]]) ### i dont
need this so i have just commented it out
clip_path = Polygon(xy, facecolor='none', edgecolor='none', closed=True)
ax.add_patch(clip_path)
im.set_clip_path(clip_path)
ax.autoscale(True)
return line, im
main()
this is my current output
An easier way to clip the gradient by the curve, is to use a polygon obtained from fill_between.
Here is some example code to get you started.
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(123)
x = np.linspace(0, 10, 200)
y = np.random.normal(0.01, 1, 200).cumsum()
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(x, y)
ylim = ax.get_ylim()
grad1 = ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1), cmap='Blues', vmin=-0.5, aspect='auto',
extent=[x.min(), x.max(), 0, y.max()], origin='lower')
poly_pos = ax.fill_between(x, y.min(), y, alpha=0.1)
grad1.set_clip_path(poly_pos.get_paths()[0], transform=ax.transData)
poly_pos.remove()
grad2 = ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1), cmap='Reds', vmin=-0.5, aspect='auto',
extent=[x.min(), x.max(), y.min(), 0], origin='upper')
poly_neg = ax.fill_between(x, y, y.max(), alpha=0.1)
grad2.set_clip_path(poly_neg.get_paths()[0], transform=ax.transData)
poly_neg.remove()
ax.set_ylim(ylim)
ax.axhline(0, color='black') # show a line at x=0
plt.show()
PS: vmin in imshow can be used to remove the color range where it's very light:
grad1 = ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1), cmap='Blues', vmin=-0.5, aspect='auto',
extent=[x.min(), x.max(), 0, y.max()], origin='lower')
grad2 = ax.imshow(np.linspace(0, 1, 256).reshape(-1, 1), cmap='Reds', vmin=-0.5, aspect='auto',
extent=[x.min(), x.max(), y.min(), 0], origin='upper')
import pandas as pd # For data handling
import seaborn as sns # For plotting
import numpy as np
import matplotlib.pyplot as plt # For plotting
import matplotlib
#some preferred user settings
plt.rcParams['figure.figsize'] = (18.0, 12.0)
pd.set_option('display.max_columns', None)
%matplotlib inline
import warnings
warnings.filterwarnings(action='ignore')
from mpl_toolkits.axisartist.parasite_axes import HostAxes, ParasiteAxes
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
import datetime as dt
import matplotlib.dates as mdates
import pandas
Metal = CAD
# Variables
AUM = Metal.iloc[:,[7]].head(104)
MM = Metal.iloc[:,[0]].head(104)
PRICE = Metal.iloc[:,[8]].head(104)
#Last_Report = Metal.iloc[:,[9]].head(1).dt.strftime('%d %b %Y').to_list()
DATES = Metal.iloc[:,[10]].head(104)
# Dataframe for Net Position High
Net_High = Metal[Metal.iloc[:,[0]] == Metal.iloc[:,[0]].max()]
# Variables for Chart Annotation for Net Position High
Pos_High_Date = Net_High.iloc[:, [0]]
Pos_High_AUM = Net_High.iloc[:, [7]][0]/[1000000000]
Pos_High_Price = Net_High.iloc[:, [8]].to_numpy()[0].round().astype('int')
Pos_High = Net_High.iloc[:, [0]][0].astype('int')
Str_Date = mdates.num2date(Pos_High_Date)
Str_Date = pd.to_datetime(Str_Date[0]).strftime("%d %b %y")[0]
# Dataframe for Net Position Low
Net_Low = df[df['#CAD_Managed_Money_Net'] == df['#CAD_Managed_Money_Net'].head(104).min()]
# Variables for Chart Annotation for Net Position High
Pos_Low_Date = Net_Low.iloc[:, [55]].to_numpy()
Pos_Low_AUM = Net_Low.iloc[:, [26]].to_numpy()[0].round()/[1000000000]
Pos_Low_Price = Net_Low.iloc[:, [27]].to_numpy()[0].round().astype('int')
Pos_Low = Net_Low['#CAD_Managed_Money_Net'][0].astype('int')
Str_Date_Low = mdates.num2date(Pos_Low_Date)
Str_Date_Low = pd.to_datetime(Str_Date_Low[0]).strftime("%d %b %y")[0]
# C Brand Colour Scheme
C = ['deepskyblue', '#003399', 'slategray', '#027608','#cc0000']
def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in ax.spines.values():
sp.set_visible(False)
fig, host = plt.subplots(figsize=(25,15))
fig.subplots_adjust(right=0.8)
#twinx() creates another axes sharing the x axis we do this twice
par1 = host.twinx()
par2 = host.twinx()
# Offset the right spine of par2 the ticks
par2.spines["right"].set_position(("axes",1.08))
#because par2 was created by twinx the frame is off so we need to use the method created above
make_patch_spines_invisible(par2)
# second, show the right spine
par2.spines["right"].set_visible(True)
######### Colouring in Plots
x = DATES
y = MM
ylim = host.get_ylim()
Long = host.imshow(np.linspace(0, 1, 256).reshape(-1, 1), cmap= 'Blues', vmin=-0.5, aspect='auto',
extent=[x.min(), x.max(), 0, y.max()], origin='lower')
poly_pos = host.fill_between(x, y.min(), y, alpha=0.1)
Long.set_clip_path(poly_pos.get_paths()[0], transform=host.transData)
poly_pos.remove()
Short = host.imshow(np.linspace(0, 1, 256).reshape(-1, 1), cmap='OrRd', vmin=-0.5, aspect='auto',
extent=[x.min(), x.max(), y.min(), 0], origin='upper')
poly_neg = host.fill_between(x, y, y.max(), alpha=0.1)
Short.set_clip_path(poly_neg.get_paths()[0], transform=host.transData)
poly_neg.remove()
##########
#plot data
p1, = host.plot(DATES, MM, label="Managed Money Net Position", linewidth=0.0,color = Citi[1], alpha = 0.8)
p2, = par1.plot(DATES, AUM, label="AUM",linewidth=1, marker = '$A$',mew = 1,mfc = 'w', color = Citi[0], alpha = 0.8)
p3, = par2.plot(DATES, PRICE, label="3M Price",linewidth=1, marker = '$p$', color = Citi[2], alpha = 0.8)
#Automatically scale and format
host_labels = ['{:,.0f}'.format(x) + 'K Lots' for x in host.get_yticks()/1000]
host.set_yticklabels(host_labels)
par1_labels = ['{:,.1f}'.format(x) + ' $Billion' for x in par1.get_yticks()/1000000000]
par1.set_yticklabels(par1_labels)
par2_labels = ['{:,.0f}'.format(x) + ' $' for x in par2.get_yticks()]
par2.set_yticklabels(par2_labels)
# x Axis formatting (date)
formatter = matplotlib.dates.DateFormatter('%b- %Y')
host.xaxis.set_major_formatter(formatter)
# Rotates and right-aligns the x labels so they don't crowd each other.
for label in host.get_xticklabels(which='major'):
label.set(rotation=30, horizontalalignment='right')
# Axis Labels
host.set_xlabel("Date")
host.set_ylabel("Managed Money Net Position")
par1.set_ylabel("AUM")
par2.set_ylabel("3M Price")
# Tick Parameters
tkw = dict(size=10, width=2.5)
# Set tick colours
host.tick_params(axis = 'y', colors = Citi[1], **tkw)
par1.tick_params(axis = 'y', colors = Citi[0], **tkw)
par2.tick_params(axis = 'y', colors = Citi[2], **tkw)
#host.tick_params(which='major',axis = 'x',direction='out', colors = Citi[2], **tkw)
#plt.xticks(x, rotation='vertical')
#host.xaxis.set_major_locator(AutoMajorLocator())
host.xaxis.set_major_locator(MultipleLocator(24))
host.tick_params('x',which='major', length=7)
#Label colours taken from plot
host.yaxis.label.set_color(p1.get_color())
par1.yaxis.label.set_color(p2.get_color())
par2.yaxis.label.set_color(p3.get_color())
# Map Title
host.set_title('Aluminium Managed Money Net Positioning as of %s'% Last_Report[0],fontsize='large')
#Colour Spines cant figure out how to do it for the host
par1.spines["right"].set_edgecolor(p2.get_color())
par2.spines["right"].set_edgecolor(p3.get_color())
###### Annotation Tests ##########
## Net Position High Box
host.annotate(f' Net Position High | {Pos_High} \n Date | {Str_Date} \n AUM | ${Pos_High_AUM[0].round(1)} Billion\n 3M Price | ${Pos_High_Price[0]}$',
xy=(Pos_High_Date, Pos_High), xycoords='data',
xytext=(0.02, .85), textcoords='axes fraction',
horizontalalignment='left',
verticalalignment='bottom',
color='white',
bbox=dict(boxstyle="round", fc= Citi[1],edgecolor='white'),
arrowprops=dict(
facecolor='black',
arrowstyle= '->'))
## Net Position Low Box
host.annotate(f' Net Position Low | {Pos_Low} \n Date | {Str_Date_Low} \n AUM | ${Pos_Low_AUM[0].round(1)} Billion\n 3M Price | ${Pos_Low_Price[0]}$',
xy=(Pos_Low_Date, Pos_Low), xycoords='data',
xytext=(0.02, .80), textcoords='axes fraction',
horizontalalignment='left',
verticalalignment='top',
color='white',
bbox=dict(boxstyle="round", fc= Citi[4],edgecolor='white'),
arrowprops=dict(
facecolor='black',
arrowstyle= '->'))
################
# Legend - a little complicated as we have to take from multiple axis
lines = [p1, p2, p3]
########## Plot text and line on chart if you want to
# host.axvline(x = DATES[52] , linestyle='dotted', color='black') ###Dotted Line when Needed
# host.text(2020.3, 10, 'Managed Money \n Aluminium')
# host.text(2020.5, 92, r'Ali',color='black')
# host.text(2020.8,15, r'some event', rotation=90)
host.legend(lines,[l.get_label() for l in lines],loc=2, fontsize=12,frameon=False)
plt.savefig('multiple_axes.png', dpi=300, bbox_inches='tight')

How to combine two matplotlib (python) colormaps from scatter plot

I am trying to combine two colourmap legends in one. Colour values are defined from third (z) data.
I am trying plot one legend colormap with two color scheme.
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
df = pd.read_excel('C:\\Users\user1\\PycharmProjects\\untitled\\Python_test.xlsx')
x = df['Vp_dry']
y = df['Vs_dry']
q = df['Vp_wet']
w = df['Vs_wet']
fig, ax = plt.subplots()
popt, pcov = curve_fit(lambda fx, a, b: a * fx ** -b, x, y)
x_linspace = np.linspace(min(x - 100), max(x + 100), 100)
power_y = popt[0]*x_linspace ** -popt[1]
ax1 = plt.scatter(x, y, c=df['Porosity'], cmap=plt.cm.Greys, vmin=2, vmax=df['Porosity'].max(), edgecolors="#B6BBBD")
plt.plot(x_linspace, power_y, color='grey', label='Dry')
popt, pcov = curve_fit(lambda fx, a, b: a * fx ** -b, q, w)
q_linspace = np.linspace(min(q - 100), max(q + 100), 100)
power_w = popt[0]*q_linspace ** -popt[1]
ax2 = plt.scatter(q, w, c=df['Porosity'], cmap=plt.cm.Blues, vmin=2, vmax=df['Porosity'].max(), edgecolors="#3D83C1")
plt.plot(q_linspace, power_w, label='Wet')
cbar = fig.colorbar(ax2)
cbar = fig.colorbar(ax1)
cbar.set_label("Porosity (%)")
plt.xlabel('Vp (m/s)')
plt.ylabel('Vs (m/s)')
plt.grid()
plt.legend()
plt.show()
Desired result:
You seem to need a colorbar with two color maps combined, one of them reversed, and have the ticks changed to percentage values.
An approach is to manually create a second subplot, use two images and make it look like a colorbar:
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import numpy as np
# first create some dummy data to plot
N = 100
x = np.random.uniform(0, 10, N)
y = np.random.normal(15, 2, N)
q = np.random.uniform(0, 10, N)
w = np.random.normal(10, 2, N)
df_porosity = np.random.uniform(0, 5, N)
fig, (ax, ax2) = plt.subplots(ncols=2, figsize=(6, 4), gridspec_kw={"width_ratios": [1, 0.08]})
plot1 = ax.scatter(x, y, c=df_porosity, cmap=plt.cm.Greys, vmin=2, vmax=df_porosity.max(), edgecolors="#B6BBBD")
plot2 = ax.scatter(q, w, c=df_porosity, cmap=plt.cm.Blues, vmin=2, vmax=df_porosity.max(), edgecolors="#3D83C1")
img_cbar = np.linspace(0, 1, 256).reshape(256, 1)
ax2.imshow(img_cbar, cmap=plt.cm.Blues, extent=[0, 1, 1, 0]) # aspect='auto')
ax2.imshow(img_cbar, cmap=plt.cm.Greys, extent=[0, 1, -1, 0])
ax2.set_ylim(-1, 1)
ax2.set_aspect(10)
ax2.set_ylabel("Porosity (%)")
ax2.yaxis.set_label_position("right")
ax2.set_xticks([])
ax2.yaxis.tick_right()
# optionally show the ticks as percentage, where 1.0 corresponds to 100 %
ax2.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))
plt.tight_layout()
plt.show()

Increase space between y tick and custom x axis

I'm trying to a build a plot that has an exponential function on the top and the utility function on the bottom. With the Y-Axis in the top plot showing the latency and X-Axis as the congestion; similarly, in the second plot, Y-Axis is the throughput and the X-Axis is the congestion.
Where I fail to get is, how do I set the X-Axis as a percentage, and is there a way to superimpose these two graphs.
#!/usr/bin/env python3
import numpy as np
import math
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import matplotlib
fig = plt.figure()
x = np.arange(1,9,1)
y = [math.exp(_) for _ in x]
ax = fig.add_subplot(211)
ax.plot(x, y)
ax.set_ylabel('Y_plot1')
ax.set_xlabel('X_plot1')
ax.set_yticks([],[])
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.yaxis.set_tick_params(which='major', direction='out')
ax.set_ymargin(1)
ax1 = fig.add_subplot(212)
mu = 5
variance = 1
sigma = math.sqrt(variance)
x_normal = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
y_normal = mlab.normpdf(x_normal, mu, sigma)
#y_normal += 1000
x_normal = [0, 0] + list(x_normal)
y_normal = [0, 0] + list(y_normal)
ax1.plot(x_normal, y_normal)
ax1.set_ylabel('Y_plot2')
ax1.set_xlabel('X_plot2')
ax1.set_yticks([],[])
ax1.spines['right'].set_visible(False)
ax1.spines['top'].set_visible(False)
ax1.xaxis.set_ticks_position('bottom')
ax1.yaxis.set_ticks_position('left')
ax1.set_ymargin(1)
fig.tight_layout()
fig.savefig('bw-latency' +'.pdf',format='pdf',bbox_inches='tight', pad_inches=0.1, dpi=1000)
plt.clf()
plt.close()
To convert your x-axis to percent, you could normalize x_normaland adjust the xticks:
x_normal = x_normal/(max(x_normal)-min(x_normal)) + min(x_normal)
ax1.plot(x_normal, y_normal)
ax1.set_xticks(np.linspace(0,1,5))
ax1.set_xticklabels([str(int(i*100)) for i in np.linspace(0,1,5)])
To superimpose two graphs, have a look at: https://matplotlib.org/gallery/api/two_scales.html
I your case:
ax3 = ax1.twinx()
y = [math.exp(_) for _ in x_normal]
ax3.plot(x_normal, y,color="r")
EDIT: Is this the kind of output you are seeking?:
Here is the code that worked for me:
def plot_percentage(x, y, ax):
x = x/max(x)
ax.plot(x, y)
ax.set_xticks(np.linspace(0, 1, 10))
ax.set_xticklabels([str(int(i*100)) for i in np.linspace(0,1, 10)])
fig = plt.figure()
x = np.arange(1,9,1)
y = [math.exp(_) for _ in x]
ax = fig.add_subplot(211)
plot_percentage(x, y, ax)
ax.set_ylabel('Y_plot1')
ax.set_xlabel('X_plot1')
ax.set_yticks([],[])
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.yaxis.set_tick_params(which='major', direction='out')
ax.set_ymargin(1)
ax1 = fig.add_subplot(212)
mu = 5
variance = 1
sigma = math.sqrt(variance)
x_normal = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
y_normal = mlab.normpdf(x_normal, mu, sigma)
#y_normal += 1000
x_normal = [0, 0] + list(x_normal)
y_normal = [0, 0] + list(y_normal)
plot_percentage(x_normal, y_normal, ax1)
ax3 = ax1.twinx()
y = [math.exp(_) for _ in x_normal]
plot_percentage(x_normal, y, ax3)
plt.show()

How to show Cartesian system in polar plot in python?

Here I tried to add the polar plot on top of the Cartesian grid,but what I got instead was 2 separate figures(one polar another Cartesian),I want this polar figure to be embedded in the Cartesian plot. Also I have used some of the code previously available as I am new to matplotlib.
from pylab import *
import matplotlib.pyplot as plt
x = [0,10,-3,-10]
y = [0,10,1,-10]
color=['w','w','w','w']
fig = plt.figure()
ax1 = fig.add_subplot(111)
scatter(x,y, s=100 ,marker='.', c=color,edgecolor='w')
circle1=plt.Circle((0,0),5,color='r',fill=False)
circle_min=plt.Circle((0,0),4.5,color='g',fill=False)
circle_max=plt.Circle((0,0),5.445,color='b',fill=False)
fig = plt.gcf()
fig.gca().add_artist(circle1)
fig.gca().add_artist(circle_min)
fig.gca().add_artist(circle_max)
left,right = ax1.get_xlim()
low,high = ax1.get_ylim()
arrow( left, 0, right -left, 0, length_includes_head = True, head_width = 0.15 )
arrow( 0, low, 0, high-low, length_includes_head = True, head_width = 0.15 )
grid()
fig = plt.figure()
ax2 = fig.add_subplot(111)
scatter(x,y, s=100 ,marker='.', c=color,edgecolor='w')
circle2=plt.Circle((0,0),5,color='r',fill=False)
circle_min=plt.Circle((0,0),4.5,color='g',fill=False)
circle_max=plt.Circle((0,0),5.445,color='b',fill=False)
fig = plt.gcf()
fig.gca().add_artist(circle2)
fig.gca().add_artist(circle_min)
fig.gca().add_artist(circle_max)
left,right = ax2.get_xlim()
low,high = ax2.get_ylim()
arrow( left, 0, right -left, 0, length_includes_head = True, head_width = 0.15 )
arrow( 0, low, 0, high-low, length_includes_head = True, head_width = 0.15 )
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi, np.pi, 100)
r1 = 1 - np.sin(3*theta)
r2 = 1 + np.cos(theta)
ax = plt.subplot(111, polar=True, # add subplot in polar coordinates
axisbg='Azure') # background colour
ax.set_rmax(2.2) # r maximum value
ax.grid(True) # add the grid
ax.plot(theta, r1,
color='Tomato', # line colour
ls='--', # line style
lw=3, # line width
label='a 3-fold curve') # label
ax.plot(theta, r2,
color='purple',
linewidth=3,
ls = '-',
label = 'a cardioid')
ax.legend(loc="lower right") # legend location
titlefont = {
'family' : 'serif',
'color' : 'black',
'weight' : 'bold',
'size' : 16,
}
ax.set_title("A plot in polar coordinates", # title
va='bottom', # some space below the title
fontdict = titlefont # set the font properties
)
grid()
show()
#I am getting a separate Cartesian image + a polar image while what I need is both the things in a single image
import matplotlib.pyplot as plt
import numpy as np
#########################################
color=['w','w','w','w']
theta = np.linspace(-np.pi, np.pi, 100)
fig = plt.figure()# initializing the figure
rect = [0.1, 0.1, 0.8, 0.8]# setting the axis limits in [left, bottom, width, height]
ax_carthesian = fig.add_axes(rect)# the carthesian axis:
ax_polar = fig.add_axes(rect, polar=True, frameon=False)# the polar axis:
#########################################
ax_carthesian.add_artist(plt.Circle((0.5,0.5),5/15,color='r',fill=False))
ax_carthesian.add_artist(plt.Circle((0.5,0.5),4.5/15,color='g',fill=False))
ax_carthesian.add_artist(plt.Circle((0.5,0.5),5.445/15,color='b',fill=False))
ax_polar.plot(theta, 1 - np.sin(3*theta), color='Tomato',ls='--',lw=1, label='a 3-fold curve')
ax_polar.plot(theta, 1 + np.cos(theta), color='purple',linewidth=1,ls = '-',label = 'a cardioid')
plt.show()
I am not used to matplotlib but I reduced your code to his minimum to better understand it and make it look less redudant. look at what I get:
import pylab
import matplotlib.pyplot as plt
import numpy as np
#########################################
x = [0,10,-3,-10]
y = [0,10,1,-10]
color=['w','w','w','w']
theta = np.linspace(-np.pi, np.pi, 100)
#########################################
pylab.scatter(x,y, s=100 ,marker='.', c=color,edgecolor='w')
plt.gcf().gca().add_artist(plt.Circle((0,0),5,color='r',fill=False))
plt.gcf().gca().add_artist(plt.Circle((0,0),4.5,color='g',fill=False))
plt.gcf().gca().add_artist(plt.Circle((0,0),5.445,color='b',fill=False))
plt.figure().add_subplot(111)
ax = plt.subplot(111, polar=True,axisbg='Azure')
ax.plot(theta, 1 - np.sin(3*theta),color='Tomato',ls='--',lw=3,label='a 3-fold curve')
ax.plot(theta, 1 + np.cos(theta),color='purple',linewidth=3,ls = '-',label = 'a cardioid')
pylab.show()
it is nearly the same result...

How to put circles on top of a polygon?

I use matplotlib to generate an image in the following way:
fig = plt.figure()
ax = fig.add_subplot(111)
ax.fill(border[0],border[1], color='g', linewidth=1, fill=True, alpha = 0.5)
patches = []
for x1,y1,r in zip(x, y, radii):
circle = Circle((x1,y1), r)
patches.append(circle)
p = PatchCollection(patches, cmap='cool', alpha=1.0)
p.set_array(c)
ax.add_collection(p)
plt.colorbar(p)
plt.savefig(fig_name)
What I want to have is a polygon (given by its border) and colored circles on the top of this polygon. However, I get the polygon on the top of the circles.
This is strange because I plot the polygon first and then I add circles to the plot.
Does anybody know why it happens and how this problem can be resolved?
ADDED
As requested, here is fully working example:
import pandas
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
from matplotlib.patches import Circle, Polygon
import numpy as np
def plot_xyc(df, x_col, y_col, c_col, radius, fig_name, title, zrange):
resolution = 50
x = df[x_col]
y = df[y_col]
c = df[c_col]
x0 = (max(x) + min(x))/2.0
y0 = (max(y) + min(y))/2.0
dx = (max(x) - min(x))
dy = (max(y) - min(y))
delta = max(dx, dy)
radii = [delta*radius for i in range(len(x))]
fig = plt.figure()
plt.title(title)
ax = fig.add_subplot(111)
border = ([-3, 3, 3, -3], [-3, -3, 3, 3])
ax.fill(border[0],border[1], color='g', linewidth=1, fill=True, alpha = 1.0)
patches = []
for x1,y1,r in zip(x, y, radii):
circle = Circle((x1,y1), r)
patches.append(circle)
patches.append(Circle((-100,-100), r))
patches.append(Circle((-100,-100), r))
p = PatchCollection(patches, cmap='cool', alpha=1.0)
p.set_array(c)
max_ind = max(c.index)
c.set_value(max_ind + 1, min(zrange))
c.set_value(max_ind + 2, max(zrange))
plt.xlim([x0 - delta/2.0 - 0.05*delta, x0 + delta/2.0 + 0.05*delta])
plt.ylim([y0 - delta/2.0 - 0.05*delta, y0 + delta/2.0 + 0.05*delta])
ax.add_collection(p)
plt.colorbar(p)
plt.savefig(fig_name)
if __name__ == '__main__':
df = pandas.DataFrame({'x':[1,2,3,4], 'y':[4,3,2,1], 'z':[1,1,2,2]})
plot_xyc(df, 'x', 'y', 'z', 0.1, 'test2.png', 'My Titlle', (0.0, 3.0))
You're looking for zorder.
In matplotlib, all additional arguments are just passed up the class heirarchy. zorder is a kwarg of the Artist class, so you just need to make sure that at some point it gets zorder.
You can do it two ways in your example;
either add it in here:
ax.fill(border[0],border[1], color='g', linewidth=1, fill=True, alpha = 1.0, zorder=1)
or here:
p = PatchCollection(patches, cmap='cool', alpha=1.0, zorder=2)
or if you want, both. Objects with a higher zorder sit on top of those with lower values.

Categories