Jeff Coldplume
Jeff Coldplume

Reputation: 353

How to change ytick label colors based on a condition

Here is some data I will use to demonstrate my question. This is a question branching from one of my old questions found here.

Alright so to start, I am implementing this code:

1) Load in the data and establish valid and non valid data.

df = pd.read_excel('Downloads/output.xlsx', index_col='date')

good_ranges = []
for i in df:
    col = df[i]
    gauge_name = col.name

    start_mark = (col.notnull() & col.shift().isnull())
    start = col[start_mark].index

    end_mark = (col.notnull() & col.shift(-1).isnull())
    end = col[end_mark].index

    for s, e in zip(start, end):
        good_ranges.append((gauge_name, s, e))
good_ranges = pd.DataFrame(good_ranges, columns=['gauge', 'start', 'end'])

good_ranges yields:

                                                gauge      start        end
0               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-02-06 2019-08-27
1               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-08-30 2019-10-01
2               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-10-09 2019-10-19
3               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-10-22 2019-10-22
4               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-10-25 2019-10-25
5               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-10-27 2019-10-31
6               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-11-05 2019-11-29
7               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-12-01 2019-12-02
8               GALISTEO CREEK BELOW GALISTEO DAM, NM 2019-12-04 2019-12-29
9               GALISTEO CREEK BELOW GALISTEO DAM, NM 2020-01-01 2020-01-02
10              GALISTEO CREEK BELOW GALISTEO DAM, NM 2020-01-04 2020-01-17
11              GALISTEO CREEK BELOW GALISTEO DAM, NM 2020-01-19 2020-02-04
12                     RIO GRANDE AT OTOWI BRIDGE, NM 2019-02-06 2020-02-04 

2) Create the plot of the data where there is valid data

fig, ax = plt.subplots(figsize=(14,8))
ax = ax.xaxis_date()
ax = plt.hlines(good_ranges['gauge'], 
                dt.date2num(good_ranges['start']), 
                dt.date2num(good_ranges['end']))
fig.tight_layout()
plt.show()

3) Find the total number of valid Daily Data Days; specify locations with >350 days of valid data

c = good_ranges[['start','end']]
good_ranges['Days'] = good_ranges['end'] - good_ranges['start']
good_ranges['Days'] = good_ranges['Days'].dt.days
df_days = good_ranges.filter(['gauge','Days'], axis=1)
df_new = df_days.groupby(df_days['gauge']).sum()
df_new['Day_Con'] = np.nan
df_new['Day_Con'] = 'YES'
df_new.loc[df_new['Days'] > 350,'Day_Con'] = 'NO'

#### Sort the gauge so that the list will line up with the list of ylabels
df_new = df_new.sort_values("gauge",ascending=False)
print(df_new)
yes_idxs = list(np.where(df_new["Day_Con"] == "YES")[0])
print(yes_idxs)
no_idxs = list(np.where(df_new["Day_Con"] == "NO")[0])
print(no_idxs)

This is what the df_new parameter yields after finding gauge sites with >350 days of data

gauge                                                          
TESUQUE CREEK ABOVE DIVERSIONS NEAR SANTA FE, NM    310     YES
SANTA FE RIVER NEAR SANTA FE, NM                    336     YES
SANTA FE RIVER ABOVE MCCLURE RES, NR SANTA FE, NM   344     YES
SANTA FE RIVER ABOVE COCHITI LAKE, NM               363      NO
SANTA CRUZ RIVER NEAR CUNDIYO, NM                   304     YES
RIO TESUQUE BELOW DIVERSIONS NEAR SANTA FE, NM      361      NO
RIO NAMBE BELOW NAMBE FALLS DAM NEAR NAMBE, NM      363      NO
RIO NAMBE ABOVE NAMBE FALLS DAM NEAR NAMBE, NM      267     YES
RIO GRANDE AT OTOWI BRIDGE, NM                      363      NO
GALISTEO CREEK BELOW GALISTEO DAM, NM               328     YES

yes_idxs yields:

[0, 1, 2, 4, 7, 9]

no_idxs yields:

[3, 5, 6, 8]

I was thinking I could specify the yes_idxs and no_idxs to help me specify the ylabel color on the correct label locations. However, when I run the code below, you can only specify an integer or index to get this to work.

ax.get_yticklabels()[1].set_color("red")

In essence, I want to be able to do is highlight the horizontal lines and/or ylabels text to be red if the values do not meet the criteria of being > 350 days. At the moment, I cannot seem to find an easy way to go about this.

Thank you in advance for the help!

Upvotes: 0

Views: 248

Answers (1)

wwii
wwii

Reputation: 23743

Tick labels are Text Artists and have a color properties. You can get a list of the labels from the plot's Axes and use those two lists as indices to change their color.

Toy plot with 10 x-axis ticks/labels

xs = [0,1,2,3,4,5,6,7,8,9]
ys = [n*2 for n in xs]

fig,ax = plt.subplots()
ax.plot(xs,ys)
ax.set_xticks(xs)
ax.set_xticklabels(xs)

Iterate over the x-axis tick labels and set their color based on a condition.

#Assuming the `yes` and `no` lists are indices
yes = [0, 1, 2, 4, 7, 9]
no = [3, 5, 6, 8]

tlabels = ax.get_xmajorticklabels()
for i,tl in enumerate(tlabels):
    if i in yes:
        tl.set_color('r')
    else:
        tl.set_color('b')
#plt.show()

You can also get to the labels through the tick.

for i,tick in enumerate(ax.xaxis.get_major_ticks()):
        if i in yes:
            tick.label.set_color('r')
        else:
            tick.label.set_color('b')

Ticks and tick labels
More Ticks and ticklabels

Upvotes: 1

Related Questions