I'm working on Jupyter notebook, with recession data. I want to make a FloatSlider that takes values from a column(it contains 737 observations for Yield spreads between 1962-2020). Then I want to use that to interact it with another column and plot it. I want see how changing Yield spread on the slider will change the graph of the other variable.
I don't have any concrete code for this because I am still figuring if this is possible. Would appreciate any help!
So far I only have this:
def plot_func(m):
#m = m_clean['Yield_Spread'].tolist()
fig = plt.figure()
ax = fig.subplots()
ax.set_title('y_pred_Probit')
fig1 = ax.plot(m_clean['Yield_Spread'], color='blue', label = '' , linewidth = 2)
#ax2 = ax.twinx()
fig2= ax.plot(m_clean['y_pred_Probit'],color='brown', label = 'y_pred_Probit', linewidth = 2)
plt.show()
smoo = interact(plot_func, m = FloatSlider(min=0.0,max=1.0,step=0.5, continuous_update=True))
but I need to assign m as the values of Yield_Spread and I also want it to be updated using an update function.
Related
I am trying to create a figure with three bar plots side by side. These bar plots have different yscales, but the data is fundamentally similar so I'd like all the bars to have the same width.
The only way I was able to get the bars to have the exact same width was by using sharex when creating the subplots, in order to keep the same x scale.
import matplotlib.pyplot as plt
BigData = [[100,300],[400,200]]
MediumData = [[40, 30],[50,20],[60,50],[30,30]]
SmallData = [[3,2],[11,3],[7,5]]
data = [BigData, MediumData, SmallData]
colors = ['#FC766A','#5B84B1']
fig, axs = plt.subplots(1, 3, figsize=(30,5), sharex=True)
subplot = 0
for scale in data:
for type in range(2):
bar_x = [x + type*0.2 for x in range(len(scale))]
bar_y = [d[type] for d in scale]
axs[subplot].bar(bar_x,bar_y, width = 0.2, color = colors[type])
subplot += 1
plt.show()
This creates this figure:
The problem with this is that the x-limits of the plot are also shared, leading to unwanted whitespace. I've tried setting the x-bounds after the fact, but it doesn't seem to override sharex. Is there a way to make the bars have the same width, without each subplot also being the same width?
Additionally, is there a way to create such a plot (one with different y scales to depending on the size of the data) without having to sort the data manually beforehand, like shown in my code?
Thanks!
Thanks to Jody Klymak for help finding this solution! I thought I should document it for future users.
We can make use of the 'width_ratios' GridSpec parameter. Unfortunately there's no way to specify these ratios after we've already drawn a graph, so the best way I found to implement this is to write a function that creates a dummy graph, and measures the x-limits from that graph:
def getXRatios(data, size):
phig, aks = plt.subplots(1, 3, figsize=size)
subplot = 0
for scale in data:
for type in range(2):
bar_x = [x + type*0.2 for x in range(len(scale))]
bar_y = [d[type] for d in scale]
aks[subplot].bar(bar_x,bar_y, width = 0.2)
subplot += 1
ratios = [aks[i].get_xlim()[1] for i in range(3)]
plt.close(phig)
return ratios
This is essentially identical to the code that creates the actual figure, with the cosmetic aspects removed, as all we want from this dummy figure is the x-limits of the graph (something we can't get from our actual figure as we need to define those limits before we start in order to solve the problem).
Now all you need to do is call this function when you're creating your subplots:
fig, axs = plt.subplots(1, 3, figsize=(40,5), gridspec_kw = {'width_ratios':getXRatios(data,(40,5))})
As long as your XRatio function creates your graph in the same way your actual graph does, everything should work! Here's my output using this solution.
To save space you could re-purpose the getXRatios function to also construct your final graph, by calling itself in the arguments and giving an option to return either the ratios or the final figure. I couldn't be bothered.
Currently my chart is showing only the main big chart on the left.
However, I now want to add the two smaller plots to the right-hand side of my main plot; with each individual set of data.
I am struggling with subplots to figure out how to do this. My photo below shows my desired output.
filenamesK = glob("C:/Users/Ke*.csv")
filenamesZ = glob("C:/Users/Ze*.csv")
K_Z_Averages = {'K':[], 'Z':[]}
# We will create a function for plotting, instead of nesting lots of if statements within a long for-loop.
def plot_data(filename, fig_ax, color):
df = pd.read_csv(f, sep=',',skiprows=24) # Read in the csv.
df.columns=['sample','Time','ms','Temp1'] # Set the column names
df=df.astype(str) # Set the data type as a string.
df["Temp1"] = df["Temp1"].str.replace('\+ ', '').str.replace(' ', '').astype(float) # Convert to float
# Take the average of the data from the Temp1 column, starting from sample 60 until sample 150.
avg_Temp1 = df.iloc[60-1:150+1]["Temp1"].mean()
# Append this average to a K_Z_Averages, containing a column for average from each K file and the average from each Z file.
# Glob returns the whole path, so you need to replace 0 for 10.
K_Z_Averages[os.path.basename(filename)[0]].append(avg_Temp1)
fig_ax.plot(df[["Temp1"]], color=color)
fig, ax = plt.subplots(figsize=(20, 15))
for f in filenamesK:
plot_data(f, ax, 'blue')
for f in filenamesZ:
plot_data(f, ax, 'red')
plt.show()
#max 's answer is fine, but something you can also do matplotlib>=3.3 is
import matplotlib.pyplot as plt
fig = plt.figure(constrained_layout=True)
axs = fig.subplot_mosaic([['Left', 'TopRight'],['Left', 'BottomRight']],
gridspec_kw={'width_ratios':[2, 1]})
axs['Left'].set_title('Plot on Left')
axs['TopRight'].set_title('Plot Top Right')
axs['BottomRight'].set_title('Plot Bottom Right')
Note hw the repeated name 'Left' is used twice to indicate that this subplot takes up two slots in the layout. Also note the use of width_ratios.
This is a tricky question. Essentially, you can place a grid on a figure (add_gridspec()) and than open subplots (add_subplot()) in and over different grid elements.
import matplotlib.pyplot as plt
# open figure
fig = plt.figure()
# add grid specifications
gs = fig.add_gridspec(2, 3)
# open axes/subplots
axs = []
axs.append( fig.add_subplot(gs[:,0:2]) ) # large subplot (2 rows, 2 columns)
axs.append( fig.add_subplot(gs[0,2]) ) # small subplot (1st row, 3rd column)
axs.append( fig.add_subplot(gs[1,2]) ) # small subplot (2nd row, 3rd column)
I am trying to make a figure of some data and some limits as dashed lines.
The problem i have is that the values of limits are way too many and some
are repeated on the x-axis so what i get is something like a solid line.
I would like to ask you if there is any way to actually produce dashed line.
Thank you
My code is as follow and the image i produce
fig = plt.figure(dpi=300)
fig.set_size_inches(4, 2.36, forward=True)
ax = fig.add_subplot(111)
plt.scatter('SZA [deg]','SWD [W/m**2]', data = QC,
marker='o',color = 'k',s=0.1)
plt.plot('SZA [deg]','GLBMaxPhys', data = QC,
linestyle='--',color = 'r',linewidth = 0.5)
Here is one potential solution:
fig = plt.figure(dpi=300)
fig.set_size_inches(4, 2.36, forward=True)
ax = fig.add_subplot(111)
plt.scatter('SZA [deg]','SWD [W/m**2]', data = QC,
marker='o',color = 'k',s=0.1)
plt.plot('SZA [deg]','GLBMaxPhys', data = QC[::50], ##change this number
linestyle='--',color = 'r',linewidth = 0.5)
You could use the markevery option in the plot call.
plt.plot(..., marker='o', markevery=5, ...)
This will only mark every 5th point.
You can check the documentation here.
I want to color the line in a plot based on the following of a data set on the y axis.
if data > 0:
color = 'r'
if data = 0:
color = 'g'
if data < 0:
color = 'b'
Unfortunately I only know how to color the entire data set one color. I also couldn't find anything on the web. I'm assuming there is a way to do this without breaking up the dataset for every time the color changes.
Below is an example of plotting the data with just one color.
import matplotlib.pyplot as plt
import numpy as np
# Simple data
x = np.linspace(0, 2 * np.pi, 400)
data = np.sin(x ** 2)
#plot
f, ax = plt.subplots()
ax.plot(x, data, color='r')
plt.show()
The color parameter actually can take a list as an argument. For example, here's a simple bit of code that sets up a list of colors based on whether the data is positive or negative:
colors = []
for item in data:
if item < 0:
colors.append('r')
else:
colors.append('g')
then simply:
ax.bar(x, data, color=colors)
Edit: So I tested it, and it appears that my answer is only applicable for bar graphs. I couldn't find anything in the matplotlib documentation that seemed to indicate that coloring a line plot with multiple colors was possible. I did, however find this site, which I believe has the information you want. The guy there defines his own function to achieve it.
Using the file at my link, here is an equivalent version for a line graph:
cmap = ListedColormap(['r', 'g']) # use the colors red and green
norm = BoundaryNorm([-1000,0,1000], cmap.N) # map red to negative and green to positive
# this may work with just 0 in the list
fig, axes = plt.subplots()
colorline(x, data, data, cmap=cmap, norm=norm)
plt.xlim(x.min(), x.max())
plt.ylim(data.min(), data.max())
plt.show()
The last three arguments of colorline here tell it the color data and how to map it.
I make a loop over two cases and for each case I try to make a plot.
for col_name in ['col2','col3']:
x_min = min(df['col1'].min(), df[col_name].min())
x_max = max(df['col1'].max(), df[col_name].max())
plt.xlim([x_min,x_max])
plt.ylim([x_min,x_max])
plt.axes().set_aspect('equal')
plt.scatter(df['col1'], df[col_name])
As a result I get one plot in my IPython notebook. Does anyone know how to overcome this problem?
You need to call figure() more than once.
for col_name in ['col2','col3']:
plt = figure() #This gives you a new figure to plot in
x_min = min(df['col1'].min(), df[col_name].min())
x_max = max(df['col1'].max(), df[col_name].max())
plt.xlim([x_min,x_max])
plt.ylim([x_min,x_max])
plt.axes().set_aspect('equal')
plt.scatter(df['col1'], df[col_name])
I would just use two figures if I want them on different windows.
Something like this ought to work.
>>> for i in range(3):
xAxis = [randint(1, 5) for _ in range(10)]
plt.figure(1)
plt.plot(xAxis)
plt.show()
xAxis2 = [randint(1, 5) for _ in range(10)]
plt.figure(2)
plt.plot(xAxis2)
plt.show()
It gave me six consecutive figures.
Since, you need a new figure for every iteration, do.
for index, col_name in ['col2','col3']:
plt.figure(index)
# Do the plotting.