I use matplotlib to generate data analysis plots, which I then show to people at conferences, in publications etc. I normally store all the data and scripts that generate every interesting/useful plot, just in case I need to update the charts at some point after creating them. Here's an example of my box-standard piece of code that generates the below plot:
# In[Imports]:
import pandas, matplotlib, matplotlib.pyplot
# In[Plot formatting]:
ticksFontSize = 18
labelsFontSize = 30
legendFontSize = 16
cm=matplotlib.pyplot.cm.get_cmap('viridis')
matplotlib.rc('xtick', labelsize=ticksFontSize)
matplotlib.rc('ytick', labelsize=ticksFontSize)
# In[Read the data]:
# CDF of TLE update frequenies
dfGood=pandas.read_csv('blue.csv',sep=',',header=None)
epochsGood=dfGood[0].values
cdfsGood=dfGood[1].values
# In[Plot the data]:
fig,ax=matplotlib.pyplot.subplots(1,1,sharex=True,figsize=(14,8))
ax.scatter(epochsGood,cdfsGood,c='indigo',marker='o',lw=0,s=30)
ax.set_xlabel(r"$TLE\ update\ frequency\ (orbital\ periods)$",
size=labelsFontSize)
ax.set_ylabel(r"$Cumulative\ Distribution\ Function\ (-)$",
fontsize=labelsFontSize)
ax.grid(linewidth=1)
ax.tick_params(axis='both',reset=False,which='both',
length=5,width=1.5)
ax.tick_params(axis='x', which='major', pad=15)
ax.set_xlim(0,5)
ax.set_ylim(0,1.1)
matplotlib.pyplot.subplots_adjust(left=0.1,right=0.95,
bottom=0.15,top=0.9)
fig.show()
Recently (within the last few months, but it could have been a long overdue update...), I updated matplotlib and the above script started generating a differently formatted plot:
The clipped Y-axis is no biggie, I can just live with that and adjust the plot/axis. What I am a bit perplexed about is the changed font. It appears that sometime during the matplotlib update the matplotlibrc file has changed. I can live with that and explicitly set matplotlibrc properties in my scripts, or set label text properties on a per-label basis as shown in this answer. But I have no idea how to go back to the previous formatting, i.e. what text properties to set. Any ideas?
Some useful info
Current Python version = 3.5.4
Python version I used to generate the "old plot" = 3.5.something
Current matplotlib version = 2.2.2
matplotlib version I used to generate the "old plot" = I wish I knew...
The default math font has changed in version 2.x from "Computer Modern" to "DejaVu Sans". You can change it in your script as mentioned in the documentation back to the previous version:
from matplotlib import pyplot as plt
plt.rcParams['mathtext.fontset'] = 'cm'
plt.rcParams['mathtext.rm'] = 'serif'
Sample output (without your data because your question does not contain an MCVE):
Related
PowerBI Service does not appear to be able to render Python Script visuals that I can render via PowerBI Desktop (using Python 3.6) without problems where I require the use of dates in the x-axis of Seaborn scatterplot.
What are the possible reasons for this?
The result of running my code in PowerBI Desktop (running Python 3.6) appears as
However, the visual looks like this when published via PowerBI Service (Python Version unknown)
Notice how the x-axis and the y-axis are completely incorrect and the legend is not working for the colour coding and shapes.
Special Notes:
I am publishing to a Power BI Service under Pro Subscription
When I publish basic Python Scripts like those covered in Microsoft documentation I have no problem
The underlying data set is from a CSV file ingested via Power Query and is not a Python generated data set ie data frame. The dataset seen in my script is that which is generated via the use of the Python Script visualisation feature of PowerBI.
The script I am using is as follows:
# The following code to create a dataframe and remove duplicated rows is always executed and acts as a preamble for your script:
# dataset = pandas.DataFrame(EmployeeName, Event_Date, RerunCount, AMPCPUTIME, Client_App)
from matplotlib import dates as mpl_dates
from matplotlib import pyplot as plt
import pandas as pd
import seaborn as sns
# Prepare date for matplotlib
dataset['Event_Date'] = pd.to_datetime(dataset['Event_Date']) # This line is critical to fixing the x-axis for Event Date
plt.clf() #clears plot
# plot the data
sns.scatterplot(x='Event_Date', y='AMPCPUTIME',hue='RerunCount', style='Client_App',s=120, data=dataset, palette='bright')
# after plotting the data, format the labels
# X-axis Formatting
plt.gcf().autofmt_xdate()
date_format = mpl_dates.DateFormatter('%d-%m-%y')
plt.gca().xaxis.set_major_formatter(date_format)
plt.gca().xaxis.set_major_locator(plt.MaxNLocator(15))
plt.xticks(fontsize=12, color = 'white')
plt.xlabel("Date of Execution", size=20, labelpad = 20, color = 'white')
# Y-axis Formatting
plt.yticks(fontsize=16,color = 'white')
plt.ylabel("CPU Usage", size=20, labelpad = 20, color = 'white')
plt.ticklabel_format(style='plain', axis='y') # This is necessary to prevent scientific notation occuring on y-axis
current_values = plt.gca().get_yticks()
plt.gca().set_yticklabels(['{:,.0f}'.format(x) for x in current_values])
# Set Size of Plot
plt.gcf().set_size_inches(20, 10)
# Set Legend for plot
plt.legend(
markerscale=3,
fontsize='medium',
title_fontsize='14',
loc='center left',
bbox_to_anchor=(1, 0.5),
labelspacing = 2,
ncol =1,
)
# Set background colour
plt.axes().set_facecolor("#385870")
plt.gcf().set_facecolor("#385870")
# Apply Title to Plot
#plt.title(str(dataset['EmployeeName'].unique())[2:-2], pad = 20, fontsize='18')
# Reduce padding around cell
plt.tight_layout()
plt.show()
Previously answered.
More people are experiencing issues with their column index going loco.
Take a look at this post, it should clear things up for you.
In matplotlib, one can easily use latex script to label axes, or write legends or any other text. But is there a way to use new fonts such as 'script-r' in matplotlib? In the following code, I am labelling the axes using latex fonts.
import numpy as np
import matplotlib.pyplot as plt
tmax=10
h=0.01
number_of_realizations=6
for n in range(number_of_realizations):
xpos1=0
xvel1=0
xlist=[]
tlist=[]
t=0
while t<tmax:
xlist.append(xpos1)
tlist.append(t)
xvel1=np.random.normal(loc=0.0, scale=1.0, size=None)
xpos2=xpos1+(h**0.5)*xvel1 # update position at time t
xpos1=xpos2
t=t+h
plt.plot(tlist, xlist)
plt.xlabel(r'$ t$', fontsize=50)
plt.ylabel(r'$r$', fontsize=50)
plt.title('Brownian motion', fontsize=20)
plt.show()
It produces the following figure
But I want 'script-r' in place of normal 'r'.
In latex one has to add the following lines in preamble to render 'script-r'
\DeclareFontFamily{T1}{calligra}{}
\DeclareFontShape{T1}{calligra}{m}{n}{<->s*[2.2]callig15}{}
\DeclareRobustCommand{\sr}{%
\mspace{-2mu}%
\text{\usefont{T1}{calligra}{m}{n}r\/}%
\mspace{2mu}%
}
I don't understand how to do this in matplotlib. Any help is appreciated.
Matplotlib uses it's own hand-rolled (pure Python) implementation of TeX to do all of the math text stuff, so you absolutely cannot assume that what works in standard LaTeX will work with Matplotlib. That being said, here's how you do it:
Install the calligra font so that Matplotlib can see it, then rebuild the font cache.
Lots of other threads deal with how to do this, I'm not going to go into detail, but here's some reference:
Use a font installed in a random spot on your filesystem.
How to install a new font into the Matplotlib managed font cache.
List all fonts currently known to your install of Matplotlib.
Replace one of Matplotlib's TeX font families with your font of choice.
Here's a function I wrote a while ago that reliably does that:
import matplotlib
def setMathtextFont(fontName='Helvetica', texFontFamilies=None):
texFontFamilies = ['it','rm','tt','bf','cal','sf'] if texFontFamilies is None else texFontFamilies
matplotlib.rcParams.update({'mathtext.fontset': 'custom'})
for texFontFamily in texFontFamilies:
matplotlib.rcParams.update({('mathtext.%s' % texFontFamily): fontName})
For you, a good way to use the function would be to replace the font used by \mathcal with calligra:
setMathtextFont('calligra', ['cal'])
Label your plots, for example, r'$\mathcal{foo}$', and the contents of the \math<whatever> macro should show up in the desired font.
Here's how you'd change your label-making code:
plt.ylabel(r'$\mathcal{r}$', fontsize=50)
and that should do it.
I'm having an issue when trying to save a bar plot as an svg. Specifically, when I save the bar plot as a PDF with savefig, I get the correct result. However, when I save it as an SVG, the bars do not terminate at the x-axis as they should but descend past the bottom of the figure. This problem only occurs when I use the log scale for the bar plot. Otherwise, everything is hunky dory.
Here is the code saving the plot as both an SVG and a PDF:
import matplotlib.pyplot as plt
import numpy as np
N = 10
ind = np.arange(N)
series1 = xrange(N)
series2 = [ N - s1_i for s1_i in series1 ]
fig, ax = plt.subplots()
width = 0.2
rects = [ ax.bar(ind, series1, width, color='r', log=True),
ax.bar(ind + width, series2, width, color='b', log=True) ]
plt.savefig("test.pdf")
plt.savefig("test.svg")
Here are the two sample images:
You can see there are no glaring issues with the PDF version.
The SVG version has bars that are not properly clipped, which is wrong.
Update: In response to tcaswell
I'm using Ubuntu 14.04 (kernel version is 3.16.0) with Python 2.7.6, Matplotlib version 1.3.1, numpy version 1.8.2.
I've tried viewing the SVG both with display and rsvg-view-3, and both show the same result; if I convert it to a PDF using ImageMagick's convert command line tool and open it with evince or another viewer such as acroread, the image remains flawed (not particularly surprising).
This is a known bug in librsvg (and limitation in libQtSvg which only handles a very restricted sub-set of SVG (1.2 tiny) which does not include clipping at all).
The svg will render correctly in any modern browser.
There is a much longer discussion at https://github.com/matplotlib/matplotlib/issues/4341, but the long and short of it is that the renderer is buggy.
I'm using python 2.7 on Ubuntu to draw charts from text files containing data.
My point is, when using python executables in shell, I have no problem recording plots, but if I want them shown on my screen instead I have to go through the graphic interface. If possible, I would very much like to skip that part and get a dynamic display that I can interact with (as if I were to run my script from a python shell)!!
a MWE of what i'm doing is :
MWE
import numpy as np
import matplotlib.pyplot as plt
with open('filename','r') as myfile:
DATA = np.genfromtxt(myfile,unpack=True)
fig = plt.figure()
... my plot configuration ...
plt.savefig("image_name"+'.png')
plt.close()
end of MWE
Using this script image_name.png appears in my repertory. I tried replacing the last 2 lines with plt.plot() and plt.draw() but nothing happened.
Many thanks!
Michel
(edited)
I'm currently writing a scientific paper and am generating most of the figures using matplotlib. I have a pipeline set up using a makefile that regenerates all of my plots whenever I update the data. My problem is that the figures are made up multiple panels, and some of those panels should contain vector illustrations which I've created using Adobe Illustrator. How can I automatically combine the graphs with the illustrations when I update my raw data? I could save the vector illustrations in a raster format and then display them using matplotlib's imshow function, but I want the output to be a vector to ensure the best possible print quality.
After some more extensive googling I found this old message on the matplotlib mailing list:
The thread suggests using the python library PyX, which works well for me.
I can save both the illustrator diagrams and the matplotlib plots as .eps files, and then combine them together like this:
import pyx
c = pyx.canvas.canvas()
c.insert(pyx.epsfile.epsfile(0, 0, "1.eps", align="tl"))
c.insert(pyx.epsfile.epsfile(0,0,"2.eps", align="tr"))
c.writeEPSfile("combined.eps")
I found this example in the svgutils documentation which outlines how to combine matplotlib-generated SVGs into a single plot.
Here's the example from that page:
import svgutils.transform as sg
import sys
#create new SVG figure
fig = sg.SVGFigure("16cm", "6.5cm")
# load matpotlib-generated figures
fig1 = sg.fromfile('sigmoid_fit.svg')
fig2 = sg.fromfile('anscombe.svg')
# get the plot objects
plot1 = fig1.getroot()
plot2 = fig2.getroot()
plot2.moveto(280, 0, scale=0.5)
# add text labels
txt1 = sg.TextElement(25,20, "A", size=12, weight="bold")
txt2 = sg.TextElement(305,20, "B", size=12, weight="bold")
# append plots and labels to figure
fig.append([plot1, plot2])
fig.append([txt1, txt2])
# save generated SVG files
fig.save("fig_final.svg")