Using Hlines ruins legends in Matplotlib - python

I'm struggling to adjust my plot legend after adding the axline/ hline on 100 level in the graph.(screenshot added)
if there's a way to run this correctly so no information will be lost in legend, and maybe add another hline and adding it to the legend.
adding the code here, maybe i'm not writing it properly.
fig, ax1 = plt.subplots(figsize = (9,6),sharex=True)
BundleFc_Outcome['Spend'].plot(kind = 'bar',color = 'blue',width = 0.4, ax = ax1,position = 1)
#
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('SPEND', color='b', size = 18)
ax1.set_xlabel('Bundle FC',color='w',size = 18)
ax2 = ax1.twinx()
ax2.set_ylabel('ROAS', color='r',size = 18)
ax1.tick_params(axis='x', colors='w',size = 20)
ax2.tick_params(axis = 'y', colors='w',size = 20)
ax1.tick_params(axis = 'y', colors='w',size = 20)
#ax1.text()
#
ax2.axhline(100)
BundleFc_Outcome['ROAS'].plot(kind = 'bar',color = 'red',width = 0.4, ax = ax2,position = 0.25)
plt.grid()
#ax2.set_ylim(0, 4000)
ax2.set_ylim(0,300)
plt.title('ROAS & SPEND By Bundle FC',color = 'w',size= 20)
plt.legend([ax2,ax1],labels = ['SPEND','ROAS'],loc = 0)
The code gives me the following picture:
After implementing the suggestion in the comments, the picture looks like this (does not solve the problem):

You can use bbox_to_anchor attribute to set legend location manually.
ax1.legend([ax1],labels = ['SPEND'],loc='upper right', bbox_to_anchor=(1.25,0.70))
plt.legend([ax2,ax1],labels = ['SPEND','ROAS'],loc='upper right', bbox_to_anchor=(1.25,0.70))
https://matplotlib.org/users/legend_guide.html#legend-location

So finally figured it out , was simpler for a some reason
Even managed to add another threshold at level 2 for minimum spend.
fig, ax1 = plt.subplots(figsize = (9,6),sharex=True)
BundleFc_Outcome['Spend'].plot(kind = 'bar',color = 'blue',width = 0.4, ax = ax1,position = 1)
#
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('SPEND', color='b', size = 18)
ax1.set_xlabel('Region',color='w',size = 18)
ax2 = ax1.twinx()
ax2.set_ylabel('ROAS', color='r',size = 18)
ax1.tick_params(axis='x', colors='w',size = 20)
ax2.tick_params(axis = 'y', colors='w',size = 20)
ax1.tick_params(axis = 'y', colors='w',size = 20)
#ax1.text()
#
BundleFc_Outcome['ROAS'].plot(kind = 'bar',color = 'red',width = 0.4, ax = ax2,position = 0.25)
plt.grid()
#ax2.set_ylim(0, 4000)
ax2.set_ylim(0,300)
plt.title('ROAS & SPEND By Region',color = 'w',size= 20)
fig.legend([ax2,ax1],labels = ['SPEND','ROAS'],loc = 0)
plt.hlines([100,20],xmin = 0,xmax = 8,color= ['r','b'])

I don't recommend using the builtin functions of pandas to do more complex plotting. Also when asking a question it is common courtesy to provide a minimal and verifiable example (see here). I took the liberty to simulate your problem.
Due to the change in axes, we need to generate our own legend. First the results:
Which can be achieved with:
import matplotlib.pyplot as plt, pandas as pd, numpy as np
# generate dummy data.
X = np.random.rand(10, 2)
X[:,1] *= 1000
x = np.arange(X.shape[0]) * 2 # xticks
df = pd.DataFrame(X, columns = 'Spend Roast'.split())
# end dummy data
fig, ax1 = plt.subplots(figsize = (9,6),sharex=True)
ax2 = ax1.twinx()
# tmp axes
axes = [ax1, ax2] # setup axes
colors = plt.cm.tab20(x)
width = .5 # bar width
# generate dummy legend
elements = []
# plot data
for idx, col in enumerate(df.columns):
tax = axes[idx]
tax.bar(x + idx * width, df[col], label = col, width = width, color = colors[idx])
element = tax.Line2D([0], [0], color = colors[idx], label = col) # setup dummy label
elements.append(element)
# desired hline
tax.axhline(200, color = 'red')
tax.set(xlabel = 'Bundle FC', ylabel = 'ROAST')
axes[0].set_ylabel('SPEND')
tax.legend(handles = elements)

Related

Data Visulation Problem With Bar Plot and It's axes

i have a problem. I will show it you with pictures and tables.
0
MGROS 4.983566
SOKM 4.983566
BIMAS 4.983566
POLHO 4.043808
VESBE 2.722698
ARCLK 2.722698
VESTL 2.722698
HURGZ 2.125138
YATAS 2.030432
SELEC 1.986755
My dataframe is like above and graph is like below.
# creating the bar plot
br = plt.bar(df.index, df.values.squeeze(), color =colorLIST,
width = 0.9)
#for rect in br:
# height = rect.get_height()
# plt.text(rect.get_x() + rect.get_width() / 2.0, height, "%"+f'{height:.2f}', ha='center', va='bottom', color = "#003C5F", fontsize = 5.5)
plt.xlabel("Sembol", color = "#7F2A3C", fontsize = 20)
plt.ylabel("Getiri", color = "#7F2A3C", fontsize = 20)
plt.xticks(rotation = 90, fontsize = 20 )
labels = plt.gca().get_xticklabels()
for i in range(len(labels)):
labels[i].set_color(colorLIST[i])
plt.title("Global Sektörler", color = "#7F2A3C", fontsize = 20)
ax.spines['top'].set_color('#C2B280')
ax.spines['right'].set_color('none')
ax.spines['left'].set_smart_bounds(True)
ax.spines['bottom'].set_smart_bounds(True)
ax.yaxis.set_major_formatter(mtick.PercentFormatter())
#ax.grid(zorder=0)
#ax.xaxis.grid()
minor_locator = AutoMinorLocator(2)
plt.gca().xaxis.set_minor_locator(minor_locator)
plt.grid(which='minor')
plt.savefig("peers_company.png", dpi = 100)
plt.show()
The code is above. I want to show the same values in one bar. For example, MGROS, SOKM and BIMAS same values. How can i show it one bar and one xticks as with all three names one under the other?
I solve this problem. Here is the code.
I only rearranged my dataframe.
df['marker'] = (df[0] != df[0].shift()).cumsum()
df["TICKERS"] = df.index.tolist()
df = df.groupby('marker').agg({ 0: "first", "TICKERS": lambda x: list(x)})
df["VALUES"] = df[0].values
df.TICKERS = df.TICKERS.apply(lambda x : " ".join(x))

Show dates in xticks only where value exist in plot chart of multiple dataframes

I have got a matplotlib question about xticks. I wanted to hide all those values that do not occur. I actually did it, but for the second set of values (red chart). I found how to hide for a specific data frame but not for 2 or more.
This is my code:
plt.subplots(figsize=(2, 1), dpi=400)
width = 0.005
xlim = np.arange(0, 1, 0.01)
ylim = np.arange(0, 0.1, 0.001)
plt.xticks(density_2.index.unique(), rotation=90, fontsize=1.5)
plt.yticks(density_2.unique(), fontsize=2)
plt.bar(density_1.index, density_1, width, color='Green', label=condition_1,alpha=0.5)
plt.bar(density_2.index, density_2, width, color='Red', label=condition_2,alpha=0.5)
plt.legend(loc="upper right", fontsize=2)
plt.show()
Link where I saw the solution: show dates in xticks only where value exist in plot chart and hide unnecessary interpolated xtick labels
Thank you very much in advance!
You need to find the intersection of the two lists of density_1's and density_2's ticks, as reported here.
Working example:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
N = 150
values_1 = np.random.randint(low = 5, high = 75, size = N)/100
density_1 = pd.DataFrame({'density_1': values_1})
density_1 = density_1.value_counts().sort_index(ascending = True)
density_1.index = sorted(list(set(values_1)), reverse = False)
values_2 = np.random.randint(low = 35, high = 100, size = N)/100
density_2 = pd.DataFrame({'density_2': values_2})
density_2 = density_2.value_counts().sort_index(ascending = True)
density_2.index = sorted(list(set(values_2)), reverse = False)
width = 0.005
condition_1 = 'Adele'
condition_2 = 'Extremoduro'
fig, ax = plt.subplots(figsize = (10, 5))
ax.bar(density_1.index, density_1, width, color = 'Green', label = condition_1, alpha = 0.5)
ax.bar(density_2.index, density_2, width, color = 'Red', label = condition_2, alpha = 0.5)
ax.legend(loc = 'upper right')
ax.set_xticks(list(set(density_1.index.unique()) & set(density_2.index.unique())), rotation = 90)
plt.show()
In the line:
list(set(density_1.index.unique()) & set(density_2.index.unique()))
you can select ticks which blongs to both density_1 and density_2.
Zoom in:

Filtering of data in signal processing

I am processing the data from serial. I have to filter the data to remove ripples. I have tried with the following code. However, I can't get the expected results. Suggest me which type of filter I have to use?
def graph_plot():
plt.xlabel("samples")
plt.ylabel("data")
plt.xlim([0, 2048])
plt.ylim([0, 255])
return plt
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.minorticks_on()
ax.grid(1, which = 'both', axis = 'y', markevery = 5)
actual_rx_data = rx_data[4:2052] #rx_data is input from serial
N = len(actual_rx_data)
rx_data = [actual_rx_data[i] for i in range (0, N)]
rx_data = np.reshape(rx_data, (2048, 1))
smoother = ConvolutionSmoother(window_len = 20, window_type = 'ones')
smoother.smooth(rx_data)
plt = graph_plot()
ax.plot(rx_data, color = 'red') #input
ax.plot(smoother.smooth_data[0], linewidth = 2, color = 'blue') #output
ax.clear()
Result obtained by the above code:
Expected results in blue color:

How to Rotate Count Plot In Seaborn?

plt.figure(figsize = (12, 8))
sns.set(style = 'dark', palette = 'colorblind', color_codes = True)
ax = sns.countplot('Position', data = data, color = 'orange')
ax.set_xlabel(xlabel = 'Different Positions in Football', fontsize = 16)
ax.set_ylabel(ylabel = 'Number of of Players', fontsize = 16)
ax.set_title(label = 'Comparison of Positions and Players', fontsize = 20)
plt.show()
After excuting this code the labels get Overlapped
Is there any way to rotate the image to prevent overlapping?
Insted of using
ax = sns.countplot('Position', data = data, color = 'orange')
Where 'Position' = x, try to use 'Position'=y, just like that:
ax = sns.countplot(y='Position', data = data, color = 'orange')
The rest of the code remains the same

Python - Animate basemap scatterplot

I have a DataFrame with shape (14403, 438) that consists of longitudes and latitudes as well as values. The DataFrame is as:
I am plotting the coordinates as:
# define map colors
land_color = '#f5f5f3'
water_color = '#cdd2d4'
coastline_color = '#f5f5f3'
border_color = '#bbbbbb'
meridian_color = '#f5f5f3'
marker_fill_color = '#0000ff'
marker_edge_color = 'None'
# create the plot
fig = plt.figure(figsize = (15, 10))
ax = fig.add_subplot(111, facecolor = '#ffffff', frame_on = False)
ax.set_title('Transportable Array', fontsize = 24, color = '#333333')
#lon_0 center of desired map domain (in degrees).
#lat_0 center of desired map domain (in degrees).
#width width of desired map domain in projection coordinates (meters).
#height height of desired map domain in projection coordinates (meters).
# draw the basemap and its features
m = Basemap(width = 5500000,height = 3300000,
resolution = 'l', area_thresh = 1000., projection = 'lcc',\
lat_1 = 45., lat_2 = 55, lat_0 = 37, lon_0 = -98.)
m.drawmapboundary(color = border_color, fill_color = water_color)
m.drawcoastlines(color = coastline_color)
m.drawcountries(color = border_color)
m.fillcontinents(color = land_color, lake_color = water_color)
m.drawparallels(np.arange(-90., 120., 30.), color = meridian_color)
m.drawmeridians(np.arange(0., 420., 60.), color = meridian_color)
# project the location history points then scatter plot them
x, y = m(stations.loc['longitude'].values, stations.loc['latitude'].values)
m.scatter(x, y, s = 8, color = marker_fill_color, edgecolor = marker_edge_color, alpha = 1, zorder = 3)
# show & save the map
plt.savefig('Transportable_Array.png', dpi = 96, bbox_inches = 'tight', pad_inches = 0.2)
plt.show()
I am trying to create an animation that will plot the coordinates for each column and then iterate over the values in the index. In the end I am trying to have it iterate over the 14,403 rows and change the markings color based on the value. I am currently having trouble even animating the plot for the coordinates alone.
I would love to be able to implement bqplot, but the scatter animations I've followed on GitHub have not worked yet.
The map currently looks like below. It'd be wicked cool if each dot can fluctuate in color based on the current iterations value.
Thank you for reading.
You can use the animation module for this. These are the general steps:
Convert the values into a colour
Update the color at each step
Save the animation
Here is some code:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import matplotlib.animation as animation
import numpy as np
land_color = '#f5f5f3'
water_color = '#cdd2d4'
coastline_color = '#f5f5f3'
border_color = '#bbbbbb'
meridian_color = '#f5f5f3'
marker_fill_color = '#0000ff'
marker_edge_color = 'None'
# Some dummy data
longVals = np.random.uniform(-120,-80, 1000)
latVals = np.random.uniform(35, 45, 1000)
vals = np.random.uniform(size=(200,1000))
# Be careful - the values that go into the colormap function
# must be integers between 0 and 254
normalisedVals = 254*(vals-vals.min())/(vals.max()-vals.min())
normalisedVals = normalisedVals.astype(np.int)
cm = plt.cm.spectral_r
fig = plt.figure(figsize = (15, 10))
ax = fig.add_subplot(111, facecolor = '#ffffff', frame_on = False)
ax.set_title('Transportable Array', fontsize = 24, color = '#333333')
# draw the basemap and its features
m = Basemap(width = 5500000,height = 3300000,
resolution = 'l', area_thresh = 1000., projection = 'lcc',
lat_1 = 45., lat_2 = 55, lat_0 = 37, lon_0 = -98.)
m.drawmapboundary(color = border_color, fill_color = water_color)
m.drawcoastlines(color = coastline_color)
m.drawcountries(color = border_color)
m.fillcontinents(color = land_color, lake_color = water_color)
m.drawparallels(np.arange(-90., 120., 30.), color = meridian_color)
m.drawmeridians(np.arange(0., 420., 60.), color = meridian_color)
x, y = m(longVals, latVals)
scat = m.scatter(x, y, s = 8, c = normalisedVals[0], edgecolor = marker_edge_color, alpha = 1, zorder = 3)
def init():
return scat,
def animate(i):
col = cm(normalisedVals[i])
scat.set_color(col)
return scat,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=20, blit=False, repeat=False)
anim.save('animation.gif', writer='imagemagick', fps=60)
I should warn you that for 14k rows this will take a while.
Also I would recommend saving as an mp4 rather than a gif due to better compression.
If you have any questions let me know!

Categories