matplotlib nice plot , who knows the scheme used? - python

May somebody know which is the scheme of color used in this post for the example plot ? this blue magenta, green ? which kind of style it is ??
EDIT ah ok I thought that was a known schemes

The shown plot comes from this answer. The colors in use are just hardcoded and do not belong to any official color scheme. The line colors are
["#7aa0c4", "#ca82e1", "#8bcd50"]
The background color is
"#f6f9fd"
The complete script to generate the plot is also available here.
In general, if you like to reproduce the colors from some image you find it's often easiest to use a color picker.
Since I invented this "scheme", you may of course ask how I would imagine it to continue for more colors. A quick guess would be the following:
["#7aa0c4", "#ca82e1", "#8bcd50", "#df9f53", "#64b9a1", "#745ea6", "#db7e76"]
Example:
import numpy as np
import matplotlib.pyplot as plt
cols = ["#7aa0c4", "#ca82e1", "#8bcd50", "#df9f53", "#64b9a1",
"#745ea6", "#db7e76"]
plt.rcParams["axes.prop_cycle"] = plt.cycler("color", cols)
x = np.linspace(0,4*np.pi, 101)
fig, (ax, ax2) = plt.subplots(nrows=2)
for i in range(7):
ax.plot(x, np.sin(x)-0.2*i)
ax2.plot(x, np.sin(x-np.pi*i/7))
plt.show()

Related

Make all data points of a matplotlib plot homogeneously transparent

I'd like to plot two scatter plots into the same Axes and turn the upper one's data points transparent such that the other plot shines through. However, I want the whole upper plot to have a homogeneous transparency level, such that superimposed markers of the upper plot do not add up their opacity as they would do if I simply set alpha=0.5.
In other words, I'd like both scatter plots to be rendered first and being set to one constant transparency level. Technically this should be possible for both raster and vector graphics (as SVG supports layer transparency, afaik), but either would be fine for me.
Here is some example code that displays what I do not want to achieve. ;)
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(1, figsize=(6,4), dpi=160)
ax = fig.gca()
s1 = ax.scatter(np.random.randn(1000), np.random.randn(1000), color="b", edgecolors="none")
s2 = ax.scatter(np.random.randn(1000), np.random.randn(1000), color="g", edgecolors="none")
s2.set_alpha(0.5) # sadly the same as setting `alpha=0.5`
fig.show() # or display(fig)
I'd like the green markers around (2,2) to not be darker where they superimpose, for example. Is this possible with matplotlib?
Thanks for your time! :)
After searching some more, I found related questions and two solutions, of which at least one kind of works for me:
As I hoped one can render one layer and then afterwards blend them together like this:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(1, figsize=(6,4), dpi=160)
ax1 = fig.gca()
s1 = ax1.scatter(np.random.randn(1000), np.random.randn(1000), color="#3355ff", edgecolors="none")
ax1.set_xlim(-3.5,3.5)
ax1.set_ylim(-3.5,3.5)
ax1.patch.set_facecolor("none")
ax1.patch.set_edgecolor("none")
fig.canvas.draw()
w, h = fig.canvas.get_width_height()
img1 = np.frombuffer(fig.canvas.buffer_rgba(), np.uint8).reshape(h, w, -1).copy()
ax1.clear()
s2 = ax1.scatter(np.random.randn(1000), np.random.randn(1000), color="#11aa44", edgecolors="none")
ax1.set_xlim(-3.5,3.5)
ax1.set_ylim(-3.5,3.5)
ax1.patch.set_facecolor("none")
ax1.patch.set_edgecolor("none")
fig.canvas.draw()
img2 = np.frombuffer(fig.canvas.buffer_rgba(), np.uint8).reshape(h, w, -1).copy()
fig.clf()
plt.imshow(np.minimum(img1,img2))
plt.subplots_adjust(0, 0, 1, 1)
plt.axis("off")
plt.show()
I may have to come up with better methods than just taking the np.minimum of both layers to keep more color options (and probably save the axes and labels to a third layer).
I did not try mplcairo as suggested in the other linked answer as it has too many dependencies for my use case (my solution should be portable).
I am still happy for additional input. :)

How to use a colored shape as yticks in matplotlib or seaborn?

I am working on a task called knowledge tracing which estimates the student mastery level over time. I would like to plot a similar figure as below using the Matplotlib or Seaborn.
It uses different colors to represent a knowledge concept, instead of a text. However, I have googled and found there is no article is talking about how we can do this.
I tried the following
# simulate a record of student mastery level
student_mastery = np.random.rand(5, 30)
df = pd.DataFrame(student_mastery)
# plot the heatmap using seaborn
marker = matplotlib.markers.MarkerStyle(marker='o', fillstyle='full')
sns_plot = sns.heatmap(df, cmap="RdYlGn", vmin=0.0, vmax=1.0)
y_limit = 5
y_labels = [marker for i in range(y_limit)]
plt.yticks(range(y_limit), y_labels)
Yet it simply returns the __repr__ of the marker, e.g., <matplotlib.markers.MarkerStyle at 0x1c5bb07860> on the yticks.
Thanks in advance!
While How can I make the xtick labels of a plot be simple drawings using matplotlib? gives you a general solution for arbitrary shapes, for the shapes shown here, it may make sense to use unicode symbols as text and colorize them according to your needs.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(42)
fig, ax = plt.subplots()
ax.imshow(np.random.rand(3,10), cmap="Greys")
symbolsx = ["⚪", "⚪", "⚫", "⚫", "⚪", "⚫","⚪", "⚫", "⚫","⚪"]
colorsx = np.random.choice(["#3ba1ab", "#b43232", "#8ecc3a", "#893bab"], 10)
ax.set_xticks(range(len(symbolsx)))
ax.set_xticklabels(symbolsx, size=40)
for tick, color in zip(ax.get_xticklabels(), colorsx):
tick.set_color(color)
symbolsy = ["◾", "◾", "◾"]
ax.set_yticks(range(len(symbolsy)))
ax.set_yticklabels(symbolsy, size=40)
for tick, color in zip(ax.get_yticklabels(), ["crimson", "gold", "indigo"]):
tick.set_color(color)
plt.show()

Remove white traces around contours from tricontourf

I'm trying to make a colormap in Python, and I have everything except this minor annoyance that is making the map look bad.
The code is straightforward. I am just using a matrix of values and plotting them using tricontourf. I am the looping over collections in my plot and changing the edgecolor and linewidth.
What I've noticed is the following. Say I want a thin white line around every contour, then I do.
CS = plt.tricontourf(X,Y,Z, 70, cmap=cm.seismic, antialiased=True)
print CS.collections
for c in CS.collections:
c.set_edgecolor('white')
c.set_linewidth(1)
plt.colorbar()
plt.show()
and get
Now obviously we look at this and say, well, the white lines around the contours look pretty bad, lets get rid of them. You could do this in a number of ways, perhaps by setting the linewidth=0 or the color to 'none'. I'll just do both in the following code. We have
CS = plt.tricontourf(X,Y,Z, 70, cmap=cm.seismic, antialiased=True)
print CS.collections
for c in CS.collections:
c.set_edgecolor('none')
c.set_linewidth(0)
plt.colorbar()
plt.show()
and get
Better, but do you still see the faint outlines of the contours? This is not just a shift in color from the colormap - this is clearly a very light line going through each contour.
Is there a way to somehow blend the colormap so that this doesn't happen? Thanks.
When you save a picture in pdf format, the problem becomes even more visible. With an increase in the number of contours, the picture is smoothed, but there are still problems with pdf.
For example:
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import uniform
x = uniform(-2,2,200)
y = uniform(-2,2,200)
z = x*np.exp(-x**2-y**2)
plt.tricontourf(x,y,z, 300, cmap="seismic", antialiased=False)
plt.colorbar()
plt.savefig('stackoverflow/tricontourf.pdf')
plt.savefig('stackoverflow/tricontourf.png', dpi=300)
But very light lines running through each contour are still visible in pdf.
A partial solution is to use tricontour instead of tricontourf with some linewidths option:
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import uniform
#Some Data
x = uniform(-2,2,200)
y = uniform(-2,2,200)
z = x*np.exp(-x**2-y**2)
plt.tricontour(x,y,z, 300, cmap="seismic", antialiased=False, linewidths=5)
plt.colorbar()
plt.savefig('stackoverflow/tricontour.pdf')
plt.savefig('stackoverflow/tricontour.png', dpi=300)
tricontourf does not support this option.
You can overlap a tricontour plot with the same colormap used in your tricontourf. This will effectively get rid of the white traces.

How to make matplotlib graphs look professionally done like this? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
Default matplotlib graphs look really unattractive and even unprofessional. I tried out couple of packages include seaborn as well as prettyplotlib but both of these just barely improves the styles.
So far I've gotten to following using seaborn package:
Below is the appearance I'm looking for which is far cry from above:
Notice the following niceness in the 2nd example:
Area under the graph is filled with much more eye pleasing color.
The graph line is thinker and nicely stands out.
Axis lines are thinker and again nicely stands out.
Area under the curve is transparent.
X-Axis tick marks are more denser.
My questions are: Do you recognize above as some kind of popular theme or style that I can quickly use in matplotlib? Or if I can use from some package? Failing that, is there anyway to set this style as my global preference? Failing that, is it even possible to do this in matlibplot?
Thanks!
This is really a matter of taste, and also a matter of target audience. matplotlib tries to produce clear illustrations for scientific purposes. This is - necessarily - a compromise, and the illustrations are not something you would print in a magazine or show in an advertisement.
There are some good news and some bad news about matplotlib in this sense.
Bad news:
There is no single magical command or package which would create beautiful plots with matplotlib.
Good news:
There are simple ways to change the default settings, see: http://matplotlib.org/users/customizing.html
The object model enables the user to change almost everything and introduce complex new features.
The source code is available, and even it can be changed quite easily by the user.
In my opinion the most difficult thing is to decide what you want. Then doing what you want is easier, even though there is a steepish learning curve in the beginning.
Just as an example:
import numpy as np
import matplotlib.pyplot as plt
# create some fictive access data by hour
xdata = np.arange(25)
ydata = np.random.randint(10, 20, 25)
ydata[24] = ydata[0]
# let us make a simple graph
fig = plt.figure(figsize=[7,5])
ax = plt.subplot(111)
l = ax.fill_between(xdata, ydata)
# set the basic properties
ax.set_xlabel('Time of posting (US EST)')
ax.set_ylabel('Percentage of Frontpaged Submissions')
ax.set_title('Likelihood of Reaching the Frontpage')
# set the limits
ax.set_xlim(0, 24)
ax.set_ylim(6, 24)
# set the grid on
ax.grid('on')
(Just a comment: The X-axis limits in the original image do not take the cyclicity of the data into account.)
This will give us something like this:
It is easy to understand that we need to do a lot of changes in order to be able to show this to a less-engineering-minded audience. At least:
make the fill transparent and less offensive in colour
make the line thicker
change the line colour
add more ticks to the X axis
change the fonts of the titles
# change the fill into a blueish color with opacity .3
l.set_facecolors([[.5,.5,.8,.3]])
# change the edge color (bluish and transparentish) and thickness
l.set_edgecolors([[0, 0, .5, .3]])
l.set_linewidths([3])
# add more ticks
ax.set_xticks(np.arange(25))
# remove tick marks
ax.xaxis.set_tick_params(size=0)
ax.yaxis.set_tick_params(size=0)
# change the color of the top and right spines to opaque gray
ax.spines['right'].set_color((.8,.8,.8))
ax.spines['top'].set_color((.8,.8,.8))
# tweak the axis labels
xlab = ax.xaxis.get_label()
ylab = ax.yaxis.get_label()
xlab.set_style('italic')
xlab.set_size(10)
ylab.set_style('italic')
ylab.set_size(10)
# tweak the title
ttl = ax.title
ttl.set_weight('bold')
Now we have:
This is not exactly as in the question, but everything can be tuned towards that direction. Many of the things set here can be set as defaults for matplotlib. Maybe this gives an idea of how to change things in the plots.
To get closer to the style you prefer, you could use the whitegrid style in seaborn. As the other answers have noted, you control the transparency of the fill with the alpha parameter to fill_between.
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_style("whitegrid")
blue, = sns.color_palette("muted", 1)
x = np.arange(23)
y = np.random.randint(8, 20, 23)
fig, ax = plt.subplots()
ax.plot(x, y, color=blue, lw=3)
ax.fill_between(x, 0, y, alpha=.3)
ax.set(xlim=(0, len(x) - 1), ylim=(0, None), xticks=x)
More information on seaborn styles can be found in the docs.
matplotlib is almost infinitely flexible so you can do almost anything with it and if it doesn't exist you can write it yourself! Obviously the defaults are bland, this is because everyone has there own idea of what is "nice" so it is pointless to impose a predefined style.
Here is a really simple example that addresses 4 of your points.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
x = np.linspace(-10, 10, 1000)
y = 1+np.sinc(x)
ax = plt.subplot(111)
ax.plot(x, y, lw=2)
ax.fill_between(x, 0, y, alpha=0.2)
ax.grid()
majorLocator = MultipleLocator(1)
ax.xaxis.set_major_locator(majorLocator)
plt.show()
If your want to set defaults so all your plots look the same then you should generate a custom matplotlibrc file or use style. A useful guide is here. To view a list of all the available options just call print plt.rcParams from an interactive terminal.
Some of the other features such as filling will need to be done on a per plot basis. You can standardise this across your work by creating a function which adds the fill between given some input such as the axis instance and data.
You can customize plots style as follow:
import numpy as np
import matplotlib.pyplot as plt
plt.use_style('ggplot') # customize your plots style
x = np.linspace(0,2*np.pi,100)
y = np.sin(x)
plt.fill_between(x,y)
plt.show()

How to format contour lines from Matplotlib

I am working on using Matplotlib to produce plots of implicit equations (eg. y^x=x^y). With many thanks to the help I have already received I have got quite far with it. I have used a contour line to produce the plot. My remaining problem is with formatting the contour line eg width, color and especially zorder, where the contour appears behind my gridlines. These work fine when plotting a standard function of course.
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import numpy as np
fig = plt.figure(1)
ax = fig.add_subplot(111)
# set up axis
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# setup x and y ranges and precision
x = np.arange(-0.5,5.5,0.01)
y = np.arange(-0.5,5.5,0.01)
# draw a curve
line, = ax.plot(x, x**2,zorder=100,linewidth=3,color='red')
# draw a contour
X,Y=np.meshgrid(x,y)
F=X**Y
G=Y**X
ax.contour(X,Y,(F-G),[0],zorder=100,linewidth=3,color='green')
#set bounds
ax.set_xbound(-1,7)
ax.set_ybound(-1,7)
#add gridlines
ax.xaxis.set_minor_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.2))
ax.xaxis.grid(True,'minor',linestyle='-',color='0.8')
ax.yaxis.grid(True,'minor',linestyle='-',color='0.8')
plt.show()
This is rather hackish but...
Apparently in the current release Matplotlib does not support zorder on contours. This support, however, was recently added to the trunk.
So, the right way to do this is either to wait for the 1.0 release or just go ahead and re-install from trunk.
Now, here's the hackish part. I did a quick test and if I changed line 618 in
python/site-packages/matplotlib/contour.py
to add a zorder into the collections.LineCollection call, it fixes your specific problem.
col = collections.LineCollection(nlist,
linewidths = width,
linestyle = lstyle,
alpha=self.alpha,zorder=100)
Not the right way to do things, but might just work in a pinch.
Also off-topic, if you accept some responses to your previous questions, you probably get quicker help around here. People love those rep points :)

Categories

Resources