How to set a maximum value for my partial dependance plot? When I set the limit for the x axis it works, but it doesn't for the y axis, why?
Similar posts I looked at: Limit axis range on pdp plot in python
shap.partial_dependence_plot(
"fc", model.predict, X100, ice=False, show=False,
model_expected_value=True, feature_expected_value=True, ylabel="R")
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
#ax = plt.gca()
#ax.set_ylim([0, 600])
plt.rcParams["figure.dpi"] = 90
plt.xlim(0, 600)
plt.ylim(0, 600)
plt.show()
shap.dependence_plot seems to return a plot object but you store it no where, right ? If so, that's probably why you can't set the limit for the y-axis (since the plot isn't available yet!). I suggested you to do so :
fig, ax = shap.partial_dependence_plot( # <- storing the plot in ax
"fc", model.predict, X100, ice=False, show=False,
model_expected_value=True, feature_expected_value=True, ylabel="R")
plt.rcParams["figure.dpi"] = 90
ax.set_xlim(0, 600) # <- changed plt by ax
ax.set_ylim(0, 600) # <- changed plt by ax
plt.show()
Related
I have the issue that I am trying to make multiple plots that are supposed to have the same bbox size. As some of my plots have an additional colorbar or wider yticklabels the bbox size varies within multiple plots.
As I would like to use these plots in a LaTex document underneath each other, I would like to set the bbox for all plots to the same value instead of defining the figure size.
If it is not clear yet what I mean, here's an example:
As you can see the bbox sizes vary, as the width of the ylabel + ylabelticks and additionally the cbar is added. I thought the easisest way to approach this would be to find the image of the smallest drawn bbox and use that as a standard for all figures and keep the figsize constant, or to just set the bbox size constant and just add the rest and have varying figsizes.. the later would need me to do additional positioning in latex/illustrator/power point or whatever, but just about any solution that works would be great (even though I belive that the later is likely not possible with matplotlib). I tried changing the bbox size but unfortunately did not succeed. So I do not have some code to start from. But any help or pointers where to look at or start would help a lot.
Here a short code snippet to reproduce.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
np.random.seed(1)
mpl.rcParams['figure.figsize'] = (16.0, 12.0)
x = np.linspace(0, 100, 100)
y = np.random.randint(100, size=100)
z = np.random.randint(0, 1e6, size=100)/1e6
fig, ax = plt.subplots()
m = mpl.cm.ScalarMappable(cmap=mpl.cm.jet)
norm = plt.Normalize(min(z), max(z))
m.set_array(list(set(z)))
cbar = plt.colorbar(m, orientation="vertical", fraction=0.07, pad=0.02)
color = lambda c: m.cmap(norm(c))
ax.scatter(x, y, color=color(z))
fig, ax = plt.subplots()
ax.scatter(x, y)
pls see following code. I recommend you using ax1 and ax2, which have more flexibility.
Key points:
using get_position() to get bounds of axes.
using set_position() to set bounds of axes.
I highly recommend using ax1, ax2 ... instead of plt.stuff for multiple subplots.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
np.random.seed(1)
x = np.linspace(0, 100, 100)
y = np.random.randint(100, size=100)
z = np.random.randint(0, 1e6, size=100)/1e6
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 4))
m = mpl.cm.ScalarMappable(cmap=mpl.cm.jet)
norm = plt.Normalize(min(z), max(z))
m.set_array(list(set(z)))
cbar = fig.colorbar(m, orientation="vertical", fraction=0.07, pad=0.02)
color = lambda c: m.cmap(norm(c))
ax2.scatter(x, y, color=color(z))
ax1.scatter(x, y)
# get the bounds of ax1 and ax2
x1, y1, w1, h1 = ax1.get_position().bounds
x2, y2, w2, h2 = ax2.get_position().bounds
# set ax1 width to width of ax2
ax1.set_position([x1, y1, w2, h1])
I have 2 sets of rectangular patches in a plot. I want to name them separately. "Layer-1" for the bottom part and similarly "Layer-2" for the upper part. I wanted to set coordinates for the Y-axis but it did not work. Moreover i was not able to add the "Layer-2" text into the label. Please help.
I tried with the below mentioned code but it did not work.
plt.ylabel("LAYER-1", loc='bottom')
yaxis.labellocation(bottom)
One solution is to create a second axis, so called twin axis that shares the same x axis. Then it is possbile to label them separately. Furthermore, you can adjust the location of the label via
axis.yaxis.set_label_coords(-0.1, 0.75)
Here is an example that you can adjust to your desires. The result can be found here: https://i.stack.imgur.com/1o2xl.png
%matplotlib notebook
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
plt.rcParams['figure.dpi'] = 100
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y1 = 0.05 * x**2
y2 = -1 *y1
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(x, y1, 'g-')
ax2.plot(x, y2, 'b-')
# common x axis
ax1.set_xlabel('X data')
# First y axis label
ax1.set_ylabel('LAYER-1', color='g')
# Second y [enter image description here][1]axis label
ax2.set_ylabel('LAYER-2', color='b')
# Adjust the label location
ax1.yaxis.set_label_coords(-0.075, 0.25)
ax2.yaxis.set_label_coords(-0.1, 0.75)
plt.show()
I am trying to achieve generate plot made of subplots: plt.plot() and plt.matshow(), in which two plots had exactly the same size. What I mean is that lower border of one plot and lower borders of second plots were located on same "height". Similarly with the top border line. Current effect is presented on the plot below.
I haven't found any way in the available resources which would help me to achieve this effect. I would be grateful if you could help me.
shape=(2500, 2500)
matrix=np.zeros(shape)
print "Start of computing"
for x in range(shape[0]) :
for y in range(shape[1]) :
matrix[x, y]=shapeFuction((x-shape[0]/2)/13.0, (y-shape[1]/2)/13.0, 2.0e-4, 9e-5, 1.0)
print "Start of plotting"
fig=plt.figure()
ax = fig.add_subplot(1,2,2, aspect=1)
ax.matshow(matrix, cmap="autumn") #data[250:501,150:351])
ax.set(adjustable='datalim', aspect=1)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.xaxis.set_ticks_position('bottom')
ax.set(adjustable='box-forced') #adjustable='datalim'
ax.grid(b=False)
print "Start of plotting part 2"
ax = fig.add_subplot(1,2,1)
phase=(9.0e-5*np.power(np.arange(0, shape[1])-shape[1]/2,3 ))/7
g=ax.get_ylim()
asp=shape[1]/float(abs(g[0]-g[1]))
ax.plot(phase) #data[250:501,150:351])
ax.set(adjustable='box-forced')#, aspect=1.06/6.0) #adjustable='datalim''box-forced'
ax.set_xlabel("x")
ax.set_ylabel("Phase")
plt.savefig('testData-x3.png')
# plt.show()
One option you have is to set the aspect of the imshow plot (which is usually 1, such that pixels are squared), to "auto", ax2.imshow(z, cmap="autumn", aspect="auto").
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3,3)
y = np.tan(x)
z = np.random.rand(30,30)
fig, (ax, ax2) = plt.subplots(ncols=2)
ax.plot(x,y)
ax2.imshow(z, cmap="autumn", aspect="auto")
plt.show()
If instead you want to keep the aspect ratio of the image plot, you can change the aspect of the line plot by comparing the different axis limits,
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3,3)
y = np.tan(x)
z = np.random.rand(30,30)
fig, (ax, ax2) = plt.subplots(ncols=2)
ax.plot(x,y)
ax2.imshow(z, cmap="autumn")
ratio = np.diff(ax.get_ylim())[0]/np.diff(ax.get_xlim())[0]
ratio2 = np.diff(ax2.get_ylim())[0]/np.diff(ax2.get_xlim())[0]
aspect = ratio2/ratio
ax.set_aspect(float(np.abs(aspect)))
plt.show()
I have two graphs to where both have the same x-axis, but with different y-axis scalings.
The plot with regular axes is the data with a trend line depicting a decay while the y semi-log scaling depicts the accuracy of the fit.
fig1 = plt.figure(figsize=(15,6))
ax1 = fig1.add_subplot(111)
# Plot of the decay model
ax1.plot(FreqTime1,DecayCount1, '.', color='mediumaquamarine')
# Plot of the optimized fit
ax1.plot(x1, y1M, '-k', label='Fitting Function: $f(t) = %.3f e^{%.3f\t} \
%+.3f$' % (aR1,kR1,bR1))
ax1.set_xlabel('Time (sec)')
ax1.set_ylabel('Count')
ax1.set_title('Run 1 of Cesium-137 Decay')
# Allows me to change scales
# ax1.set_yscale('log')
ax1.legend(bbox_to_anchor=(1.0, 1.0), prop={'size':15}, fancybox=True, shadow=True)
Now, i'm trying to figure out to implement both close together like the examples supplied by this link
http://matplotlib.org/examples/pylab_examples/subplots_demo.html
In particular, this one
When looking at the code for the example, i'm a bit confused on how to implant 3 things:
1) Scaling the axes differently
2) Keeping the figure size the same for the exponential decay graph but having a the line graph have a smaller y size and same x size.
For example:
3) Keeping the label of the function to appear in just only the decay graph.
Any help would be most appreciated.
Look at the code and comments in it:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import gridspec
# Simple data to display in various forms
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
fig = plt.figure()
# set height ratios for subplots
gs = gridspec.GridSpec(2, 1, height_ratios=[2, 1])
# the first subplot
ax0 = plt.subplot(gs[0])
# log scale for axis Y of the first subplot
ax0.set_yscale("log")
line0, = ax0.plot(x, y, color='r')
# the second subplot
# shared axis X
ax1 = plt.subplot(gs[1], sharex = ax0)
line1, = ax1.plot(x, y, color='b', linestyle='--')
plt.setp(ax0.get_xticklabels(), visible=False)
# remove last tick label for the second subplot
yticks = ax1.yaxis.get_major_ticks()
yticks[-1].label1.set_visible(False)
# put legend on first subplot
ax0.legend((line0, line1), ('red line', 'blue line'), loc='lower left')
# remove vertical gap between subplots
plt.subplots_adjust(hspace=.0)
plt.show()
Here is my solution:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
fig, (ax1,ax2) = plt.subplots(nrows=2, sharex=True, subplot_kw=dict(frameon=False)) # frameon=False removes frames
plt.subplots_adjust(hspace=.0)
ax1.grid()
ax2.grid()
ax1.plot(x, y, color='r')
ax2.plot(x, y, color='b', linestyle='--')
One more option is seaborn.FacetGrid but this requires Seaborn and Pandas libraries.
Here are some adaptions to show how the code could work to add a combined legend when plotting a pandas dataframe. ax=ax0 can be used to plot on a given ax and ax0.get_legend_handles_labels() gets the information for the legend.
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
dates = pd.date_range('20210101', periods=100, freq='D')
df0 = pd.DataFrame({'x': np.random.normal(0.1, 1, 100).cumsum(),
'y': np.random.normal(0.3, 1, 100).cumsum()}, index=dates)
df1 = pd.DataFrame({'z': np.random.normal(0.2, 1, 100).cumsum()}, index=dates)
fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True, gridspec_kw={'height_ratios': [2, 1], 'hspace': 0})
df0.plot(ax=ax0, color=['dodgerblue', 'crimson'], legend=False)
df1.plot(ax=ax1, color='limegreen', legend=False)
# put legend on first subplot
handles0, labels0 = ax0.get_legend_handles_labels()
handles1, labels1 = ax1.get_legend_handles_labels()
ax0.legend(handles=handles0 + handles1, labels=labels0 + labels1)
# remove last tick label for the second subplot
yticks = ax1.get_yticklabels()
yticks[-1].set_visible(False)
plt.tight_layout()
plt.show()
I am trying to plot counts in gridded plots, but I haven't been able to figure out how to go about it.
I want:
to have dotted grids at an interval of 5;
to have major tick labels only every 20;
for the ticks to be outside the plot; and
to have "counts" inside those grids.
I have checked for potential duplicates, such as here and here, but have not been able to figure it out.
This is my code:
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
for key, value in sorted(data.items()):
x = value[0][2]
y = value[0][3]
count = value[0][4]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.annotate(count, xy = (x, y), size = 5)
# overwrites and I only get the last data point
plt.close()
# Without this, I get a "fail to allocate bitmap" error.
plt.suptitle('Number of counts', fontsize = 12)
ax.set_xlabel('x')
ax.set_ylabel('y')
plt.axes().set_aspect('equal')
plt.axis([0, 1000, 0, 1000])
# This gives an interval of 200.
majorLocator = MultipleLocator(20)
majorFormatter = FormatStrFormatter('%d')
minorLocator = MultipleLocator(5)
# I want the minor grid to be 5 and the major grid to be 20.
plt.grid()
filename = 'C:\Users\Owl\Desktop\Plot.png'
plt.savefig(filename, dpi = 150)
plt.close()
This is what I get.
I also have a problem with the data points being overwritten.
Could anybody PLEASE help me with this problem?
There are several problems in your code.
First the big ones:
You are creating a new figure and a new axes in every iteration of your loop →
put fig = plt.figure and ax = fig.add_subplot(1,1,1) outside of the loop.
Don't use the Locators. Call the functions ax.set_xticks() and ax.grid() with the correct keywords.
With plt.axes() you are creating a new axes again. Use ax.set_aspect('equal').
The minor things:
You should not mix the MATLAB-like syntax like plt.axis() with the objective syntax.
Use ax.set_xlim(a,b) and ax.set_ylim(a,b)
This should be a working minimal example:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# Major ticks every 20, minor ticks every 5
major_ticks = np.arange(0, 101, 20)
minor_ticks = np.arange(0, 101, 5)
ax.set_xticks(major_ticks)
ax.set_xticks(minor_ticks, minor=True)
ax.set_yticks(major_ticks)
ax.set_yticks(minor_ticks, minor=True)
# And a corresponding grid
ax.grid(which='both')
# Or if you want different settings for the grids:
ax.grid(which='minor', alpha=0.2)
ax.grid(which='major', alpha=0.5)
plt.show()
Output is this:
A subtle alternative to MaxNoe's answer where you aren't explicitly setting the ticks but instead setting the cadence.
import matplotlib.pyplot as plt
from matplotlib.ticker import (AutoMinorLocator, MultipleLocator)
fig, ax = plt.subplots(figsize=(10, 8))
# Set axis ranges; by default this will put major ticks every 25.
ax.set_xlim(0, 200)
ax.set_ylim(0, 200)
# Change major ticks to show every 20.
ax.xaxis.set_major_locator(MultipleLocator(20))
ax.yaxis.set_major_locator(MultipleLocator(20))
# Change minor ticks to show every 5. (20/4 = 5)
ax.xaxis.set_minor_locator(AutoMinorLocator(4))
ax.yaxis.set_minor_locator(AutoMinorLocator(4))
# Turn grid on for both major and minor ticks and style minor slightly
# differently.
ax.grid(which='major', color='#CCCCCC', linestyle='--')
ax.grid(which='minor', color='#CCCCCC', linestyle=':')