How to properly plot a line over bars? - python

This one used to work fine, but somehow it stopped working (I must have changed something mistakenly but I can't find the issue).
I'm plotting a set of 3 bars per date, plus a line that shows the accumulated value of one of them. But only one or another (either the bars or the line) is properly being plotted. If I left the code for the bars last, only the bars are plotted. If I left the code for the line last, only the line is plotted.
fig, ax = plt.subplots(figsize = (15,8))
df.groupby("date")["result"].sum().cumsum().plot(
ax=ax,
marker='D',
lw=2,
color="purple")
df.groupby("date")[selected_columns].sum().plot(
ax=ax,
kind="bar",
color=["blue", "red", "gold"])
ax.legend(["LINE", "X", "Y", "Z"])
Appreciate the help!

Pandas draws bar plots with the x-axis as categorical, so internally numbered 0, 1, 2, ... and then setting the label. The line plot uses dates as x-axis. To combine them, both need to be categorical. The easiest way is to drop the index from the line plot. Make sure that the line plot is draw first, enabling the labels to be set correctly by the bar plot.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({'date': pd.date_range('20210101', periods=10),
'earnings': np.random.randint(100, 600, 10),
'costs': np.random.randint(0, 200, 10)})
df['result'] = df['earnings'] - df['costs']
fig, ax = plt.subplots(figsize=(15, 8))
df.groupby("date")["result"].sum().cumsum().reset_index(drop=True).plot(
ax=ax,
marker='D',
lw=2,
color="purple")
df.groupby("date")[['earnings', 'costs', 'result']].sum().plot(
ax=ax,
kind="bar",
rot=0,
width=0.8,
color=["blue", "red", "gold"])
ax.legend(['Cumul.result', 'earnings', 'costs', 'result'])
# shorten the tick labels to only the date
ax.set_xticklabels([tick.get_text()[:10] for tick in ax.get_xticklabels()])
ax.set_ylim(ymin=0) # bar plots are nicer when bars start at zero
plt.tight_layout()
plt.show()

Here I post the solution:
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
a=[11.3,222,22, 63.8,9]
b=[0.12,-1.0,1.82,16.67,6.67]
l=[i for i in range(5)]
plt.rcParams['font.sans-serif']=['SimHei']
fmt='%.1f%%'
yticks = mtick.FormatStrFormatter(fmt)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.plot(l, b,'og-',label=u'A')
ax1.yaxis.set_major_formatter(yticks)
for i,(_x,_y) in enumerate(zip(l,b)):
plt.text(_x,_y,b[i],color='black',fontsize=8,)
ax1.legend(loc=1)
ax1.set_ylim([-20, 30])
ax1.set_ylabel('ylabel')
plt.legend(prop={'family':'SimHei','size':8})
ax2 = ax1.twinx()
plt.bar(l,a,alpha=0.1,color='blue',label=u'label')
ax2.legend(loc=2)
plt.legend(prop={'family':'SimHei','size':8},loc="upper left")
plt.show()
The key to this is the command
ax2 = ax1.twinx()

Related

I get an odd figure when I try to make a figure with both one (line)plot and a bar plot at one figure

I dont know how to handle matplotlib well.
I want to make a figure which has two data, one is line plot and the other is histogram.
And I cannot use seaborn due to my server issue for the time being.
This is my codes i've been writing.
fig, ax1 = plt.subplots()
ax1.plot(dat['frequency'], '-s', color='green', markersize=7, linewidth=5, alpha=0.7, label='frequency')
ax1.set_xlabel('Year')
ax1.set_ylabel('frequency')
ax2 = ax1.twinx()
ax2.hist(dat['PDO'], color='deeppink', label='PDO', alpha=0.7)
ax2.set_ylabel('PDO')
plt.show()
And for sure, two data has same x axis range but different y axis range.
(first one is like (0, 80) and the second one is like (-2, 1))
And the result is here below. It's literally weird.
I want to get a figure like this one, one figure with two data like this. But one is line plot and the other is bar plot.
How can I make a figure I really want?
I want to make a figure with two dataset, one is in line plot and the other is in histogram bar plot.
I've tried it quite a lot but couldn't make it.
If your x axis range is the same for both series, it should work:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({'Year': np.random.randint(2000, 2021, 1000),
'Value': np.random.randint(0, 100, 1000)})
# Create your own series, just an example
s1 = df.groupby('Year')['Value'].mean()
s2 = s1 / s1.max()
fig, ax1 = plt.subplots()
ax1.plot(s1.index, s1, '-s', color='green', markersize=7, linewidth=5, alpha=0.7, label='frequency')
ax1.set_xlabel('Year')
ax1.set_ylabel('frequency')
ax2 = ax1.twinx()
ax2.bar(s2.index, s2, color='deeppink', label='PDO', alpha=0.7) # bar and not hist
ax2.set_ylabel('PDO')
plt.show()
Output:

How to clean up x-axis values in matplotlib?

So I have the following code:
fig, ax = plt.subplots(dpi=220)
data.plot(kind='bar', y='p_1', ax=ax, color ='red')
data.plot(kind='bar', y='value_1', ax=ax, color ='blue')
ax.set_xlabel("Index values")
ax.set_ylabel("Value 1 / P_1")
#ax.legend(["Value 1, P_1"])
plt.title('Line plots')
plt.show()
Which returns the following graph:
As you can see the x-axis has some crazy stuff going on. I was wondering what went wrong and how to fix this?
Here's what you're looking for I think plt.xticks(positions, labels)
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
fig, ax = plt.subplots(dpi=220)
### used this to generate and test a new plot
data = pd.DataFrame(np.array(
[np.arange(50),
np.arange(50)]
).T).rename(columns={0: 'value_1', 1:'p_1'})
print(data)
data.plot(kind='bar', y='p_1', ax=ax, color ='red')
data.plot(kind='bar', y='value_1', ax=ax, color ='blue')
ax.set_xlabel("Index values")
ax.set_ylabel("Value 1 / P_1")
### added new code here
ticks = range(0, 50, 5)
labels = ticks
plt.xticks(ticks, labels)
#ax.legend(["Value 1, P_1"])
plt.title('Line plots')
plt.xticks(np.arange(0, len(value_1)+1, 5), np.arange(0, len(value_1)+1, 5) )
creates a tick every 5 intervals and corresponding label.

How to increase the size of xticks in pandas plot

This is a follow up for a question which i asked here:
The code is as follows:
from pandas_datareader import data as web
import matplotlib.pyplot as plt
import matplotlib.dates as md
fig, (ax1, ax2) = plt.subplots(2, 1)
df = web.DataReader('F', 'yahoo')
df2 = web.DataReader('Fb', 'yahoo')
ax = df.plot(figsize=(35,15), ax=ax1)
df2.plot(y = 'Close', figsize=(35,15), ax=ax2)
plt.xticks(fontsize = 25)
for ax in (ax1, ax2):
ax.xaxis.set_major_locator(md.MonthLocator(bymonth = range(1, 13, 6)))
ax.xaxis.set_major_formatter(md.DateFormatter('%b\n%Y'))
ax.xaxis.set_minor_locator(md.MonthLocator())
plt.setp(ax.xaxis.get_majorticklabels(), rotation = 0 )
plt.show()
This produces this plot:
How can i increase the size of both the xticks in the two subplots as you can see the size was increased for the bottom one only.
[1]: https://stackoverflow.com/questions/62358966/adding-minor-ticks-to-pandas-plot
You can use the tick_params function on the ax instance to control the size of the tick-labels on the x-axis. If you want to control the size of both x and y axis, use axis='both'. You can additionally specify which='major' or which='minor' or which='both' depending on if you want to change major, minor or both tick labels.
for ax in (ax1, ax2):
# Rest of the code
ax.tick_params(axis='x', which='both', labelsize=25)

Adjust y-axis in Seaborn multiplot

I'm plotting a CSV file from my simulation results. The plot has three graphs in the same figure fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(24, 6)).
However, for comparison purposes I want the y-axis in all graphs starting at zero and the ending at a specific value. I tried the solution mentioned here from the Seaborn author. I don't get any errors, but the solution also does not work for me.
Here's my script:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
fname = 'results/filename.csv'
def plot_file():
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(24, 6))
df = pd.read_csv(fname, sep='\t')
profits = \
df.groupby(['providerId', 'periods'], as_index=False)['profits'].sum()
# y-axis needs to start at zero and end at 10
g = sns.lineplot(x='periods',
y='profits',
data=profits,
hue='providerId',
legend='full',
ax=axes[0])
# y-axis need to start at zero and end at one
g = sns.scatterplot(x='periods',
y='price',
hue='providerId',
style='providerId',
data=df,
legend=False,
ax=axes[1])
# y-axis need to start at zero and end at one
g = sns.scatterplot(x='periods',
y='quality',
hue='providerId',
style='providerId',
data=df,
legend=False,
ax=axes[2])
g.set(ylim=(0, None))
plt.show()
print(g) # -> AxesSubplot(0.672059,0.11;0.227941x0.77)
The resulting figure is as follows:
How can I adjust each individual plot?
Based on the way you've written your code, you can refer to each subplot axis with g.axis and use g.axis.set_ylim(low,high). (A difference compared to the linked answer is that your graphs are not being plotted on a seaborn FacetGrid.)
An example using dummy data and different axis ranges to illustrate:
df = pd.DataFrame(np.random.uniform(0,10,(100,2)), columns=['a','b'])
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(8,4))
g = sns.lineplot(x='a',
y='b',
data=df.sample(10),
ax=axes[0])
g.axes.set_ylim(0,25)
g = sns.scatterplot(x='a',
y='b',
data=df.sample(10),
ax=axes[1])
g.axes.set_ylim(0,3.5)
g = sns.scatterplot(x='a',
y='b',
data=df.sample(10),
ax=axes[2])
g.axes.set_ylim(0,0.3)
plt.tight_layout()
plt.show()

Make single legend for two subplots of DataFrame

I create a plot with two axes on different subplots. Currently one overlays another. The problem is to make legend to contain both labels in stack. How can I do this?
d = data.groupby('atemp_rounded').sum().reset_index()
fig = plt.figure()
ax1 = fig.add_subplot(111) # don't know what 111 stands for...
ax2 = ax1.twinx()
d.plot(ax=ax1, y='casual')
d.plot(ax=ax2, y='registered', color='g')
plt.show()
You may set the legend of the individual plots off and instead create a figure legend. To have this placed within the axes boundaries the position needs to be specified in axes coordinates.
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({"A" : [3,2,1], "B" : [2,2,1]})
fig = plt.figure()
ax1 = fig.add_subplot(111) # don't know what 111 stands for...
ax2 = ax1.twinx()
df.plot(ax=ax1, y='A', legend=False)
df.plot(ax=ax2, y='B', color='g', legend=False)
fig.legend(loc="upper right", bbox_to_anchor=(0,0,1,1), bbox_transform=ax1.transAxes)
plt.show()

Categories

Resources