Matplotlib fuzzy near 0 - python-3.x

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.

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 :-)

Equal spacing between pie charts of different sizes in matplotlib

I am having difficulties with setting an equal space between pie charts of different sizes. The 5 are correctly arranged in one row, but the distance between the contours of neighboring pies aren't equal. I tried many abbreviations of the following code, all of them not making a big difference in the output (see image):
#code:
import matplotlib.pyplot as plt
import pandas as pd
labels = 'Verkehr', 'Maschinen und Motoren', 'Feuerungen', 'Industrie / Gewerbe', 'Land- und Forstwirtschaft'
sizesax1 = [108295, 10107, 7220, 11551, 7220]
sizesax2 = [77882, 6676, 6676, 13351, 6676]
sizesax3 = [55652, 4417, 6184, 15900, 6184]
sizesax4 = [36327, 2642, 4632, 16512, 5944]
sizesax5 = [18781, 1409, 3287, 1878, 4695]
fig, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(1, 5, figsize =(20,4))
ax1.pie(sizesax1, startangle=0, colors = ('red', 'darkblue', 'orange', 'yellow', 'green'), radius=1*4)
ax2.pie(sizesax2, startangle=0, colors = ('red', 'darkblue', 'orange', 'yellow', 'green'), radius=.77*4)
ax3.pie(sizesax3, startangle=0, colors = ('red', 'darkblue', 'orange', 'yellow', 'green'), radius=.61*4)
ax4.pie(sizesax4, startangle=0, colors = ('red', 'darkblue', 'orange', 'yellow', 'green'), radius=.46*4)
ax5.pie(sizesax5, startangle=0, colors = ('red', 'darkblue', 'orange', 'yellow', 'green'), radius=.33*4)
some additions i tried:
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=1, hspace=None)
or
fig.tight_layout()
#giving me this error message:
/srv/conda/envs/notebook/lib/python3.7/site-packages/ipykernel_launcher.py:17: UserWarning:
Tight layout not applied. The bottom and top margins cannot be made large enough to
accommodate all axes decorations.
and some others.
Big thank you already for reading this! I am a complete beginner in python and just managed to come as far as you see in this image:
enter image description here
It is not clear what it is required. I'll assume it is the following image:
Fundamentally, the problem is that the pie needs a square aspect ratio, which is not provided by a row of subplots.
The simplest solution, is to create only one plot and plot there multiple pies with different centres. Something like:
import matplotlib.pyplot as plt
sizes = [ [108295, 10107, 7220, 11551, 7220],
[77882, 6676, 6676, 13351, 6676],
[55652, 4417, 6184, 15900, 6184],
[36327, 2642, 4632, 16512, 5944],
[18781, 1409, 3287, 1878, 4695]]
colors = ('red', 'darkblue', 'orange', 'yellow', 'green')
R = 4
radius = [R*i for i in [1.0, 0.77, 0.61, 0.46, 0.33] ]
wid = sum(radius)*2
hei = R*2
fig, ax = plt.subplots(figsize =(wid,hei))
fig.subplots_adjust(left = 0, right = 1, bottom = 0, top = 1)
y = R
x = 0
for i in range(5):
x += radius[i]
ax.pie(sizes[i], startangle = 0, colors = colors,
radius = radius[i], center = (x,y) )
x += radius[i]
ax.set(xlim =(0,x), ylim=(0,R*2))
plt.savefig("aaa.png")
Notice that my figure aspect ratio is not the (20,4) of the question, which does not hold for the way I interpreted the intended result.
But it might be the case that there is the need of having these in different axes. If so, the idea is:
Use gridspec to create a single row with 5 columns and provide the ratios so that they correspond to the required radius.
Plot the larger pie in the left slot.
In all remaining slots, use a subgrid, dividing into a column of three (sub-)slots.
Set the height ratios so that the middle one ends up with an aspect ratio of a square.
Plot the pies in the middle slots.
Here we go:
import matplotlib.pyplot as plt
sizes = [ [108295, 10107, 7220, 11551, 7220],
[77882, 6676, 6676, 13351, 6676],
[55652, 4417, 6184, 15900, 6184],
[36327, 2642, 4632, 16512, 5944],
[18781, 1409, 3287, 1878, 4695]]
colors = ('red', 'darkblue', 'orange', 'yellow', 'green')
R = 4
radius = [R*i for i in [1.0, 0.77, 0.61, 0.46, 0.33] ]
wid = sum(radius)*2
hei = R*2
ratios = [i/radius[0] for i in radius] # for gridspec
fig = plt.figure(figsize =(wid,hei))
gs = fig.add_gridspec(1, 5,
width_ratios = ratios,
wspace=0, left = 0, right = 1, bottom = 0, top = 1)
ax = fig.add_subplot(gs[0,0])
ax.pie(sizes[0], startangle = 0, colors = colors, radius = 1 )
ax.set(xlim=(-1,1) ,ylim=(-1,1))
for i in range(1,5):
mid = ratios[i]/sum(ratios)*wid
inrat = [(hei-mid)/2, mid, (hei-mid)/2]
ings = gs[0,i].subgridspec(3, 1, hspace=0,
height_ratios = inrat)
ax = fig.add_subplot(ings[1,0])
ax.pie(sizes[i], startangle = 0, colors = colors, radius = 1 )
ax.set(xlim=(-1,1), ylim=(-1,1))
plt.savefig("aaa.png")

How could I edit my code to plot 4D contour something similar to this example in python?

Similar to many other researchers on stackoverflow who are trying to plot a contour graph out of 4D data (i.e., X,Y,Z and their corresponding value C), I am attempting to plot a 4D contour map out of my data. I have tried many of the suggested solutions in stackover flow. From all of the plots suggested this, and this were the closest to what I want but sill not quite what I need in terms of data interpretation. Here is the ideal plot example: (source)
Here is a subset of the data. I put it on the dropbox. Once this data is downloaded to the directory of the python file, the following code will work. I have modified this script from this post.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.tri as mtri
#####Importing the data
df = pd.read_csv('Data_4D_plot.csv')
do_random_pt_example = False;
index_x = 0; index_y = 1; index_z = 2; index_c = 3;
list_name_variables = ['x', 'y', 'z', 'c'];
name_color_map = 'seismic';
if do_random_pt_example:
number_of_points = 200;
x = np.random.rand(number_of_points);
y = np.random.rand(number_of_points);
z = np.random.rand(number_of_points);
c = np.random.rand(number_of_points);
else:
x = df['X'].to_numpy();
y = df['Y'].to_numpy();
z = df['Z'].to_numpy();
c = df['C'].to_numpy();
#end
#-----
# We create triangles that join 3 pt at a time and where their colors will be
# determined by the values of their 4th dimension. Each triangle contains 3
# indexes corresponding to the line number of the points to be grouped.
# Therefore, different methods can be used to define the value that
# will represent the 3 grouped points and I put some examples.
triangles = mtri.Triangulation(x, y).triangles;
choice_calcuation_colors = 2;
if choice_calcuation_colors == 1: # Mean of the "c" values of the 3 pt of the triangle
colors = np.mean( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
elif choice_calcuation_colors == 2: # Mediane of the "c" values of the 3 pt of the triangle
colors = np.median( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
elif choice_calcuation_colors == 3: # Max of the "c" values of the 3 pt of the triangle
colors = np.max( [c[triangles[:,0]], c[triangles[:,1]], c[triangles[:,2]]], axis = 0);
#end
#----------
###=====adjust this part for the labeling of the graph
list_name_variables[index_x] = 'X (m)'
list_name_variables[index_y] = 'Y (m)'
list_name_variables[index_z] = 'Z (m)'
list_name_variables[index_c] = 'C values'
# Displays the 4D graphic.
fig = plt.figure(figsize = (15,15));
ax = fig.gca(projection='3d');
triang = mtri.Triangulation(x, y, triangles);
surf = ax.plot_trisurf(triang, z, cmap = name_color_map, shade=False, linewidth=0.2);
surf.set_array(colors); surf.autoscale();
#Add a color bar with a title to explain which variable is represented by the color.
cbar = fig.colorbar(surf, shrink=0.5, aspect=5);
cbar.ax.get_yaxis().labelpad = 15; cbar.ax.set_ylabel(list_name_variables[index_c], rotation = 270);
# Add titles to the axes and a title in the figure.
ax.set_xlabel(list_name_variables[index_x]); ax.set_ylabel(list_name_variables[index_y]);
ax.set_zlabel(list_name_variables[index_z]);
ax.view_init(elev=15., azim=45)
plt.show()
Here would be the output:
Although it looks brilliant, it is not quite what I am looking for (the above contour map example). I have modified the following script from this post in the hope to reach the required graph, however, the chart looks nothing similar to what I was expecting (something similar to the previous output graph). Warning: the following code may take some time to run.
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
df = pd.read_csv('Data_4D_plot.csv')
x = df['X'].to_numpy();
y = df['Y'].to_numpy();
z = df['Z'].to_numpy();
cc = df['C'].to_numpy();
# convert to 2d matrices
Z = np.outer(z.T, z)
X, Y = np.meshgrid(x, y)
C = np.outer(cc.T,cc)
# fourth dimention - colormap
# create colormap according to cc-value
color_dimension = C # change to desired fourth dimension
minn, maxx = color_dimension.min(), color_dimension.max()
norm = matplotlib.colors.Normalize(minn, maxx)
m = plt.cm.ScalarMappable(norm=norm, cmap='jet')
m.set_array([])
fcolors = m.to_rgba(color_dimension)
# plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X,Y,Z, rstride=1, cstride=1, facecolors=fcolors, vmin=minn, vmax=maxx, shade=False)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()
Now I was wondering from our kind community and experts if you can help me to plot a contour figure similar to the example graph (image one in this post), where the contours are based on the values within the range of C?

Add 3 or more legends to a seaborn clustermap

Using another answer, I'm wondering if it is possible to add 3 or more legends? Adapting the code from the author, I could add 4 row labels, but adding the legend is tricky. If I add more row_dendrogram and col_dendrogram, they simply do not show independently from the others.
import seaborn as sns
from matplotlib.pyplot import gcf
networks = sns.load_dataset("brain_networks", index_col=0, header=[0, 1, 2])
# Label 1
network_labels = networks.columns.get_level_values("network")
network_pal = sns.cubehelix_palette(network_labels.unique().size, light=.9, dark=.1, reverse=True, start=1, rot=-2)
network_lut = dict(zip(map(str, network_labels.unique()), network_pal))
network_colors = pd.Series(network_labels, index=networks.columns).map(network_lut)
# Label 2
node_labels = networks.columns.get_level_values("node")
node_pal = sns.cubehelix_palette(node_labels.unique().size)
node_lut = dict(zip(map(str, node_labels.unique()), node_pal))
node_colors = pd.Series(node_labels, index=networks.columns).map(node_lut)
# Label 3
lab3_labels = networks.columns.get_level_values("node")
lab3_pal = sns.color_palette("hls", lab3_labels.unique().size)
lab3_lut = dict(zip(map(str, lab3_labels.unique()), lab3_pal))
lab3_colors = pd.Series(lab3_labels, index=networks.columns, name='lab3').map(lab3_lut)
# Label 4
lab4_labels = networks.columns.get_level_values("node")
lab4_pal = sns.color_palette("husl", lab4_labels.unique().size)
lab4_lut = dict(zip(map(str, lab4_labels.unique()), lab4_pal))
lab4_colors = pd.Series(lab4_labels, index=networks.columns, name='lab4').map(lab4_lut)
network_node_colors = pd.DataFrame(network_colors).join(pd.DataFrame(node_colors)).join(pd.DataFrame(lab3_colors)).join(pd.DataFrame(lab4_colors))
g = sns.clustermap(networks.corr(),
row_cluster=False, col_cluster=False,
row_colors = network_node_colors,
col_colors = network_node_colors,
linewidths=0,
xticklabels=False, yticklabels=False,
center=0, cmap="vlag")
# add legends
for label in network_labels.unique():
g.ax_col_dendrogram.bar(0, 0, color=network_lut[label], label=label, linewidth=0);
l1 = g.ax_col_dendrogram.legend(title='Network', loc="center", ncol=5, bbox_to_anchor=(0.47, 0.89), bbox_transform=gcf().transFigure)
for label in node_labels.unique():
g.ax_row_dendrogram.bar(0, 0, color=node_lut[label], label=label, linewidth=0);
l2 = g.ax_row_dendrogram.legend(title='Node', loc="center", ncol=2, bbox_to_anchor=(0.8, 0.89), bbox_transform=gcf().transFigure)
#how to add other row dendrograms here without them overlapping with the existing ones?
plt.show()
I believe the problem here is that one cannot directly access the axes of the plot. The legend is based on the bar graph, the row which you add. I have found the following workaround which, tbh, is not nice. But working. It follows the classical matplotlib problem of adding an artist to an ax, you can read more about it in the following posts:
1, 2, 3 and in the docs.
So what I do is that I save the objects of the bar plot when I create them and then later form the legend out of them. The full code is below. But maybe I would recommend contacting the author and raising a question/issue there.
import seaborn as sns
from matplotlib.pyplot import gcf
import matplotlib.pyplot as plt
# fig, axs = plt.subplots()
networks = sns.load_dataset("brain_networks", index_col=0, header=[0, 1, 2])
# Label 1
network_labels = networks.columns.get_level_values("network")
network_pal = sns.cubehelix_palette(network_labels.unique().size, light=.9, dark=.1, reverse=True, start=1, rot=-2)
network_lut = dict(zip(map(str, network_labels.unique()), network_pal))
network_colors = pd.Series(network_labels, index=networks.columns).map(network_lut)
# Label 2
node_labels = networks.columns.get_level_values("node")
node_pal = sns.cubehelix_palette(node_labels.unique().size)
node_lut = dict(zip(map(str, node_labels.unique()), node_pal))
node_colors = pd.Series(node_labels, index=networks.columns).map(node_lut)
# Label 3
lab3_labels = networks.columns.get_level_values("node")
lab3_pal = sns.color_palette("hls", lab3_labels.unique().size)
lab3_lut = dict(zip(map(str, lab3_labels.unique()), lab3_pal))
lab3_colors = pd.Series(lab3_labels, index=networks.columns, name='lab3').map(lab3_lut)
# Label 4
lab4_labels = networks.columns.get_level_values("node")
lab4_pal = sns.color_palette("husl", lab4_labels.unique().size)
lab4_lut = dict(zip(map(str, lab4_labels.unique()), lab4_pal))
lab4_colors = pd.Series(lab4_labels, index=networks.columns, name='lab4').map(lab4_lut)
network_node_colors = pd.DataFrame(network_colors).join(pd.DataFrame(node_colors)).join(pd.DataFrame(lab3_colors)).join(pd.DataFrame(lab4_colors))
g = sns.clustermap(networks.corr(),
row_cluster=False, col_cluster=False,
row_colors = network_node_colors,
col_colors = network_node_colors,
linewidths=0,
xticklabels=False, yticklabels=False,
center=0, cmap="vlag")
# add legends
for label in network_labels.unique():
g.ax_col_dendrogram.bar(0, 0, color=network_lut[label], label=label, linewidth=0);
l1 = g.ax_col_dendrogram.legend(title='Network', loc="center", ncol=5, bbox_to_anchor=(0.35, 0.89), bbox_transform=gcf().transFigure)
for label in node_labels.unique():
g.ax_row_dendrogram.bar(0, 0, color=node_lut[label], label=label, linewidth=0);
l2 = g.ax_row_dendrogram.legend(title='Node', loc="center", ncol=2, bbox_to_anchor=(0.66, 0.89), bbox_transform=gcf().transFigure)
# create a list for the bar plot patches
xx = []
for label in lab3_labels.unique():
x = g.ax_row_dendrogram.bar(0, 0, color=lab3_lut[label], label=label, linewidth=0)
xx.append(x)
# add the legend
legend3 = plt.legend(xx, lab3_labels.unique(), loc="center", title='lab3', bbox_to_anchor=(.78, 0.89), bbox_transform=gcf().transFigure)
# create a list for the bar plot patches
yy = []
for label in lab4_labels.unique():
y = g.ax_row_dendrogram.bar(0, 0, color=lab4_lut[label], label=label, linewidth=0)
yy.append(y)
# add the second legend
legend4 = plt.legend(yy, lab4_labels.unique(), loc="center", title='lab4', ncol=2, bbox_to_anchor=(.9, 0.89), bbox_transform=gcf().transFigure)
plt.gca().add_artist(legend3)

how to adjust width of bokeh heatmap and remove white space around

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

Resources