how to adjust width of bokeh heatmap and remove white space around - python-3.x

I would like to change the width of the heatmap cell so that its dimensions are square (even). Ideally, the cells are small and square so that I can fit several heatmaps with just one column of data. I want to reproduce something like this:
My current code makes one heatmap that is too wide and there is lots of white space, as well as a strange y position that cuts off the bottom cell. Not sure what's going on. Thanks.
def genHeatMap():
colours = ['#67d33d',
'#76d74f',
'#84da5f',
'#91de6e',
'#9ce17b',
'#a6e488',
'#b1e795',
'#bbeaa1',
'#91de6e',
'#9ce17b']
values = [1.0,
0.17647058823529413,
0.08021390374331551,
0.04054054054054054,
0.06,
0.07894736842105263,
0.07317073170731707,
0.05813953488372093,
0.1320754716981132,
0.0]
y_labels=['103', '134', '140', '185', '235', '292', '299', '431', '566', '659']
y = list(range(10))
x = ['a'] * 10
df = {'xs':x,'ys':y,'value':values,'colour':colours,'labels':y_labels}
p = figure(x_range='a',y_range=y_labels,plot_width=300,plot_height=300,
tooltips = [('CSID', f'#labels-103'), ('Tanimoto', '#value')])
p.rect('xs', 'ys', width=1, height=1, source=df,color='colour', line_color="black")
p.toolbar.logo = None
p.min_border_bottom = 20
p.min_border_left = 0
p.min_border_right = 0
p.min_border_top = 0
p.xaxis.major_tick_line_color = None
p.xaxis.minor_tick_line_color = None
p.xaxis.major_label_text_font_size = '0pt'
return p

Set p.x_range.range_padding = 0
https://docs.bokeh.org/en/latest/docs/reference/models/ranges.html#bokeh.models.ranges.FactorRange.range_padding

Related

Make one y-axis label bold in matplotlib

Goodmorning,
Question, I've got this script that creates a horizontal bar chart (see image)
I would like to have one label in the y-axis bold "Nederland".
I've searched an tried a lot, but I really have no idea how I can do this.
I found this solution:
Matplotlib - Changing the color of a single x-axis tick label
But I could not get it to work.
Any hint to a solution would be great.
def AVG_BarChart(self, data:dict=None, graph_file:str = None, datum:str=None, countries:dict=None, watermarktext:str="energieprijzenbot.nl", prijsper:str="kWh")->bool:
plt.figure(figsize=(9, 6))
plt.xlabel(f"Prijs per {prijsper}")
plt.title(f"Gemiddelde {prijsper} inkoopprijs per land {datum}")
colors = ["#FE8000", "#EFBD76", "#FFA52B", "#FF9D3C", "#FFF858", "#FCFFCB", "#07EEB2", "#FF4179","#E05B4B", "#E09336", "#DAB552", "#DBD9A6", "#87B49C", "#4B8A7E", "#A5DD96", "#E1F3C9", "#0095AD", "#00D5E5", "#82E9F0", "#C0ED42", "#FFE301", "#FFF352", "#FF85DA", "#FF69B3","#A15AC4", "#3F7539", "#B8CBAD", "#E1E2C2", "#F84040", "#9D1E29"]
random.shuffle(colors)
values = 2 ** np.random.randint(2, 10, len(data))
max_value = values.max()
labels = list(data.keys())
values = list(data.values())
height = 0.9
plt.barh(y=labels, width=values, height=height, color=colors, align='center', alpha=0.8)
ax = plt.gca()
ax.xaxis.set_major_formatter('€ {x:n}')
plt.bar_label(ax.containers[0], labels=[f'€ {x:n}' for x in ax.containers[0].datavalues], label_type="edge", padding=-50)
ax.text(0.5, 0.5, watermarktext, transform=ax.transAxes,
fontsize=40, color='gray', alpha=0.3,
ha='center', va='center', rotation='30')
for i, (label, value) in enumerate(zip(labels, values)):
country_iso = self.get_key(val=label, my_dict=countries).lower()
self.offset_image(x=value, y=i, flag=country_iso, bar_is_too_short=value < max_value / 10, ax=ax)
plt.subplots_adjust(left=0.15)
plt.savefig(graph_file, bbox_inches='tight', width = 0.4)
return True
I tried looping thru the labels like this
i = 0
for w in ax.get_yticklabels():
country = ax.get_yticklabels()[i].get_text()
if country == "Nederland":
ax.get_yticklabels()[i].set_color('red')
ax.get_yticklabels()[i].set_fontweight('bold')
i += 1
When debugging I actually get a country name back, but when running the script normal, all country labels are empty...
So, I was close to the answer. But somehow I got back empty .get_text() string.
# ... some code
labels = list(data.keys())
# ... more code
ax.set_yticklabels(labels)
for lab in ax.get_yticklabels():
if lab.get_text() == "Nederland":
lab.set_fontweight('bold')
I just hope by setting the labels again, It does not mix up anything :-)

Bokeh colorbar, assign a tick to each color

I'm trying to plot an heatmap of a matrix containing some counts (called mat in my code, then df after change the structure to use it with Bokeh). The structure is like this:
X
element 1
element 2
element 3
category 1
0
6
4
category 2
1
7
3
category 3
5
2
10
category 4
0
1
4
Now with my code I'm using df.value.unique() both for the color mapper and the ticks, but in the heatmap the colorbar's ticks doesn't correspond to the colors:
How can I make the ticks coincide each one to one color? I'm quite sure I have to use the CategoricalColorMapper but with that I get only a white screen. Thank you for the help.
Here's my code:
mat = pd.read_csv("tests/count_50.dat", sep="\t", index_col=0)
mat.index.name = 'MGI_id'
mat.columns.name = 'phen_sys'
#set data as float numbers
mat=mat.astype(float)
#Create a custom palette and add a specific mapper to map color with values
df = mat.stack(dropna=False).rename("value").reset_index()
pal=bokeh.palettes.brewer['YlGnBu'][len(df.value.unique())]
mapper = LinearColorMapper(palette=pal, low=df.value.min(), high=df.value.max(), nan_color = 'gray')
#Define a figure
p = figure(
plot_width=1280,
plot_height=800,
title="Heatmap",
x_range=list(df.MGI_id.drop_duplicates()),
y_range=list(df.phen_sys.drop_duplicates()[::-1]),
tooltips=[('Phenotype system','#phen_sys'),('Gene','#MGI_id'),('Phenotypes','#value')],
x_axis_location="above",
output_backend="webgl")
#Create rectangles for heatmap
p.rect(
x="MGI_id",
y="phen_sys",
width=1,
height=1,
source=ColumnDataSource(df),
fill_color=transform('value', mapper))
p.xaxis.major_label_orientation = 45
#Add legend
t = df.value.unique()
t.sort()
color_bar = ColorBar(
color_mapper=mapper,
ticker=FixedTicker(ticks=t, desired_num_ticks=len(df.value.unique())),
label_standoff=6,
border_line_color=None)
p.add_layout(color_bar, 'right')
show(p)
I found a solution:
I create a factor list by ordering the values and then converting both the dataframe values and the factors. At that point I created a CategoricalColorMapper instead of the linear one and the plot now is correct:
Your list of values goes from 0 to 10, so ColorBar will go up to 10. You can change mapper 'high' value to '9':
mapper = LinearColorMapper(palette=colors, low=0, high=9, nan_color = 'gray')
Or a ColorBar that goes from 1 to 10:
mapper = LinearColorMapper(palette=colors, low=1, high=10, nan_color = 'gray')

Matplotlib fuzzy near 0

Hi all, two questions:
First: Can anyone tell me what that fuzzy scrible near the 0 on the x and y axis is and how to remove it?
Second: I know that rects1 output ['42', '12', '167', '80', '197', '210', '41'] why is it showing 0,1,2,3,4,5,6? what am i missing?
ylst = []
xlst = []
xlst1 = []
figure = Figure(figsize=(9, 6), dpi=180)
for xgrp in get_days_week(3):
xlst.append(media_dia(xgrp).get("totmedia<1h", "ERRO"))
xlst1.append(tempo_dia(xgrp).get("tot_viag", "ERRO"))
ylst.append(str(xgrp))
x = np.arange(len(ylst)) # the label locations
y = np.arange(len(xlst1))
width = 0.25 # the width of the bars
figure, ax = plt.subplots()
rects1 = ax.bar(x - width / 2, xlst, width, label="N veiculos com media viagem < 1h")
rects2 = ax.bar(x + width / 2, xlst1, width, label="Total Viagens")
figure.set_figheight(6)
figure.set_figwidth(8)
ax.set_title(titulo)
ax.legend()
ax.set_xlabel(xname)
#ax.set_ylabel(yname)
ax.bar_label(rects1, padding=3)
ax.bar_label(rects2, padding=3)
ax.set_xticks(x)
ax.set_xticklabels(ylst)
# ax.set_yticks(y)
# ax.set_yticklabels(xlst1)
print("::: ",y)
print("-> ",xlst1)
# ax.set_yticklabels(np.arange(200))
figure.tight_layout()
canvas = FigureCanvasTkAgg(figure, graphframe)
canvas.get_tk_widget().grid(row=1, column=col)
Im sorry for the two questions but since its the same code and are problably connected i hope its alright.

What is equivalent of seaborn's hue in Matplotlib?

May I ask what is the equivalent of hue in Matplotlib? I have a line of seaborn code and would need to convert it into Matplotlib format. Each box corresponds to 1 ID at that time. How do i create a legend as well? The dataframe dataset_filtered has 3 columns: time_window (x axis), id and LagTime which is y axis.
sns.catplot(x='time_window', hue='ID', y='LagTime', data= dataset_filtered, kind="box",showfliers=False)
This is what I have written so far but it is not working...
# Generate a color dictionary using RGB for each Id
colors = []
for num in range(len(unique_id)):
num = num + 1
color = (1/num, 1/num, 1/num)
colors.append(color)
color_dictionary = dict(zip(unique_id, colors))
plt.figure(figsize=(30,15))
for time_window in dataset_filtered.index.unique():
dataset_plot = dataset_filtered.loc[time_window]
box = dataset_plot.boxplot('LagTime',patch_artist=True,boxprops=dict(facecolor=color_dictionary['id']),medianprops=dict(color='black'),labels='id')
plt.xlim(-0.5,8)
plt.xticks(np.arange(0.2,10,0.5),dataset_filtered.index.unique())
handles, labels = plt.gca().get_legend_handles_labels()
by_label = OrderedDict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())
plt.xticklabels()

matplotlib set stacked bar chart labels

I am trying to create a stacked bar chart that groups data by operating system. I'm having trouble creating an individual label for each component in each bar.
What I'm trying to do is different from the example in the docs because in my data each category appears in only one bar, whereas in the example each bar contains one member of each category.
Currently I have this code
plt.cla()
plt.clf()
plt.close()
def get_cmap(n, name='hsv'):
'''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct
RGB color; the keyword argument name must be a standard mpl colormap name.'''
return plt.cm.get_cmap(name, n)
fig = plt.figure(figsize=(18, 10), dpi=80)
# group by the prefixes for now
prefixes = []
indices = []
bars = []
legend = {}
cmap = get_cmap(len(os_counts.index) + 1)
k = 0
for i, prefix in enumerate(d):
indices.append(i)
if len(d[prefix]["names"]) == 1:
prefixes.append(d[prefix]["names"][0])
else:
prefixes.append(prefix)
#colors = [next(cycol) for j in range(len(d[prefix]["names"]))]
colors = [cmap(k + j) for j in range(len(d[prefix]["names"]))]
k += len(colors)
bar = plt.bar([i] * len(d[prefix]["names"]), d[prefix]["values"], color=colors, label=d[prefix]["names"])
bars.append(bar)
plt.xticks(rotation=90)
plt.ylabel("Frequency")
plt.xlabel("Operating System")
plt.xticks(indices, prefixes)
plt.legend()
plt.show()
Which produces this result. As you can see, the legend is created for the first colour within the bar and shows an array.
I think that each call to plt.bar gets one label. So, you are giving it a list as a label for each plt.bar call. If you want a label for every color, representing every operating system then I think the solution is to call plt.bar once for each color or os.

Resources