Only one dataname shows in the legend - python

I like to display a diagram of two data columns. The problem about it is that the legend shows only the last name l/s.
Here is my diagram:
import pandas as pd
import matplotlib.pyplot as plt
Tab = pd.read_csv('Mst01.csv', delimiter=';')
x = Tab['Nr. ']
y1 = Tab['cm']
y2 = Tab['l/s']
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(x, y1, 'g-', label='cm')
ax2.plot(x, y2, 'b-', label='l/s')
ax1.set_xlabel('Nr.')
ax1.set_ylabel('cm', color='g')
ax2.set_ylabel('l/s', color='b')
plt.title('Mst01')
plt.legend()
plt.show()
If I do
ax1.legend()
ax2.legend()
both legends will displayed but one above the other.
By the way, is there a easyier way the get the spaces for every line of code?

Good evening!
so you got two possibilities either you add the plots together or you use fig.legend()
here is some sample code which yields to the solution
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# Create Example Dataframe
dummy_data = np.random.random_sample((100,2))
df = pd.DataFrame(dummy_data, columns=['Col_1', 'Col_2'])
df.Col_2 = df.Col_2*100
# Create Figure
fig, ax = plt.subplots()
col_1 = ax.plot(df.Col_1, label='Col_1', color='green')
ax_2 = ax.twinx()
col_2 = ax_2.plot(df.Col_2, label='Col_2', color='r')
# first solution
lns = col_1+col_2
labs = [l.get_label() for l in lns]
ax.legend(lns, labs, loc='upper right')
# secound solution
fig.legend()
fig
The solution can be derived from this question.
What do you mean by spaces? you mean the indention of e.g. a for loop?

Related

Markers in beginning and end of line plots

I have 5 datasets that have thousands of x and y coordinates grouped by 'frame' that create 5 trajectory plots. I'd like to mark the first and last coordinates for each plot but having difficulty figuring it out. I am using Jupiter Notebook.
mean_pos1 = gr1.mean()
mean_pos2 = gr2.mean()
mean_pos3 = gr3.mean()
mean_pos4 = gr4.mean()
mean_pos5 = gr5.mean()
plt.figure()
xlim=(200, 1500)
ylim=(0, 1200)
ax1 = mean_pos1.plot(x='x', y='y',color='blue',label='Dolphin A'); ax1.set_title('mean trajectory');
ax2 = mean_pos2.plot(x='x', y='y',color='red',label='Dolphin B'); ax2.set_title('mean trajectory');
ax3 = mean_pos3.plot(x='x', y='y',color='green',label='Dolphin C'); ax3.set_title('mean trajectory');
ax4 = mean_pos4.plot(x='x', y='y',color='magenta',label='Dolphin D'); ax4.set_title('mean trajectory');
ax5 = mean_pos5.plot(x='x', y='y',color='cyan',label='Dolphin E'); ax5.set_title('mean trajectory');
ax1.set_xlim(xlim)
ax1.set_ylim(ylim)
ax2.set_xlim(xlim)
ax2.set_ylim(ylim)
ax3.set_xlim(xlim)
ax3.set_ylim(ylim)
ax4.set_xlim(xlim)
ax4.set_ylim(ylim)
ax5.set_xlim(xlim)
ax5.set_ylim(ylim)
plt.show()
the output of them looks like this:
Use the scatter method to plot the markers separately on the same axis by grabbing the first and last elements from your x and y series:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({'x': np.random.normal(3,0.2,10), 'y': np.random.normal(5,0.3,10)})
fig, ax = plt.subplots()
df.plot(x='x', y='y', ax=ax)
ax.scatter(df['x'].iloc[0], df['y'].iloc[0], marker='o', color='red')
ax.scatter(df['x'].iloc[-1], df['y'].iloc[-1], marker='o', color='red')
plt.show()

python - repositioning my legend using loc

this is the output of my code
as you can see both legends 'pl' and 'ppl' are overlapping at the top right. How do I get one of them to move to top left.
I tried searching for ans, and used "loc" to fix the issue, somehow I continue getting error. Can someone help please?
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax1.set_xlabel('Date')
ax1.set_ylabel('percent change / 100')
dd = pd.DataFrame(np.random.randint(1,10,(30,2)),columns=['pl','ppl'])
dd['pl'].plot(ax=ax1,legend=True)
dd['ppl'].plot(ax=ax2, style=['g--', 'b--', 'r--'],legend=True)
ax2.set_ylabel('difference')
plt.show()
Perhaps plot directly with matplotlib instead of using DataFrame.plot:
ax1.plot(dd['pl'], label='pl')
ax1.legend(loc='upper left')
ax2.plot(dd['ppl'], ls='--', c='g', label='ppl')
ax2.legend(loc='upper right')
Output:
I think you need to call legend on plot and position the legend accordingly. Please see below.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax1.set_xlabel('Date')
ax1.set_ylabel('percent change / 100')
dd = pd.DataFrame(np.random.randint(1,10,(30,2)),columns=['pl','ppl'])
dd['pl'].plot(ax=ax1, legend=True).legend(loc='center left',bbox_to_anchor=(1.0, 0.5))
dd['ppl'].plot(ax=ax2, style=['g--', 'b--', 'r--'],legend=True).legend(loc='upper right')
You can create the legend in several ways:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax1.set_xlabel("Date")
ax1.set_ylabel("percent change / 100")
dd = pd.DataFrame(np.random.randint(1, 10, (30, 2)), columns=["pl", "ppl"])
dd["pl"].plot(ax=ax1)
dd["ppl"].plot(ax=ax2, style=["g--", "b--", "r--"])
# # two separate legends
# ax1.legend()
# ax2.legend(loc="upper left")
# # a single legend for the whole fig
# fig.legend(loc="upper right")
# # a single legend for the axis
# get the lines in the axis
lines1 = ax1.lines
lines2 = ax2.lines
all_lines = lines1 + lines2
# get the label for each line
all_labels = [lin.get_label() for lin in all_lines]
# place the legend
ax1.legend(all_lines, all_labels, loc="upper left")
ax2.set_ylabel("difference")
plt.show()
The last one I left uncommented creates a single legend inside the ax, with both lines listed.
Cheers!

Error while updating a plot + How to improve its appearance

I have this code:
import matplotlib.pyplot as plt
import numpy as np
dat=[0,40]
fig = plt.figure()
ax = fig.add_subplot(111)
ax2 = fig.add_subplot(211)
Ln, = ax.plot(dat)
Ln2, = ax2.plot(dat)
plt.ion()
plt.show()
x, xx = [], []
for i in range(20):
x.append(i / 2)
xx = [np.cos(a) for a in x[-10:]]
x.extend(xx)
ax.set_xlim(0, len(x)+5)
ax.set_ylim(min(x), max(x)+5)
Ln.set_ydata(x)
Ln.set_xdata(range(len(x)))
x = x[:-len(xx)]
ax2.set_xlim(0, len(x)+5)
ax2.set_ylim(min(x), max(x)+5)
Ln2.set_ydata(x)
Ln2.set_xdata(range(len(x)))
plt.pause(0.5)
If you run it, you'll see:
That ax2 is plotting upside, while it should be below.
How each subplot overlaps the other.
This is a screenshot of the result:
I want it to be more "good loocking", but I've searched and I just don't know where to start. I'd appreciate your help!
You got the indexes wrong, it should be:
ax = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
from the docs:
first digit is the number of rows, the second the number of columns,
and the third the index of the subplot

Putting several plots side by side

I have 9 histograms made with matplotlib.pyplot.
Is there an easy way to "stick" them to each other, so that every new histogram would not start with a new row?
Data: data
Providing code:
for column in data:
plt.figure(figsize=(5,5))
a1 = data[(data['Outcome'] == 0)][column]
a2 = data[(data['Outcome'] == 1)][column]
ax = np.linspace(0, data[column].max(), 50)
plt.hist(a1, ax, color='blue', alpha=0.6, label='Have Diabetes = NO')
plt.hist(a2, ax, color='yellow', alpha=0.6, label='Have Diabetes = YES')
plt.title(f'Histogram for {column}')
plt.xlabel(f'{column}')
plt.ylabel('number of people')
plt.grid(True)
leg = plt.legend(loc='upper right', frameon=True)
What I want is something like this:
I actually don't need it to be 3x3, just not go in a column. Is it possible? Thanks for any possible help.
You need to assign the plots to ax , and also it will be set_title etc:
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
data = pd.read_csv("datasets_228_482_diabetes.csv")
fig,ax = plt.subplots(3,3,figsize=(9,9))
ax = ax.flatten()
for i,column in enumerate(data.columns):
a1 = data[(data['Outcome'] == 0)][column]
a2 = data[(data['Outcome'] == 1)][column]
ax[i].hist(a1, color='blue', alpha=0.6, label='Have Diabetes = NO')
ax[i].hist(a2, color='yellow', alpha=0.6, label='Have Diabetes = YES')
ax[i].set_title('Histogram for '+column)
ax[i].set_xlabel(f'{column}')
ax[i].set_ylabel('number of people')
ax[i].legend(loc='upper right',frameon=True,markerscale=7,fontsize=7)
fig.tight_layout()
As you can see, the last column outcome is pretty useless, so if you don't plot that, you can also consider using seaborn:
g = sns.FacetGrid(data=data.melt(id_vars="Outcome"),
col="variable",hue="Outcome",sharex=False,sharey=False,
col_wrap=4,palette=['blue','yellow'])
g = g.map(plt.hist,"value",alpha=0.7)
I think you should be plotting using axes rather than pyplot:
from matplotlib import pyplot as plt
fig, axes = plt.subplots(3,3, figsize=(9,9))
for d, ax in zip(data_list, axes.ravel()):
ax.hist(d) # or something similar

Seaborn plot with second y axis

i wanted to know how to make a plot with two y-axis so that my plot that looks like this :
to something more like this by adding another y-axis :
i'm only using this line of code from my plot in order to get the top 10 EngineVersions from my data frame :
sns.countplot(x='EngineVersion', data=train, order=train.EngineVersion.value_counts().iloc[:10].index);
I think you are looking for something like:
import matplotlib.pyplot as plt
x = [1,2,3,4,5]
y = [1000,2000,500,8000,3000]
y1 = [1050,3000,2000,4000,6000]
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.bar(x, y)
ax2.plot(x, y1, 'o-', color="red" )
ax1.set_xlabel('X data')
ax1.set_ylabel('Counts', color='g')
ax2.set_ylabel('Detection Rates', color='b')
plt.show()
Output:
#gdubs If you want to do this with Seaborn's library, this code set up worked for me. Instead of setting the ax assignment "outside" of the plot function in matplotlib, you do it "inside" of the plot function in Seaborn, where ax is the variable that stores the plot.
import seaborn as sns # Calls in seaborn
# These lines generate the data to be plotted
x = [1,2,3,4,5]
y = [1000,2000,500,8000,3000]
y1 = [1050,3000,2000,4000,6000]
fig, ax1 = plt.subplots() # initializes figure and plots
ax2 = ax1.twinx() # applies twinx to ax2, which is the second y axis.
sns.barplot(x = x, y = y, ax = ax1, color = 'blue') # plots the first set of data, and sets it to ax1.
sns.lineplot(x = x, y = y1, marker = 'o', color = 'red', ax = ax2) # plots the second set, and sets to ax2.
# these lines add the annotations for the plot.
ax1.set_xlabel('X data')
ax1.set_ylabel('Counts', color='g')
ax2.set_ylabel('Detection Rates', color='b')
plt.show(); # shows the plot.
Output:
Seaborn output example
You could try this code to obtain a very similar image to what you originally wanted.
import seaborn as sb
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle
x = ['1.1','1.2','1.2.1','2.0','2.1(beta)']
y = [1000,2000,500,8000,3000]
y1 = [3,4,1,8,5]
g = sb.barplot(x=x, y=y, color='blue')
g2 = sb.lineplot(x=range(len(x)), y=y1, color='orange', marker='o', ax=g.axes.twinx())
g.set_xticklabels(g.get_xticklabels(), rotation=-30)
g.set_xlabel('EngineVersion')
g.set_ylabel('Counts')
g2.set_ylabel('Detections rate')
g.legend(handles=[Rectangle((0,0), 0, 0, color='blue', label='Nontouch device counts'), Line2D([], [], marker='o', color='orange', label='Detections rate for nontouch devices')], loc=(1.1,0.8))

Categories

Resources