I have a dataset with train and test sets and three classes A,B,and C. I want to create a plot in which I show the distribution of data labels in each class for TRAIN and TEST sets separately (these are binary class labels 0 and 1). Ideally, I would like to show TRAIN and TEST stats in different colours, maybe in a bar chart. These are the values:
a_train = [40,75]
a_test = [10,19]
b_train=[41,75]
b_test=[10,19]
c_train=[51,75]
c_test=[12,19]
I have tried to use pyplot but was confused how to create the plot:
import numpy as np
import matplotlib.pyplot as plt
top=[(['A',[[40,75],[10,19]]]),('B',[[41,75],[10,19]]),('C',[[51,75],[12,19]])]
labels, ys = zip(*top)
xs = np.arange(len(labels))
width = 1
plt.bar(xs, ys, width, align='center')
plt.xticks(xs, labels)
plt.yticks(ys)
which gives this error:
ValueError: shape mismatch: objects cannot be broadcast to a single shape
labels = ['a_train', 'a_test', 'b_train', 'b_test','c_train','c_test']
Positive = [40, 10, 41, 10, 51, 12]
Negative = [75, 19, 75, 19, 75, 19]
x = np.arange(len(labels))
width = 0.30 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(x - width/2, Positive, width, label='Positive')
rects2 = ax.bar(x + width/2, Negative, width, label='Negative')
ax.set_ylabel('Values')
ax.set_xticks(x)
ax.set_xticklabels(labels)
ax.legend()
plt.show()
Result
Related
Not at all sure what I'm doing wrong besides perhaps the order that I am plotting the ocean in. I am trying to get the ocean feature in to mask the data in the ocean. I am trying to get data to not appear in the ocean and to get the ax.add_feature(cfeature.OCEAN) to be on top of the temperature data I am plotting so I see ocean and no data. Similar to what is happening in the great lakes region where you see lakes and no temperature data.
proj_map = ccrs.Mercator(central_longitude=cLon)
proj_data = ccrs.PlateCarree()
fig = plt.figure(figsize=(30,20))
ax = fig.add_subplot(1,1,1, projection=proj_map)
ax.set_extent([-84,-66,37,47.5])
CT = ax.contourf(Tlat, Tlon, tempF, transform=temp.metpy.cartopy_crs, levels=clevs,
cmap=cmap)
ax.add_feature(cfeature.COASTLINE.with_scale('10m'), linewidth=0.5)
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.LAKES)
ax.add_feature(cfeature.BORDERS, linewidth=0.5)
ax.add_feature(cfeature.STATES.with_scale('10m'), linewidth=0.5)
ax.add_feature(USCOUNTIES.with_scale('20m'), linewidth=0.25)
cbar = fig.colorbar(CT, orientation='horizontal', shrink=0.5, pad=0.05)
cbar.ax.tick_params(labelsize=14)
cbar.set_ticks([-50, -40, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
110, 120])
cbar.ax.set_xlabel("Temp ($^\circ$F)",fontsize=20)
Here is what the image looks like
You need to use zorder option to specify proper orders of the plot on the map. Features with largers values of zorder will be plotted on top of those with lower values. In your case, you need zorder of the OCEAN larger than the filled-contour.
Here is a runnable demo code and its sample plot. Read comments in the code for explanation.
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(projection=ccrs.PlateCarree()))
extent = [-84, -66, 37, 47.5]
# generate (x, y), centered at the middle of the `extent`
mean = [(extent[0]+extent[1])/2, (extent[2]+extent[3])/2] #mean
cov = [[7, 3.5], [3.5, 6]] #co-variance matrix
x, y = np.random.multivariate_normal(mean, cov, 4000).T
# make a 2D histogram
# set the edges of the bins in x and y directions
bin_size = 40
lonrange = np.linspace(extent[0], extent[1], bin_size)
latrange = np.linspace(extent[2], extent[3], bin_size)
# the cell sizes of the bins:
dx = (lonrange[1]- lonrange[0])/2
dy = (latrange[3]- latrange[2])/2
# compute array of center points of the bins' grid
# the dimensions of mesh-grid < the edges by 1
lonrange2 = np.linspace(extent[0]+dx, extent[1]-dx, bin_size-1)
latrange2 = np.linspace(extent[2]+dy, extent[3]-dy, bin_size-1)
x2d, y2d = np.meshgrid(lonrange2, latrange2)
# create 2d-histogram
# zorder is set = 10
h = ax.hist2d(x, y, bins=[lonrange, latrange], zorder=10, alpha=0.75)
#h: (counts, xedges, yedges, image)
ax.add_feature(cfeature.OCEAN, zorder=12) #zorder > 10
ax.add_feature(cfeature.BORDERS, linewidth=0.5)
ax.gridlines(draw_labels=True, xlocs=list(range(-85, -60, 5)), ylocs=list(range(35, 50, 5)),
linewidth=1.8, color='gray', linestyle='--', alpha=0.8, zorder=20)
# plot colorbar, using image from hist2d's result
plt.colorbar(h[3], ax=ax, shrink=0.45)
# finally, show the plot.
plt.show()
The output plot:
If zorder option is not specified:
ax.add_feature(cfeature.OCEAN)
the plot will be:
Dears,
I have the following csv file
depth
lst
dol
Anhd
sst
50
20
40
80
100
100
25
50
85
100
150
15
35
75
100
I take the data from csv to draw subplot contains four curves in the same subplot, I have filled by red color from left edge to first curve, also I have filled by blue color from last curve to right edge, I want to fill between entire curves in between first and last curve and make color legend.
the table is equal to csv file
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import pandas as pd
import re
import json
test = r'D:\python\TEST-COMPOSITION.csv'
test =pd.read_csv(test)
mineral_names = test.drop(['depth'],axis=1)
mineral_names = list(mineral_names.columns.values)
colors = ["green", "gray"]
fig = plt.figure(figsize=(15, 12), dpi=100, tight_layout=True)
gs = gridspec.GridSpec(nrows=1, ncols=10, wspace=0)
fig.add_subplot(gs[0, 1])
for i in range(len(mineral_names)-1):
plt.plot(test[mineral_names[i]],test['depth'],linewidth=2, color='black')
for i in range(len(mineral_names)-1):
if i == 0:
left_col_value = 0
right_col_value = 100
span = abs(left_col_value - right_col_value)
cmap = plt.get_cmap('hot_r')
color_index = np.arange(left_col_value, right_col_value, span / 100)
for index in sorted(color_index):
index_value = (index - left_col_value) / span
plt.fill_betweenx(test['depth'],test[mineral_names[0]], left_col_value, where=test[mineral_names[i]] >= index, color="red")
if i == range(len(mineral_names)-1)[-1]:
left_col_value = 0
right_col_value = 100
span = abs(left_col_value - right_col_value)
cmap = plt.get_cmap('hot_r')
color_index = np.arange(left_col_value, right_col_value, span / 100)
for index in sorted(color_index):
index_value = (index - left_col_value) / span
plt.fill_betweenx(test['depth'],test[mineral_names[i]], right_col_value, where=test[mineral_names[i]] >= index, color="blue")
#if i ==1:
#plt.fill_betweenx(test['depth'], test[mineral_names[i+1]], test[mineral_names[i]],color = "green", alpha=0.4)
plt.gca().invert_yaxis()
plt.show()```
Here is an approach looping through the curves, and using a variable previous_curve which contains the position of the previous curve. At the start, the previous curve is all zeros. Similarly, the name of the previous curve can be saved and used as a label for the fill. All labels will appear in the default legend.
The example code below uses a gridspec with only 4 columns, to make the example plot a bit clearer.
import matplotlib.pyplot as plt
from matplotlib import gridspec
import pandas as pd
import numpy as np
test = pd.DataFrame({'depth': [50, 100, 150],
'lst': [20, 25, 15],
'dol': [40, 50, 35],
'Anhd': [80, 85, 75],
'sst': [100, 100, 100]})
mineral_names = test.columns[1:]
fig = plt.figure(figsize=(15, 12), dpi=100, tight_layout=True)
gs = gridspec.GridSpec(nrows=1, ncols=4, wspace=0)
ax = fig.add_subplot(gs[0, 1])
for mineral_name in mineral_names[:-1]:
ax.plot(test[mineral_name], test['depth'], linewidth=2, color='black')
colors = ["red", "green", "gray", "blue"]
previous_curve = 0
previous_name = ''
for mineral_name, color in zip(mineral_names, colors):
ax.fill_betweenx(test['depth'], previous_curve, test[mineral_name], color=color, alpha=0.4,
label=f'{previous_name} - {mineral_name}')
previous_curve = test[mineral_name]
previous_name = mineral_name
ax.margins(x=0, y=0) # no white space in plot
ax.invert_yaxis()
ax.legend()
plt.show()
I am working with a plot that contains an uneven length of data. I created another group of females (green bars), and I would like to label these two female groups F1 and F2.
Here is my code:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
labels = ['G1', 'G2', 'G3', 'G4']
labels2 = ['F1', 'F2']
male = [1, 3, 10, 20]
female = [2, 7]
female_2 = [3, 11]
x_male = np.arange(len(male))
x_female = np.arange(len(female))
offset_male = np.zeros(len(male))
offset_female = np.zeros(len(female))
shorter = min(len(x_male), len(x_female))
width = 0.25 # the width of the bars
offset_male[:shorter] = width/2
offset_female[:shorter] = width/2
fig, ax = plt.subplots()
rects1 = ax.bar(x_male - offset_male, male, width, label='male')
rects2 = ax.bar(x_female + offset_female, female, width, label='female')
rects3 = ax.bar(x_female + 3 * offset_female, female_2, width, label='female')
# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_xticks(x_male)
ax.set_xticklabels(labels)
ax.legend()
fig.tight_layout()
plt.show()
Do you have any idea how I can do it?
blend all ticks together
ax.set_xticks(list(x_male)+list(x_female + 3 * offset_female))
ax.set_xticklabels(labels+labels2)
I'm having a problem adding a colorbar to a plot of many lines corresponding to a power-law.
To create the color-bar for a non-image plot, I added a dummy plot (from answers here: Matplotlib - add colorbar to a sequence of line plots).
To colorbar ticks do not correspond to the colors of the plot.
I have tried changing the norm of the colorbar, and I can fine-tune it to be semy accurate for a particular case, but I can't do that generally.
def plot_loglog_gauss():
from matplotlib import cm as color_map
import matplotlib as mpl
"""Creating the data"""
time_vector = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256]
amplitudes = [t ** 2 * np.exp(-t * np.power(np.linspace(-0.5, 0.5, 100), 2)) for t in time_vector]
"""Getting the non-zero minimum of the data"""
data = np.concatenate(amplitudes).ravel()
data_min = np.min(data[np.nonzero(data)])
"""Creating K-space data"""
k_vector = np.linspace(0,1,100)
"""Plotting"""
number_of_plots = len(time_vector)
color_map_name = 'jet'
my_map = color_map.get_cmap(color_map_name)
colors = my_map(np.linspace(0, 1, number_of_plots, endpoint=True))
# plt.figure()
# dummy_plot = plt.contourf([[0, 0], [0, 0]], time_vector, cmap=my_map)
# plt.clf()
norm = mpl.colors.Normalize(vmin=time_vector[0], vmax=time_vector[-1])
cmap = mpl.cm.ScalarMappable(norm=norm, cmap=color_map_name)
cmap.set_array([])
for i in range(number_of_plots):
plt.plot(k_vector, amplitudes[i], color=colors[i], label=time_vector[i])
c = np.arange(1, number_of_plots + 1)
plt.xlabel('Frequency')
plt.ylabel('Amplitude')
plt.yscale('symlog', linthreshy=data_min)
plt.xscale('log')
plt.legend(loc=3)
ticks = time_vector
plt.colorbar(cmap, ticks=ticks, shrink=1.0, fraction=0.1, pad=0)
plt.show()
By comparing with the legend you see the ticks values don't match the actual colors. For example, 128 is shown in green in the colormap while red in the legend.
The actual result should be a linear-color colorbar. with ticks at regular intervals on the colorbar (corresponding to irregular time intervals...). And of course correct color for value of tick.
(Eventually the plot contains many plots (len(time_vector) ~ 100), I lowered the number of plots to illustrate and to be able to show the legend.)
To clarify, this is what I want the result to look like.
The most important principle is to keep the colors from the line plots and the ScalarMappable in sync. This means, the color of the line should not be taken from an independent list of colors, but rather from the same colormap and using the same normalization as the colorbar to be shown.
One major problem is then to decide what to do with 0 which cannot be part of a loagrithmic normalization. The following is a workaround assuming a linear scale between 0 and 2, and a log scale above, using a SymLogNorm.
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
"""Creating the data"""
time_vector = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256]
amplitudes = [t ** 2 * np.exp(-t * np.power(np.linspace(-0.5, 0.5, 100), 2)) for t in time_vector]
"""Getting the non-zero minimum of the data"""
data = np.concatenate(amplitudes).ravel()
data_min = np.min(data[np.nonzero(data)])
"""Creating K-space data"""
k_vector = np.linspace(0,1,100)
"""Plotting"""
cmap = plt.cm.get_cmap("jet")
norm = mpl.colors.SymLogNorm(2, vmin=time_vector[0], vmax=time_vector[-1])
sm = mpl.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])
for i in range(len(time_vector)):
plt.plot(k_vector, amplitudes[i], color=cmap(norm(time_vector[i])), label=time_vector[i])
#c = np.arange(1, number_of_plots + 1)
plt.xlabel('Frequency')
plt.ylabel('Amplitude')
plt.yscale('symlog', linthreshy=data_min)
plt.xscale('log')
plt.legend(loc=3)
cbar = plt.colorbar(sm, ticks=time_vector, format=mpl.ticker.ScalarFormatter(),
shrink=1.0, fraction=0.1, pad=0)
plt.show()
I wrote a python code below to draw a bar chart for my data. I adjusted parameters but failed to make it beautiful(See attached pic).
The python code is shown below:
def plotElapsedDis(axis, jvm1, jvm2, ylabel, title, name):
import matplotlib.pyplot as plt
import numpy as np
#fig, ax = plt.subplots(111)
fig = plt.figure()
ax = fig.add_subplot(111)
## the data
N = len(jvm1)
#menMeans = [18, 35, 30, 35, 27]
#womenMeans = [25, 32, 34, 20, 25]
ind = np.arange(N)+1
width = 0.25 # the width of the bars
rects1 = ax.bar(ind-width, jvm1, width)
rects2 = ax.bar(ind, jvm2, width, color='r')
ax.set_ylabel(ylabel)
ax.set_title(title)
plt.xticks(ind , axis, rotation=-90)
ax.legend( (rects1[0], rects2[0]), ('Originl', 'Optimal') )
plt.savefig(name)
plt.close()
plotElapsedDis(keys, y_jvm1, y_jvm2, 'seconds', 'CPU Elapsed', '../tmp/cpu_elapsed.jpg')
The first three lists for plotElapsedDis are:
keys= [u'mergesort_hongli', u'so_object', u'gc_mb', u'socket_transfer_1mb', u'app_factorial', u'string_concat', u'printff', u'so_lists', u'so_lists_small', u'word_anagrams', u'fasta', u'count_multithreaded', u'app_mandelbrot', u'primes', u'nbody', u'app_fib', u'socket_transfer_1mb_noblock', u'nsieve_bits', u'gc_string', u'simple_server', u'gc_array', u'cal', u'spectral_norm', u'app_pentomino', u'so_sieve', u'eval', u'so_matrix', u'mbari_bogus1', u'fractal', u'simple_connect', u'partial_sums', u'pi', u'so_array', u'count_shared_thread', u'fiber_ring', u'list', u'binary_trees', u'app_tarai', u'monte_carlo_pi', u'observ', u'write_large']
y_jvm1= [20.703852000000001, 173.12867899999998, 74.149726000000001, 15.717608999999999, 26.226012000000001, 136.44825599999999, 46.775888000000002, 63.851292000000001, 13.929881, 71.078192999999999, 66.729854000000003, 92.045006000000001, 55.671535999999996, 24.082338, 46.349951999999995, 38.166196999999997, 15.777601000000001, 123.075288, 161.76140800000002, 12.053167, 60.597787000000004, 43.662361000000004, 45.789037999999998, 209.30117999999999, 32.190105000000003, 48.988551000000001, 55.191608000000002, 52.242056999999996, 89.343417000000002, 12.721064999999999, 109.08541600000001, 24.236315000000001, 19.817986000000001, 226.82451600000002, 100.985647, 60.686772999999995, 55.589548000000001, 69.965362999999996, 35.801557000000003, 25.728088, 16.169540999999999]
y_jvm2= [19.938967999999999, 178.796818, 67.512734999999992, 15.787599, 26.058038, 137.27913000000001, 12.535093, 59.649929999999998, 13.865891000000001, 60.618783000000001, 68.384602999999998, 283.39391599999999, 56.349432, 24.923209999999997, 44.113292999999999, 40.564831999999996, 12.393115, 120.76664, 152.30684499999998, 12.195145, 64.276227000000006, 18.565175999999997, 48.006701, 212.65967000000001, 32.544051000000003, 49.798428000000001, 58.516103000000001, 17.243377000000002, 92.973864999999989, 12.519096000000001, 111.39406500000001, 27.048887000000001, 20.014955999999998, 280.62933700000002, 86.977775999999992, 61.553642000000004, 50.455328000000002, 70.610264999999998, 28.390682999999999, 28.378685000000001, 17.351361000000001]
The problems with this generated pic above are that:
The label for x-aixs are too long, which are truncated(out of figure border).
Distict the bars by others instead of color. Since the pic will be print so that distinction by color would not be work. How to fill bars of one group with different style (e.g, the last bar infigure).
I will appreciate if anyone can help adjust the outlook of this pic. Thanks!
I would consider you clean up the names a little bit, that should help. Once you do that, you can change the rotation to 45 which will make it look better.
You can do that by changing plt.xticks(ind , axis, rotation=90) to plt.xticks("range", "custom label list", rotation=90)
def plotElapsedDis(axis, jvm1, jvm2, ylabel, title, name):
import matplotlib.pyplot as plt
import numpy as np
#fig, ax = plt.subplots(111)
fig = plt.figure()
ax = fig.add_subplot(111)
## the data
N = len(jvm1)
#menMeans = [18, 35, 30, 35, 27]
#womenMeans = [25, 32, 34, 20, 25]
ind = np.arange(N)+1
width = 0.25 # the width of the bars
# add "hatch"
rects1 = ax.bar(ind-width, jvm1, width, color='white', edgecolor='black', hatch="*")
rects2 = ax.bar(ind, jvm2, width, color='white', edgecolor='black', hatch='//')
ax.set_ylabel(ylabel)
ax.set_title(title)
plt.xticks(ind , axis, rotation=90)
ax.legend( (rects1[0], rects2[0]), ('Originl', 'Optimal') )
fig.tight_layout() # make sure it fits
plt.show()
plotElapsedDis(keys, y_jvm1, y_jvm2, 'seconds', 'CPU Elapsed', '../tmp/cpu_elapsed.jpg')