Python - Pyplot x-axis not showing on graph - python

pyplot is not showing the x-axis on the graph:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('sitka_weather_2014.csv')
df['AKST'] = pd.to_datetime(df.AKST)
df['Dates'] = df['AKST'].dt.strftime('%b %d, %Y')
df.set_index("Dates", inplace= True)
# Plot Data
fig = plt.figure(dpi=256, figsize=(14, 7))
plt.title("Daily high and low temperature - 2014")
df['Max TemperatureF'].plot(linewidth=1, c='blue', label="Max Temperature °F")
df['Min TemperatureF'].plot(linewidth=1, c='red', label="Min Temperature °F")
plt.grid(True)
plt.rc('grid', linestyle=":", linewidth=1, color='gray')
plt.legend(loc='upper left')
plt.xlabel('', fontsize=10)
plt.ylabel("Temperature (°F)", fontsize=10)
plt.tick_params(axis='both', which='major', labelsize=10)
fig.autofmt_xdate(rotation=45)
plt.show()
The x-axis should be the index of the Pandas Dataframe (df) containing the dates.

Your code is actually fine. I tried to run it with the necessary sitka_weather_2014.csv file and it works.
The problem is that you can't see the x-axis because the size of the figure is too big, and thus the description of the x-axis dissapears. Try to scale your figure e.g. by making the dpi smaller:
fig = plt.figure(dpi=100, figsize=(14, 7)) #dpi=100 instead of dpi=256
Or make the labelsize smaller:
plt.tick_params(axis='both', which='major', labelsize=5) #labelsize=5 instead of labelsize=10
Whatever works best for you. But the code is fine and the description of the x-axis is showing.

You have your xlabel value set to null:
plt.xlabel('', fontsize=10)

Related

Plotting two weeks of pandas time series data on single axis in matplotlib

I have two datasets that each cover one week. z1 is from 2022-02-07 to 2022-02-14, and z2 is from 2022-01-31 to 2022-02-07. So they both start on a Monday and end on the next Monday.
I want to plot z1 and z2 so they share the same x and y axes, with xticklabels showing Mon, Tue, etc. How do I do this?
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
z1 = pd.DataFrame(data={'datetime': pd.date_range(start='2022-02-07',end='2022-02-14',freq='1H'), 'data1': np.random.randint(5,40,size=337)})
z1 = z1.set_index('datetime')
z1['day'] = z1.index.day_name()
z2 = pd.DataFrame(data={'datetime': pd.date_range(start='2022-01-31',end='2022-02-07',freq='1H'), 'data2': np.random.randint(22,31,size=337)})
z2 = z2.set_index('datetime')
z2['day'] = z2.index.day_name()
plt.figure(figsize=(14,6))
ax = plt.subplot(111)
ax2 = ax.twinx()
z1.plot(ax=ax, label='this week', lw=2, color='b', x_compat=True)
z2.plot(ax=ax2, label='last week', lw=2, color='r', x_compat=True)
# ax.plot(z1['day'], z1['data1'], label='this week', lw=2, color='b')
# ax2.plot(z2['day'], z2['data2'], label='last week', lw=2, color='r')
ax.xaxis.set_major_locator(mdates.DayLocator())
xfmt = mdates.DateFormatter('%a')
ax.xaxis.set_major_formatter(xfmt)
ax.tick_params(axis="x", rotation=0)
ax.legend()
ax2.legend()
plt.show()
but I want this:
I don't think it is possible to make a single graph for each of the pandas plots since they have different indices.
Using matplotlib, the x-axis should be continuous data using the number of data points. After creating the graph, set_xticks to 24 tick points where the day of the week changes. set_xticklabels to use the day of the week of either data frame and use it as a tick label for each of the 24 ticks.
fig, ax = plt.subplots(figsize=(14,6))
ax = plt.subplot(111)
ax2 = ax.twinx()
ax.plot(np.arange(169), z1['data1'], label='this week', lw=2, color='b')
ax2.plot(np.arange(169), z2['data2'], label='last week', lw=2, color='r')
ax.set_xticks(np.arange(0,169,24))
ax.set_xticklabels(z1.day[::24])
ax.tick_params(axis="x", rotation=0)
fig.legend(bbox_to_anchor=(0.12, 0.12, 0.1, 0.1))
plt.show()

How to change the order of categorical x-axis in interaction plot in python?

So I am generating the interaction plot by using statsmodels package.
Here in the figure below, you can see my current result.
I would like to have first "Block" and second "Alternating" in my x-axis. I was wondering how to make this change?
Here is my code:
from statsmodels.graphics.factorplots import interaction_plot
import matplotlib.pyplot as plt
fig = interaction_plot(x=d['Group'], trace=d['Condition'], response=d['Asynch'],
colors=['blue','yellow','green','gray'])
plt.rc("figure")
plt.rc('xtick', labelsize=24)
plt.rc('ytick', labelsize=24)
plt.xlabel('Condition', fontsize=28)
plt.ylabel('IRI (ms)', fontsize=28)
sns.set(font_scale = 1.4)
plt. legend(loc='upper center', prop={'size': 24})
plt.legend(loc='upper right')
plt.ylabel("Asynchrony (ms)")
plt.show()
# plt.savefig('interaction.png', dpi=300)
fig.savefig('interaction.png', dpi=600)
and here is the result:
My interaction plot

Adjusting legend layout for multiple legends associated to one Python plot?

I am creating a Python plot from a dataframe with 3 y-axes. For each y-axis, there are multiple y-values I want to plot. All data sets for the y-axes are plotted against a shared Date x-axis.
The code looks as follows:
df = pd.read_excel (r'test.xlsx', sheet_name='test', engine='openpyxl')
fig, ax = plt.subplots()
ax3 = ax.twinx()
rspine = ax3.spines['right']
rspine.set_position(('axes', 1.15))
ax3.set_frame_on(True)
ax3.patch.set_visible(False)
fig.subplots_adjust(right=0.7)
ax.plot(df['Date'], df['Gas1'], label="Gas1", color='g')
ax.plot(df['Date'], df['Gas2'], label="Gas2", color='b')
ax.plot(df['Date'], df['Gas3'], label="Gas3", marker="o", markersize=2, color='r')
ax.set_xlabel("Date")
ax.set_ylabel("Gas Rate")
ax2 = ax.twinx()
ax2.plot(df['Date'], df['Water1'], label="Water1", color='k')
ax2.plot(df['Date'], df['Water2'], label="Water2", color='y')
ax2.set_ylabel("Water")
ax3.plot(df['Date'], df['Pressure1'], label="Pressure1")
ax3.plot(df['Date'], df['Pressure2'], label="Pressure2")
ax3.set_ylabel("Pressure")
ax.legend()
ax2.legend()
ax3.legend()
plt.show()
The problem I am having is that I want the legends to be outside of the plot, preferably on the right-hand side after the 2nd y-axis. Is this possible? Right now the legends are just overlayed on the plot and not fully visible. I have tried using bbox_to_anchor and loc functions but had no luck. Thank you!
ax.get_legend_handles_labels() collects all the legend handles and their labels. Combining those for each of the axes, a new legend can be created.
bbox_to_anchor= sets an anchor point for the legend, using axes coordinates. loc= needs to be set, to tell which point of the legend's box will get fixed by the anchor.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame({'Date': pd.date_range('20210401', periods=30, freq='D'),
'Gas1': np.random.randn(30).cumsum(),
'Gas2': np.random.randn(30).cumsum(),
'Gas3': np.random.randn(30).cumsum(),
'Water1': np.random.randn(30).cumsum(),
'Water2': np.random.randn(30).cumsum(),
'Pressure1': np.random.randn(30).cumsum(),
'Pressure2': np.random.randn(30).cumsum()})
fig, ax = plt.subplots()
ax3 = ax.twinx()
rspine = ax3.spines['right']
rspine.set_position(('axes', 1.15))
ax3.set_frame_on(True)
ax3.patch.set_visible(False)
fig.subplots_adjust(right=0.7)
ax.plot(df['Date'], df['Gas1'], label="Gas1", color='g')
ax.plot(df['Date'], df['Gas2'], label="Gas2", color='b')
ax.plot(df['Date'], df['Gas3'], label="Gas3", marker="o", markersize=2, color='r')
ax.set_ylabel("Gas Rate")
plt.setp(ax.get_xticklabels(), rotation=45, ha='right')
ax2 = ax.twinx()
ax2.plot(df['Date'], df['Water1'], label="Water1", color='k')
ax2.plot(df['Date'], df['Water2'], label="Water2", color='y')
ax2.set_ylabel("Water")
ax3.plot(df['Date'], df['Pressure1'], label="Pressure1")
ax3.plot(df['Date'], df['Pressure2'], label="Pressure2")
ax3.set_ylabel("Pressure")
handles1, labels1 = ax.get_legend_handles_labels()
handles2, labels2 = ax2.get_legend_handles_labels()
handles3, labels3 = ax3.get_legend_handles_labels()
ax.legend(handles=handles1 + handles2 + handles3,
labels=labels1 + labels2 + labels3,
bbox_to_anchor=(1.28, 1.02), loc='upper left')
plt.tight_layout()
plt.show()

how to animate a scatterplot of pandas data with matplotlib

I'm currently trying to animate a scatterplot of monthly data saved in a pandas dataframe. So far I made loop, which generates one single plot after another. Now I would like to join them in a single gif (or mp4 I don't care). Is there an easy way to make use of mathplotlibs animation function? I can't get my head around, how to loop sliced data through FuncAnimation. So far I did this:
time = df.monat.unique()
for i in time:
dft = df[(df.monat == i) & (df.xcol < 4000)]
plt.scatter(x=dft['xcol'],
y=dft['ycol'],
s=dft['scol'] / 25,
c=dft['clr'],
linewidth=0,
alpha=0.8)
plt.title('Title ' + str(i), fontsize=10)
plt.xlabel('x label', fontsize=9)
plt.ylabel('y label', fontsize=9)
legend1_line2d = list()
for val in clrdict.values():
legend1_line2d.append(mlines.Line2D([0], [0],
linestyle='none',
marker='o',
alpha=0.6,
markersize=6,
markeredgecolor=None,
markeredgewidth=0,
markerfacecolor=val))
legend1 = plt.legend(legend1_line2d,
names,
frameon=False,
numpoints=1,
fontsize=8,
loc='upper right')
plt.show()
I figured it out by myself:
Generate an empty plot (fig). Like before all unique time-values are stored in a series(time). A simple counter (i) helps generating the correct slice of the data (dft) for each month (df.monat == a value from the series 'time') within the update-function. The update-function is called times the value of the frame-parameter in the anim.FuncAnimation (frames=len(time)).
Hope, this will be helpful for somebody else (most of the explanations for the matplotlib FuncAnimation I've found worked with random numbers - not with specific pandas columns):
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
import matplotlib.animation as anim
...
time = df.monat.unique()
fig = plt.figure()
i = 1
def update(i):
plt.clf()
dft = df[(df.monat == time[i]) & (df.xcol < 4000)]
plt.scatter(x=dft['xcol'],
y=dft['ycol'],
s=dft['scol'] / 25,
c=dft['clr'],
linewidth=0,
alpha=0.8)
plt.title('Title ' + str(time[i]), fontsize=10)
plt.xlabel('x label', fontsize=9)
plt.ylabel('y label', fontsize=9)
plt.xlim(0, 900) # fixed dimensions x
plt.ylim(-5, 100) # fixed dimensions y
legend1_line2d = list()
for val in clrdict.values():
legend1_line2d.append(mlines.Line2D([0], [0],
linestyle='none',
marker='o',
alpha=0.6,
markersize=6,
markeredgecolor=None,
markeredgewidth=0,
markerfacecolor=val))
legend1 = plt.legend(legend1_line2d,
names,
frameon=False,
numpoints=1,
fontsize=8,
loc='upper right')
i += 1
ani = anim.FuncAnimation(fig, update, frames=len(time), interval=500)
# plt.show() # this will show the ani over and over
ani.save("test.mp4", dpi=200, fps=1, codec="libx264", bitrate=5000, extra_args=['-pix_fmt', 'yuv420p'])

Unable to generate legend using python / matlibplot for 4 lines all labelled

Want labels for Bollinger Bands (R) ('upper band', 'rolling mean', 'lower band') to show up in legend. But legend just applies the same label to each line with the pandas label for the first (only) column, 'IBM'.
# Plot price values, rolling mean and Bollinger Bands (R)
ax = prices['IBM'].plot(title="Bollinger Bands")
rm_sym.plot(label='Rolling mean', ax=ax)
upper_band.plot(label='upper band', c='r', ax=ax)
lower_band.plot(label='lower band', c='r', ax=ax)
#
# Add axis labels and legend
ax.set_xlabel("Date")
ax.set_ylabel("Adjusted Closing Price")
ax.legend(loc='upper left')
plt.show()
I know this code may represent a fundamental lack of understanding of how matlibplot works so explanations are particularly welcome.
The problem is most probably that whatever upper_band and lower_band are, they are not labeled.
One option is to label them by putting them as column to a dataframe. This will allow to plot the dataframe column directly.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
y =np.random.rand(4)
yupper = y+0.2
ylower = y-0.2
df = pd.DataFrame({"price" : y, "upper": yupper, "lower": ylower})
fig, ax = plt.subplots()
df["price"].plot(label='Rolling mean', ax=ax)
df["upper"].plot(label='upper band', c='r', ax=ax)
df["lower"].plot(label='lower band', c='r', ax=ax)
ax.legend(loc='upper left')
plt.show()
Otherwise you can also plot the data directly.
import matplotlib.pyplot as plt
import numpy as np
y =np.random.rand(4)
yupper = y+0.2
ylower = y-0.2
fig, ax = plt.subplots()
ax.plot(y, label='Rolling mean')
ax.plot(yupper, label='upper band', c='r')
ax.plot(ylower, label='lower band', c='r')
ax.legend(loc='upper left')
plt.show()
In both cases, you'll get a legend with labels. If that isn't enough, I recommend reading the Matplotlib Legend Guide which also tells you how to manually add labels to legends.

Categories