Legend markers appear several times - python

I need to plot data sites on a map. For example, survey "DEPROAS" has five stations so, I need to plot'em and insert it in legend guide. But, when I do this, instead of plotting just once (representative of these five stations), It plots five dots. Any idea? Figure and code below.
#### DEPROAS #### - Cabo Frio
fcf1=[-22-(59.030/60),-42-(07.340/60)]
fcf2=[-23-(05.444/60),-41-(54.700/60)]
fcf=[fcf1,fcf2]
fcf=np.array(fcf)
lat_fcf = fcf[0:len(fcf),0]
lon_fcf = fcf[0:len(fcf),1]
x_fcf,y_fcf=m(lon_fcf,lat_fcf)
plt.plot(x_fcf[0],y_fcf[0], 'o', label='DEPROAS', color='#88ff4d', zorder = 3000)
plt.plot(x_fcf[1],y_fcf[1], 'o', label='DEPROAS', color='#88ff4d', zorder = 3000)
#### DEPROAS #### - Ubatuba
fub1=[-23-(43.560/60),-44-(53.860/60)]
fub2=[-24-(04.028/60),-44-(39.005/60)] ##rever nos dados no lab
fub=[fub1,fub2]
fub=np.array(fub)
lat_fub = fub[0:len(fub),0]
lon_fub = fub[0:len(fub),1]
x_fub,y_fub=m(lon_fub,lat_fub)
plt.plot(x_fub[0],y_fub[0], 'o', label = 'DEPROAS', color='#88ff4d', zorder = 3000)
plt.plot(x_fub[1],y_fub[1], 'o', label = 'DEPROAS', color='#88ff4d', zorder = 3000)
#### DEPROAS #### - Guanabara
fbg1=[-23-(18.34/60),-42-(45.81/60)]
fbg=[fbg1]
fbg=np.array(fbg)
lat_fbg = fbg[0:len(fbg),0]
lon_fbg = fbg[0:len(fbg),1]
x_fbg,y_fbg=m(lon_fbg,lat_fbg)
plt.plot(x_fbg[0],y_fbg[0], 'o', label = 'DEPROAS', color='#88ff4d', zorder = 3000)

You plot 5 series with label "DEPROAS" therefore your legend has 5 entries of all these markers and labels.
According to legend guide you have to construct custom legend and put all desired series to a list and plot it in a legend:
...
series1, = plt.plot(x_fub[0],y_fub[0], 'o', label = 'DEPROAS', color='#88ff4d', zorder = 3000)
plt.plot(x_fub[1],y_fub[1], 'o', label = 'DEPROAS', color='#88ff4d', zorder = 3000)
# make custom legend for series1
plt.legend(handles=[series1], loc=2)
...

Related

How to resize the x-axis and make it different from the y-axis Matplotlib

I have the following development that I am working on with ElementTree, Pandas and Matplotlib modules in Python:
def extract_name_value(signals_df):
#print(signals_df)
names_list = [name for name in signals_df['Name'].unique()]
num_names_list = len(names_list)
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
# Creation Graphic
fig = plt.figure(figsize=(18, 20))
plt.suptitle(f'File PXML: {rootXML}', fontsize=20, fontweight='bold', color='SteelBlue', position=(0.75, 0.90))
fig.tight_layout()
i = 1
for name in names_list:
# get data
data = signals_df[signals_df["Name"] == name]["Value"]
datax = signals_df["Name"]
# x = [n for n in range(len(data))]
x = [n for n in range(len(datax))]
print(x)
# get color
j = random.randint(0, len(colors) - 1)
# add subplots
ax = plt.subplot(num_names_list, 1, i)
ax.plot(x, data, drawstyle='steps', marker='o', color=colors[j], linewidth=3)
# plt.xticks(None)
ax.set_ylabel(name, fontsize=12, fontweight='bold', color='SteelBlue', rotation=50, labelpad=45)
ax.grid(alpha=0.4)
i += 1
plt.show()
I am getting the following error:
I have been looking for the error and I totally understand that the dimensions of x and y must be equal, but there is the possibility of making a graph where the x-axis is greater than the y-axis? and also the x-axis comes from a variable not related to the y-axis? how would this be?
The x-axis is the count of all the values it has in the Signal element of the xml file: I put it here because of how extensive it is and this value is larger than the y-axis, but how to contemplate the 3 values that I bring from the xml that are Singal Name, Signal Value as y-axis and Count of Signals as x-axis. I really appreciate your comments and help.
IIUC, you are trying to plot several stepped values agains their order of appearance (X-index) in XML file. Then you should plot against original dataframe's X values. I haven't changed your code much for style or such, just fixed a little.
import xml.etree.ElementTree as ET
import pandas as pd
from matplotlib import pyplot as plt
import random
file_xml = 'example_un_child4.xml'
def transfor_data_atri(rootXML):
file_xml = ET.parse(rootXML)
data_XML = [
{"Name": signal.attrib["Name"],
"Value": int(signal.attrib["Value"].split(' ')[0])
} for signal in file_xml.findall(".//Signal")
]
signals_df = pd.DataFrame(data_XML)
extract_name_value(signals_df)
def extract_name_value(signals_df):
#print(signals_df)
names_list = [name for name in signals_df['Name'].unique()]
num_names_list = len(names_list)
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
# Creation Graphic
#fig = plt.figure(figsize=(18, 20), sharex=True)
fig, ax = plt.subplots(nrows=num_names_list, figsize=(10, 15), sharex=True)
plt.suptitle(f'File PXML: {file_xml}', fontsize=20, fontweight='bold', color='SteelBlue', position=(0.75, 0.90))
#fig.tight_layout()
i = 1
for pos, name in enumerate(names_list):
# get data
data = signals_df[signals_df["Name"] == name]["Value"]
datax = signals_df["Name"]
# x = [n for n in range(len(data))]
#x = [n for n in range(len(datax))]
#print(x)
# get color
j = random.randint(0, len(colors) - 1)
# add subplots
#ax[pos] = plt.subplot(num_names_list, 1, i)
ax[pos].plot(data.index, data, drawstyle='steps', marker='o', color=colors[j], linewidth=3)
# plt.xticks(None)
ax[pos].set_ylabel(name, fontsize=12, fontweight='bold', color='SteelBlue', rotation=50, labelpad=45)
ax[pos].grid(alpha=0.4)
i += 1
fig.tight_layout()
plt.show()
transfor_data_atri(file_xml)

User defined legend in python

I have this plot in which some areas between curves are being filled by definition. Is there any way to include them in legend? Especially where those filled areas are overlapped and as well as that a new and different color is being appeared.
Or there is possibility to define an arbitrary legend regardless of the curves' data?
Using fill_bettween to plot your data will automatically include the filled area in the legend.
To include the areas where the two datasets overlap, you can combine the legend handles from both dataset into a single legend handle.
As pointed out in the comments, you can also define any arbitrary legend handle with a proxy.
Finally, you can define exactly what handles and labels you want to appear in the legend, regardless of the data plotted in your graph.
See the MWE below that illustrates the points stated above:
import matplotlib.pyplot as plt
import numpy as np
plt.close('all')
# Gererate some datas:
x = np.random.rand(50)
y = np.arange(len(x))
# Plot data:
fig, ax = plt.subplots(figsize=(11, 4))
fillA = ax.fill_between(y, x-0.25, 0.5, color='darkolivegreen', alpha=0.65, lw=0)
fillB = ax.fill_between(y, x, 0.5, color='indianred', alpha=0.75, lw=0)
linec, = ax.plot(y, np.zeros(len(y))+0.5, color='blue', lw=1.5)
linea, = ax.plot(y, x, color='orange', lw=1.5)
lineb, = ax.plot(y, x-0.25, color='black', lw=1.5)
# Define an arbitrary legend handle with a proxy:
rec1 = plt.Rectangle((0, 0), 1, 1, fc='blue', lw=0, alpha=0.25)
# Generate the legend:
handles = [linea, lineb, linec, fillA, fillB, (fillA, fillB),
rec1, (fillA, fillB, rec1)]
labels = ['a', 'b', 'c', 'A', 'B', 'A+B', 'C', 'A+B+C']
ax.legend(handles, labels, loc=2, ncol=4)
ax.axis(ymin=-1, ymax=2)
plt.show()
Yes, you are absolutely right ian_itor, tacaswell and Jean-Sébastien, user defined legend seems to be the unique solution, in addition I made different linewidth for those area to be distinguishable from the curves, and playing with alpha got the right color.
handles, labels = ax.get_legend_handles_labels()
display = (0,1,2,3,4)
overlap_1 = plt.Line2D((0,1),(0,0), color='firebrick', linestyle='-',linewidth=15, alpha = 0.85)
overlap_2= plt.Line2D((0,1),(0,0), color='darkolivegreen',linestyle='-',linewidth=15, alpha = 0.65)
over_lo_3= plt.Line2D((0,1),(0,0), color='indianred',linestyle='-',linewidth=15, alpha = 0.75)
ax.legend([handle for i,handle in enumerate(handles) if i in display]+[overlap_1 , overlap_2 , overlap_3 ],
[label for i,label in enumerate(labels) if i in display]+['D','F','G'])

How to change marker and color in matplotlib for a specific column value?

I have a data file including 3 columns. The first 2 columns represent coordinates, the third one is a string value like 'foo', 'bar' or 'ter'.
I would like to display with python's matplotlib based on this label, different marker and color. Example:
foo => red circle
bar => green triangle
ter => black square
What I did till now is:
import numpy as np
import matplotlib.pyplot as plt
coordData = np.genfromtxt("mydata.csv", usecols=(0,1), delimiter=",", dtype=None)
coordLabels = np.genfromtxt("mydata.csv", usecols=2, delimiter=",", dtype=None)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(coordData[:, 0], coordData[:, 1], c="r", marker="o")
plt.show()
How can I switch marker and color based on the coordLabels values?
SOLUTION
Based on the suggestion I made some changes:
coordData = np.genfromtxt("mydata.csv", usecols=(0, 1), delimiter=",", dtype=None)
coordLabels = np.genfromtxt("mydata.csv", usecols=2, delimiter=",", dtype=None)
fig = plt.figure()
ax = fig.add_subplot(111)
uniqueVals = np.unique(coordLabels)
markers = ['^', 'o', '*']
colors = { '^' : 'r',
'o' : 'b',
'*' : 'g'}
for marker, val in zip(markers, uniqueVals):
toUse = coordLabels == val
ax.scatter(coordData[toUse,0], coordData[toUse,1], c = colors[marker], marker=marker)
plt.show()
If you want the color to be dependent upon the label in coordLabels, you want to set the color equal to that variable instead of 'r' like you have.
ax.scatter(coordData[:, 0], coordData[:, 1], c=coordLabels, marker="o")
If you want different markers for each of the plots, you will need to create multiple scatter plots (one for each value in coordLabels
uniqueVals = ['foo', 'bar', 'ter']
# Create your own list of markers here (needs to be the same size as `uniqueVals`)
markers = ['o', '^', 's']
colors = ['r', 'g', 'b']
for color, marker, val in zip(colors, markers, uniqueVals):
toUse = coordLabels == val
ax.scatter(coordData[toUse,0], coordData[toUse,1], c=color, marker=marker)

Matplotlib, Set multiple parameters at once?

Is there a way to set parameters for multiple graphs at once - basically defining a default?
What I have right now:
fig = plt.figure()
ax1 = fig.add_subplot(313)
ax1.scatter(entries,gvalues[0], color='b', marker = '1')
ax1.scatter(entries,gvalues[1], color = 'g', marker = 'v')
xticks([z for z in range(N)], namelist)
ylabel('Label1', ha='center', labelpad=28)
ylim(0,)
ax2 = fig.add_subplot(312, sharex=ax1)
ax2.scatter(entries,gvalues[2], color = 'b', marker = '1')
ax2.scatter(entries,gvalues[3], color= 'g', marker = 'v')
ylabel('Label2', ha='center', labelpad=28)
setp(ax2.get_xticklabels(),visible=False)
ylim(0,)
I am going to have a handful of these graphs, and it would be great if I didn't have to set ha = 'center', labelpad = 28 and ylim(0,) everytime.
Cheers
You can use a dictionary to store your options as below:
font_options = dict(ha='center', labelpad=28)
ax1.set_ylabel('Label1', **font_options)
...
ax2.set_ylabel('Label2', **font_options)
The **font_options argument will unpack each of the key-value pairs in the dictionary and apply them within the ylabel function.
Similarly for the ylim option you can store your limits in a variable such as:
ylimit = 0
ylim(ylimit,)

How to put the axis for two subplots separately?

I am trying to have two sub-plots in the figure in the Python Script. But I am not able to set the axis separately according to my inputs. Can anybody help me to set the x-axis, y-axis for each of the sub-plot separately?
I am including the piece of code that I have done, which was not giving me the result.
fig = plt.figure()
ax = plt.subplot(121) # To show the ascending order
plt.xlabel ('RF Input Power (dBm)', fontsize = 'small')
plt.ylabel ('Gain (dB)', fontsize = 'small')
tx = plt.title('Gain Vs Ascending RFInputAmpl for ' + str(measuredFrequencyUnderTest) + 'MHz', fontsize = 'small')
axPlotAxis = plt.axis([rfInputMin, rfInputMax, -20.0, 30.0])
# Now, Plot all the gain stages across the RFInput
ax.plot(rfInput_Plot, lna_Pre_Plot, color = 'r', marker = '+', label = 'lna_Pre')
ax.plot(rfInput_Plot, lna_Post_Plot, color = 'm', marker = 'x', label = 'lna_Post')
ax.plot(rfInput_Plot, sampler1_Plot, color = 'k', marker = '*', label = 'Sampler1')
ax.plot(rfInput_Plot, sampler2_Plot, color = 'c', marker = 's', label = 'Sampler2')
ax.plot(rfInput_Plot, vga_Plot, color = 'b', marker = 'p', label = 'VGA')
ax.plot(rfInput_Plot, dagc1_Plot, color = 'g', marker = 'H', label = 'DAGC1')
ax.plot(rfInput_Plot, dagc2_Plot, color = 'y', marker = 'v', label = 'DAGC2')
# Put the Legend
ax.legend(loc='upper center', bbox_to_anchor = (1.3, -0.05), shadow=True,numpoints = 1, prop = legend_font_props, ncol = 3)
# Now, come to the second plot
ay = plt.subplot(122) # To show the descending order
plt.xlabel ('RF Input Power (dBm)', fontsize = 'small')
plt.ylabel ('Gain (dB)', fontsize = 'small', horizontalalignment = 'left')
ty = plt.title('Gain Vs Descending RF Input for '+ str(measuredFrequencyUnderTest)+ 'MHz', fontsize = 'small')
# Now, fix the x axis here in descending order
plt.axis([rfInputMax, rfInputMin, y_Min_Value, y_Max_Value])
plt.minorticks_on()
Is there something wrong that I am performing? Pls help me to correct it.
You can set independent scales very easily (from an ipython -pylab session):
In [8]: ax = plt.subplot(121)
In [9]: ay = plt.subplot(122)
In [10]: ax.set_xlim((-1,2))
In [11]: ax.set_ylim((10,20))
In [12]: ay.set_xlim((-10,4))
In [13]: ay.set_ylim((3,5))

Categories

Resources