change the ticks of a chart - python

I can't make a change in the ticks, and either the whole graph turns white or the texts are grouped together and since the date is cyclic, it has the same matches on different days and that makes the graph messy
fig, ax = plt.subplots(sharex=True, constrained_layout=True,
figsize=(20, 12))
ax.plot(incra['Temp'], "-b", label='Temp')
ax.plot(incra['Hum'], "-k", label='Temp')
ax.set_ylabel('CO2 ppm')
ax.yaxis.grid(b=True, color='black', alpha=0.3, linestyle='-.', linewidth=1)
ax.xaxis.grid(b=True, color='black', alpha=0.3, linestyle='-.', linewidth=1)
ax.set_xticklabels(labels=incra['Date'], rotation = 45)
plt.savefig('po.png', format='png')[enter image description here](https://i.stack.imgur.com/0VbNX.png)
I have a large dataset, but I only want a few matches on the x-axis, how can I change my code to optimize for this?

x_ticks = [0, 50, 100, 150, 200]
ax.set_xticks(x_ticks)
ax.set_xticklabels(labels=incra['Date'][x_ticks], rotation = 45)

Related

How can I avoid color overlap in matplot python?

I am trying to make a clear visualizatin of my data.
This is my code:
width = 0.5
plt.figure(figsize=(10,8))
counts1, bins, bars = plt.hist(data=df1_small, x='fz', bins=np.arange(-5, 5.5, width), color='dodgerblue', alpha=0.3) #rwidth can change the space between bars
#plt.plot(bins[:-1] + width/2, counts1, color='#FF6103', linewidth=2)
counts2, bins, bars = plt.hist(data=df2_big, x='fz', bins=np.arange(-5, 5.5, width), color='red', alpha=0.1)
#plt.plot(bins[:-1] + width/2, counts2, color='#76EEC6', linewidth=2)
labels = ["small", "big"]
plt.legend(labels)
plt.grid(False)
#plt.savefig("./figure/acce.eps", dpi=300)
plt.savefig("./figure/acce.png", dpi=300)
plt.show()
Whenever I plot, I found that color is overlapped if plot is overlapped.
Is there any idea to avoid this overlap?
This is my plot right now:
I want to avoid color overlapping and make it clear with just two colors.
Thank you
If you want to avoid any overlap between the two histograms, you could plot both in separate subplots. In this case, I think it makes more sense to title the axes than to add labels, but you could do either. See below:
# Create two subplots, aligned horizontally
fig, axes = plt.subplots(1, 2, figsize=(10, 8))
width = 0.5
# Plot each histogram in its own axis
counts1, bins, bars = axes[0].hist(data=df1_small, x='fz', bins=np.arange(-5, 5.5, width), color='dodgerblue', alpha=0.3) #rwidth can change the space between bars
counts2, bins, bars = axes[1].hist(data=df2_big, x='fz', bins=np.arange(-5, 5.5, width), color='red', alpha=0.1)
# Add title
axes[0].set_title("small")
axes[1].set_title("small")
# Add labels
axes[0].legend("small")
axes[1].legend("big")
# Need to disable the grid for both axes
axes[0].grid(False)
axes[1].grid(False)
plt.savefig("./figure/acce.png", dpi=300)
plt.show()

How Can I space legend items with variable spacing and have legend marker colors reflect the colormap

I would like to have an increasing spacing between legend items instead of a single value (labelspacing). The latter only accepts an int value type, but I want a variable spacing between legend items. Also, I want the markerfacecolor to follow the colormap used when creating the scatter plot.
N = 45
x, y = np.random.rand(2, N)
s = np.random.randint(10, 1000, size=N)
fig, ax = plt.subplots()
scatter = ax.scatter(x, y, c=s, s=s)
cbar = fig.colorbar(scatter,
ax=ax,
label='Size',
fraction=0.1,
pad=0.04)
# produce a legend with a cross section of sizes from the scatter
handles, labels = scatter.legend_elements(prop="sizes", alpha=0.6)
for hd in handles:
hd.set_markeredgewidth(2)
hd.set_markeredgecolor("red")
hd.set_markerfacecolor('blue')
legend2 = ax.legend(
handles[::2], labels[::2], loc="upper right", title="Sizes", labelspacing=1.2
)
plt.show()
I searched StackOverflow and tried some possible methods but without success. Could someone guide how I can achieve the desired output?
I managed to set markerfacecolor as the colormap. But I am still struggling with the variable labelspacing!.
Any help!
N = 45
x, y = np.random.rand(2, N)
s = np.random.randint(10, 1000, size=N)
fig, ax = plt.subplots()
scatter = ax.scatter(x, y, c=s, s=s)
cbar = fig.colorbar(scatter,
ax=ax,
label='Size',
fraction=0.1,
pad=0.04)
# produce a legend with a cross section of sizes from the scatter
handles, labels = scatter.legend_elements(prop="sizes", alpha=0.6)
leg_colrs = [color.get_markerfacecolor() for color in scatter.legend_elements()[0]]
for hd, color in zip(handles, leg_colrs):
hd.set_markeredgewidth(2)
hd.set_markeredgecolor("red")
hd.set_markerfacecolor(color)
legend2 = ax.legend(
handles[::2], labels[::2], loc="upper right", title="Sizes", labelspacing=1.2
)
plt.show()

How to add multiple data labels in a bar chart

I have two grouped bar charts of value changes between cases for two systems among 3 groups as below. Here I was able to add data labels to the bars using the code below (figure produced attached)
What I want to do is on top (or bottom for the negative change in value cases), add an extra data label that captures the % of the value changes as shown in the second figure with the 33% in red (I edited it in by hands). How do I achieve that from this code? Thank you in advance.
import matplotlib.pyplot as plt
import numpy as np
value_case0_system1 = np.array([30, 20, 40])
value_case1_system1 = np.array([20, 25, 50])
value_case2_system1 = np.array([10, 35, 45])
value_case1_system2 = np.array([60, 50, 40])
value_case2_system2 = np.array([50, 40, 55])
change_case0_to_case1_system1 = np.subtract(value_case1_system1,value_case0_system1)
change_case1_to_case2_system1 = np.subtract(value_case2_system1,value_case1_system1)
change_case1_to_case2_system2 = np.subtract(value_case2_system2,value_case1_system2)
fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(18,10))
labels = ['Group 1', 'Group 2', 'Group 3']
x = np.arange(len(labels))
ax0.set_ylabel('Change in Values', va='center', rotation='vertical',
fontsize=17, fontweight='bold')
width = 0.28
ax0.set_title('System 1', fontsize=17, fontweight='bold')
ax0.axhline(y=0, color='black', ls=':', lw=2)
ax0.set_xticks(x)
ax0.set_xticklabels(labels,fontsize=15)
rects1 = ax0.bar(x-width/2, change_case0_to_case1_system1, width, label='Case 0 to Case 1',
color='#292929', edgecolor='black', linewidth=1)
rects2 = ax0.bar(x+width/2, change_case1_to_case2_system1, width, label='Case 1 to Case 2',
color='#7f6d5f', edgecolor='black', linewidth=1)
ax0.bar_label(rects1, padding=3, fontsize=11)
ax0.bar_label(rects2, padding=3, fontsize=11)
leg = ax0.legend(loc="upper left", bbox_to_anchor=[0, 1],
ncol=1, fancybox=True)
ax0.legend(fontsize=15)
ax1.set_title('System 2', fontsize=17, fontweight='bold')
ax1.axhline(y=0, color='black', ls=':', lw=2)
ax1.set_xticks(x)
ax1.set_xticklabels(labels,fontsize=15)
rects3 = ax1.bar(x, change_case1_to_case2_system2, width, label='Case 1 to Case 2',
color='#7f6d5f', edgecolor='black', linewidth=1)
ax1.legend(shadow=True, fancybox=True)
ax1.bar_label(rects3, padding=3, fontsize=11)
leg = ax1.legend(loc="upper left", bbox_to_anchor=[0, 1],
ncol=1, fancybox=True)
ax1.legend(fontsize=15)
plt.tight_layout()
plt.show()
The code for the extra plot formatting has been left out, because it's not relevant for the answer. It can be added back, as per your requirements.
Each .bar_label colors the label globally, so unlike this answer, a second .bar_label needs to be added for the percent change, with a different color and padding
For each case-to-case, calculate the percent change, and set the string format in a list comprehension.
Set the list of string formatted calculations to the labels parameter in .bar_label.
Given the code in the OP, 6 lines of code need to be added, 3 for creating the list of labels, and 3 for adding the labels to the plot.
Additional resources:
matplotlib: Bar Label Demo
Adding value labels on a matplotlib bar chart
Tested in python 3.8.11, matplotlib 3.4.3
change_case0_to_case1_system1 = np.subtract(value_case1_system1, value_case0_system1)
# add list of string formatted percent change calculation
per_change_case0_to_case1_system1 = [f'({v}%)' for v in (change_case0_to_case1_system1 / value_case0_system1).round(2)*100]
change_case1_to_case2_system1 = np.subtract(value_case2_system1, value_case1_system1)
# add list of string formatted percent change calculation
per_change_case1_to_case2_system1 = [f'({v}%)' for v in (change_case1_to_case2_system1 / value_case1_system1).round(2)*100]
change_case1_to_case2_system2 = np.subtract(value_case2_system2, value_case1_system2)
# add list of string formatted percent change calculation
per_case1_to_case2_system2 = [f'({v}%)' for v in (change_case1_to_case2_system2 / value_case1_system2).round(2)*100]
fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(18,10))
labels = ['Group 1', 'Group 2', 'Group 3']
x = np.arange(len(labels))
width = 0.28
ax0.set_xticks(x)
ax0.set_xticklabels(labels, fontsize=15)
rects1 = ax0.bar(x-width/2, change_case0_to_case1_system1, width, label='Case 0 to Case 1', color='#292929', edgecolor='black', linewidth=1)
rects2 = ax0.bar(x+width/2, change_case1_to_case2_system1, width, label='Case 1 to Case 2', color='#7f6d5f', edgecolor='black', linewidth=1)
ax0.bar_label(rects1, padding=3, fontsize=11)
# add a second annotation with the string formatted labels
ax0.bar_label(rects1, labels=per_change_case0_to_case1_system1, padding=15, fontsize=11, color='red')
ax0.bar_label(rects2, padding=3, fontsize=11)
# add a second annotation with the string formatted labels
ax0.bar_label(rects2, labels=per_change_case1_to_case2_system1, padding=15, fontsize=11, color='red')
rects3 = ax1.bar(x, change_case1_to_case2_system2, width, label='Case 1 to Case 2', color='#7f6d5f', edgecolor='black', linewidth=1)
ax1.set_xticks(x)
ax1.set_xticklabels(labels,fontsize=15)
ax1.bar_label(rects3, padding=3, fontsize=11)
# add a second annotation with the string formatted labels
ax1.bar_label(rects3, labels=per_case1_to_case2_system2, padding=15, fontsize=11, color='red')
plt.tight_layout()
plt.show()

How to change the diagonal rotation of a x-axis label on chart?

I am trying to figure out how change the rotation of dates on the x-axis of my chart. See below the image. I have examples of how to do it, but they don't match well as I have twin y axis's. Can you help change the rotation of the dates?
Here is my code:
fig, ax1 = plt.subplots()
fig = plt.figure(figsize=(8,6))
t = df['date']
s1 = df['msft']
ax1.plot(t, s1, 'b-')
ax1.set_xlabel('Dates')
ax1.legend(loc=0)
ax1.grid()
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('Price', color='b')
ax1.tick_params('y', colors='b')
ax2 = ax1.twinx()
s2 = df['amzn']
ax2.plot(t, s2, 'r-')
ax2.set_ylabel('amzn', color='r')
ax2.tick_params('date', colors='r')
ax2.legend(loc=0)
fig.tight_layout()
plt.show()
I added ax1.set_xticklabels(t, rotation=45), this line got the dates to be at a 45 degree angle. –

Bar plot with polar axis

I want to make my plot similar to this-
Currently, what I am able to get is this:
I am not able to do the following things:
Get the time labels inside the inner circle
Get the ticks inside the circle. This question - How to create minor ticks for polar plot matplotlib, had an idea which I tried but it was messing up with other parts of the plot.
Time labels only work properly when the step size is 3. For other steps, it does not align with the bars.
Below is the reproducible code to produce the plot
arr = np.random.randint(0, 24, size = 50000)
df = pd.DataFrame({"COL": arr}).COL.value_counts().sort_index()
N = 24
bottom = 1000
theta, width = np.linspace(0.0, 2 * np.pi, N, endpoint=False, retstep=True)
plt.figure(figsize = (10, 6))
ax = plt.subplot(111, polar=True)
bars = ax.bar(
theta, df,
width=width-0.03,
bottom=bottom,
color="#f39c12", edgecolor="black"
)
bars = ax.bar(
theta, [3000]*24,
width=width-0.03,
bottom=bottom,
color="#f39c12", alpha=0.2
)
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.grid(False)
ax.spines['polar'].set_visible(False)
ax.set_rticks([])
ticks = [f"{i}:00" for i in range(0, 24, 3)]
ax.set_xticklabels(ticks)
_ = ax
I just drew two lines and a circle to make the "clock icon"
## Draw a "clock" icon inside of the graph
##lines for hands of a clock
x1, y1 = [0, 90], [0, 0.5*bottom]
x2, y2 = [0,0], [0, 0.5*bottom]
plt.plot(x1, y1, x2, y2, linewidth=2.5, solid_capstyle='round', color='#0066ff', alpha=1)
##circle for clockface
circle = pl.Circle((0, 0), 0.65*bottom, transform=ax.transData._b, linewidth=3, fill=False, color="#0066ff", alpha=1)
ax.add_artist(circle)
did you ever figure out how to write the numbers inside of the clock?
Also if you wanna add the numbers inside of the circle do this:
#00, 06, 12, 18 labels for clockface
plt.text(0, bottom*.80, "00", transform=ax.transData._b, ha='center', va='center', color='black', fontsize=2.5, fontweight='bold')
plt.text(bottom*.80, 0, "06", transform=ax.transData._b, ha='center', va='center', color='black', fontsize=2.5, fontweight='bold')
plt.text(0, -bottom*.80, "12", transform=ax.transData._b, ha='center', va='center', color='black', fontsize=2.5, fontweight='bold')
plt.text(-bottom*.80, 0, "18", transform=ax.transData._b, ha='center', va='center', color='black', fontsize=2.5, fontweight='bold')
I know it's not the best or fanciest way to do this but it works OK! Please # me if you have a cleaner way to write this code haha..
Also some other notes:
-For the code i posted above change the sizes of the hour and minute hand to make it look even better (multiply bottom variable by different values below 1)
-I had to change the fontsize, and linewidths as I changed the size and dpi of the image to make it look right but its not too hard to figure out how to make it look right.
-I ended up not drawing the tick marks as it didn't seem worth my time to figure out how to do it. would love to know from anyone else if there's some way to space out dashes or something around there. But i really just didn't wanna mess with the rotation

Categories

Resources