change color on matplotlib - colors

I want to change the color of my bar chart.
However, it always plots in black.
Where am I mistaken?
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
rects = ax.bar(range(len(l)), l, color = 'r')
ax.set_title('title')
ax.set_xlabel('xlabel')
ax.set_ylabel('ylabel')
plt.show()
I tried with other parameters ('g', 'c' etc.) but the result is always the same.

Related

How do I get matplotlib subplot and GridSpec to position and size subplots as I want them?

I am trying to create a figure with 2x10 subplots. I would like them all to be square with a thin white space in between them, but they are coming out as rectangles (longer in height than width). The images I'm putting in each cell of the grid are all square, but the cell itself is not square so the extra space just becomes white space which creates a giant gap between the top row and the bottom row. Here's the code that shows the rectangles:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from PIL import Image
fig = plt.figure()
gs1 = GridSpec(2, 10)
for a in range(10):
ax = plt.subplot(gs1[0, a])
ax2 = plt.subplot(gs1[1, a])
plt.show()
output from above code
Imagine this but with little to no gaps in between cells and each cell is square instead of rectangular. Thanks in advance for any help!
You can use plt.tight_layout() to clean up your subplot figure. Also, play around with plt.rcParams for the figure size:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from PIL import Image
plt.rcParams["figure.figsize"] = (20,10)
fig = plt.figure()
gs1 = GridSpec(2, 10)
for a in range(10):
ax = plt.subplot(gs1[0, a])
ax2 = plt.subplot(gs1[1, a])
plt.tight_layout()
plt.show()
Output
For more control, you can use fig,ax and turn off all the labels and ticks. Then you can remove the white space between the subplots.
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from PIL import Image
plt.rcParams["figure.figsize"] = (20,4)
fig, ax = plt.subplots(2,10)
gs1 = GridSpec(2, 10)
for x in range(2):
for y in range(10):
ax[x,y].plot()
ax[x,y].tick_params(axis = 'both', bottom= False, left = False,
labelbottom = False, labelleft = False)
ax[1,0].tick_params(axis = 'both', bottom= True, left = True,
labelbottom = True, labelleft = True)
plt.subplots_adjust(wspace=0.05, hspace=0.05)
plt.show()
Output:

Combine bar plot and line plot in seaborn [duplicate]

I have dataframe like this:
df_meshX_min_select = pd.DataFrame({
'Number of Elements' : [5674, 8810,13366,19751,36491],
'Time (a)' : [42.14, 51.14, 55.64, 55.14, 56.64],
'Different Result(Temperature)' : [0.083849, 0.057309, 0.055333, 0.060516, 0.035343]})
and I tried to combine bar plot (number of elements Vs Different result) and line plot (Number of elements Vs Time) in the same figure, but I found the following problem like this:
it seems that x_value doesn't match when combining 2 plots, but if you see the data frame, the x value is exactly the same value.
My expectation is combining these 2 plots into 1 figure:
and this is the code that I made:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
df_meshX_min_select = pd.DataFrame({
'Number of Elements' : [5674, 8810,13366,19751,36491],
'Time (a)' : [42.14, 51.14, 55.64, 55.14, 56.64],
'Different Result(Temperature)' : [0.083849, 0.057309, 0.055333, 0.060516, 0.035343]})
x1= df_meshX_min_select["Number of Elements"]
t1= df_meshX_min_select["Time (a)"]
T1= df_meshX_min_select["Different Result(Temperature)"]
#Create combo chart
fig, ax1 = plt.subplots(figsize=(10,6))
color = 'tab:green'
#bar plot creation
ax1.set_title('Mesh Analysis', fontsize=16)
ax1.set_xlabel('Number of elements', fontsize=16)
ax1.set_ylabel('Different Result(Temperature)', fontsize=16)
ax1 = sns.barplot(x='Number of Elements', y='Different Result(Temperature)', data = df_meshX_min_select)
ax1.tick_params(axis='y')
#specify we want to share the same x-axis
ax2 = ax1.twinx()
color = 'tab:red'
#line plot creation
ax2.set_ylabel('Time (a)', fontsize=16)
ax2 = sns.lineplot(x='Number of Elements', y='Time (a)', data = df_meshX_min_select, sort=False, color=color, ax=ax2)
ax2.tick_params(axis='y', color=color)
#show plot
plt.show()
Anyone can help me, please?
Seaborn and pandas use a categorical x-axis for bar plots (internally numbered 0,1,2,...) and floating-point numbers for a line plot. Note that your x-values aren't evenly spaced, so either the bars would have weird distances between them, or wouldn't align with the x-values from the line plot.
Here is a solution using standard matplotlib to combine both graphs.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
df_meshx_min_select = pd.DataFrame({
'number of elements': [5674, 8810, 13366, 19751, 36491],
'time (a)': [42.14, 51.14, 55.64, 55.14, 56.64],
'different result(temperature)': [0.083849, 0.057309, 0.055333, 0.060516, 0.035343]})
x1 = df_meshx_min_select["number of elements"]
t1 = df_meshx_min_select["time (a)"]
d1 = df_meshx_min_select["different result(temperature)"]
fig, ax1 = plt.subplots(figsize=(10, 6))
color = 'limegreen'
ax1.set_title('mesh analysis', fontsize=16)
ax1.set_xlabel('number of elements', fontsize=16)
ax1.set_ylabel('different result(temperature)', fontsize=16, color=color)
ax1.bar(x1, height=d1, width=2000, color=color)
ax1.tick_params(axis='y', colors=color)
ax2 = ax1.twinx() # share the x-axis, new y-axis
color = 'crimson'
ax2.set_ylabel('time (a)', fontsize=16, color=color)
ax2.plot(x1, t1, color=color)
ax2.tick_params(axis='y', colors=color)
plt.show()
I was plotting a boxplot with a lineplot and I had the same problem even my two x-axes are identical, so I solved converting my x-axis feature to type string:
df_meshX_min_select['Number of Elements'] = df_meshX_min_select['Number of Elements'].astype('string')
This way the plot works using seaborn:

Is it possible to use matplotlib to include a subheading in legend that isnt a part of the graph?

I am using matplotlib to plot a pie chart. I have added a legend to the chart. However, i would like to add a "Total" to the legend, to sum up the values of all the other categories. Hence the value of "Total" would not be a part of the pie chart, and would only be shown in the legend. Is it possible for me to do that? Thank you.
You can create 2 legends. On the second one, you can create/manipulate symbol/text/title as you want. Here is a runnable code that you can try.
from matplotlib import pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.axis('equal')
langs = ['C', 'C++', 'Java', 'Python', 'PHP']
students = [23,17,35,29,12]
ax.pie(students, labels = langs,autopct='%1.2f%%')
# first legend
lgn = plt.legend()
ax = plt.gca().add_artist(lgn)
# second legend
gold_patch = mpatches.Patch(color='gold', label='Total= 9999') # use your description text here
second_legend = plt.legend(handles=[gold_patch], loc=1, \
bbox_to_anchor=(0.5, 0.35, 0.55, 0.35)) # adjust location of legend here
second_legend.set_frame_on(False) # use True/False as needed
second_legend.set_title("Other categories")
plt.show()
The output plot:

Bar Plot with inverted y axis and bars attached to bottom

The code below creates a bar plot with an inverted y-axis. What I don't manage yet is that the bars do not "hang from above" but start at the bottom. In other words, I like the bars to start at the maximum value of the y axis (i.e. at the x-axis) and ending at the value of df['y']. How can I do that?
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(data={'x_cat': ['aaaaa',
'bvvvvvv',
'deeeee',
'qqqqqqq',
'rr rrrrrrrr',
'rss sdasr',
'cccccccccccc',
'aarrrrrrrrrrra'
],
'y': [11.91,
35.19,
43.61,
46.12,
75.03,
81.39,
83.28,
89.20]
})
df['rank'] = df['y'].rank(method='dense') - 1
fig = plt.figure()
ax = fig.add_subplot(111)
# increase space below subplot
fig.subplots_adjust(bottom=0.3)
ax.bar(df['rank'],
df['y'],
width=0.8,
)
# invert y axis
ax.invert_yaxis()
# label x axis
ax.set_xticks(range(len(df)))
ax.set_xticklabels(df['x_cat'],
fontdict={'fontsize': 14})
for tick in ax.get_xticklabels():
tick.set_rotation(90)
You would need to calculate the new bottom. (Note that
because the axis is inverted, the "bottom" becomes the visual top of the bars.) The bottom is the value, the height is maximum minus the value itself.
I changed some other aspects of your plot, e.g. if your values are not sorted, calculating the rank and using it for plotting would result in wrong labelling. Hence better sort the dataframe beforehands (and forget about the rank).
Finally, we would need to adjust the "sticky edges" of the bars, because they should sit tight to the bottom of the figure (i.e. the top of the axis).
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({'x_cat': ['aaaaa', 'bvvvvvv', 'deeeee', 'qqqqqqq', 'rr rrrrrrrr',
'rss sdasr', 'cccccccccccc', 'aarrrrrrrrrrra'],
'y': [11.91, 35.19, 43.61, 46.12, 75.03, 81.39, 83.28, 89.20]})
df.sort_values("y", inplace=True)
fig = plt.figure()
ax = fig.add_subplot(111)
# increase space below subplot
fig.subplots_adjust(bottom=0.3)
bars = ax.bar(df['x_cat'], df['y'].max()-df['y'], bottom=df['y'], width=0.8, )
# invert y axis
ax.invert_yaxis()
ax.tick_params(axis="x", rotation=90, labelsize=14)
for bar in bars:
bar.sticky_edges.y[:] = [df['y'].values.max()]
ax.autoscale()
plt.show()

MatPlotLib + GeoPandas: Plot Multiple Layers, Control Figsize

Given the shape file available here: I know can produce the basic map that I need with county labels and even some points on the map (see below). The issue I'm having is that I cannot seem to control the size of the figure with figsize.
Here's what I have:
import geopandas as gpd
import matplotlib.pyplot as plt
%matplotlib inline
figsize=5,5
fig = plt.figure(figsize=(figsize),dpi=300)
shpfileshpfile=r'Y:\HQ\TH\Groups\NR\PSPD\Input\US_Counties\cb_2015_us_county_20m.shp'
c=gpd.read_file(shpfile)
c=c.loc[c['GEOID'].isin(['26161','26093','26049','26091','26075','26125','26163','26099','26115','26065'])]
c['coords'] = c['geometry'].apply(lambda x: x.representative_point().coords[:])
c['coords'] = [coords[0] for coords in c['coords']]
ax=c.plot()
#Control some attributes regarding the axis (for the plot above)
ax.spines['top'].set_visible(False);ax.spines['bottom'].set_visible(False);ax.spines['left'].set_visible(False);ax.spines['right'].set_visible(False)
ax.tick_params(axis='y',which='both',left='off',right='off',color='none',labelcolor='none')
ax.tick_params(axis='x',which='both',top='off',bottom='off',color='none',labelcolor='none')
for idx, row in c.iterrows():
ax.annotate(s=row['NAME'], xy=row['coords'],
horizontalalignment='center')
lat2=[42.5,42.3]
lon2=[-84,-83.5]
#Add another plot...
ax.plot(lon2,lat2,alpha=1,marker='o',linestyle='none',markeredgecolor='none',markersize=15,color='white')
plt.show()
As you can see, I opted to call the plots by the axis name because I need to control attributes of the axis, such as tick_params. I'm not sure if there is a better approach. This seems like a "no-brainer" but I can't seem to figure out why I can't control the figure size.
Thanks in advance!
I just had to do the following:
Use fig, ax = plt.subplots(1, 1, figsize = (figsize))
2.use the ax=ax argument in c.plot()
import geopandas as gpd
import matplotlib.pyplot as plt
%matplotlib inline
figsize=5,5
#fig = plt.figure(figsize=(figsize),dpi=300)
#ax = fig.add_subplot(111)
fig, ax = plt.subplots(1, 1, figsize = (figsize))
shpfileshpfile=r'Y:\HQ\TH\Groups\NR\PSPD\Input\US_Counties\cb_2015_us_county_20m.shp'
c=gpd.read_file(shpfile)
c=c.loc[c['GEOID'].isin(['26161','26093','26049','26091','26075','26125','26163','26099','26115','26065'])]
c['coords'] = c['geometry'].apply(lambda x: x.representative_point().coords[:])
c['coords'] = [coords[0] for coords in c['coords']]
c.plot(ax=ax)
ax.spines['top'].set_visible(False);ax.spines['bottom'].set_visible(False);ax.spines['left'].set_visible(False);ax.spines['right'].set_visible(False)
ax.tick_params(axis='y',which='both',left='off',right='off',color='none',labelcolor='none')
ax.tick_params(axis='x',which='both',top='off',bottom='off',color='none',labelcolor='none')
for idx, row in c.iterrows():
ax.annotate(s=row['NAME'], xy=row['coords'],
horizontalalignment='center')
lat2=[42.5,42.3]
lon2=[-84,-83.5]
ax.plot(lon2,lat2,alpha=1,marker='o',linestyle='none',markeredgecolor='none',markersize=15,color='white')

Resources