Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plotting with Serif Font, scientific notation #2042

Closed
isentropic opened this issue May 30, 2019 · 13 comments
Closed

Plotting with Serif Font, scientific notation #2042

isentropic opened this issue May 30, 2019 · 13 comments

Comments

@isentropic
Copy link
Member

Following 897, I attempted to make the plot look different,

using Plots
pyplot()
upscale = 1 #8x upscaling in resolution
fntsm = Plots.font("Latin Modern Math", 10.0*upscale)
fntlg = Plots.font("Latin Modern Math", 14.0*upscale)
default(titlefont=fntlg, guidefont=fntlg, tickfont=fntsm, legendfont=fntsm)
default(size=(800*upscale,600*upscale)) #Plot canvas size
default(framestyle=:box)
default(dpi=300) #Only for PyPlot - presently broken

The problem is that backends have trouble rendering powers of 10:
image

PyPlot handles this as follows (example):
image

Are there any additional parameters that require tuning?

@isentropic
Copy link
Member Author

Additionally,
pyplotjs() handles this as follows:
image

gr() does not change the fonts at all, and makes the picture huge (this was mentioned in previous issues)

@isentropic isentropic changed the title Plotting with Sans-Serif Font, powers of 10 Plotting with Sans-Serif Font, scientific notation May 30, 2019
@ma-laforge
Copy link
Contributor

Hi @isentropic,

I just want to start off by explaining there was a slight bug with the code snippet you used above. You should replace the fntsm & fntlg expressions with the following:

fntsm = Plots.font("sans-serif", pointsize=round(10.0*upscale))
fntlg = Plots.font("sans-serif", pointsize=round(14.0*upscale))

(see comments by nathancunn in #897 for explanations)

Also, I assume you generated the above plots with code similar to the following:

x = 0:1e-6:6e-6
y1 = 0 .* x
y2 = y1 .+ 1

plot(x, [y1, y2])

If not, please provide such code for clarity.

@ma-laforge
Copy link
Contributor

As for the trouble rendering powers of 10:

Background

It would appear that most backends display the exponential portion of the powers of 10 by using the unicode characters for +, -, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. These are special characters that are already positionned in the superscript position... so that plotting backends just have to build a unicode string & render it using the drawing backend (ex: Cairo).

You can read more about it here:
https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts#Superscripts_and_subscripts_block

(Note that the tables preceed the exponent with an "X" just so you can see that the numbers are indeed superscripts (or subscripts).

Alternative Implementation

Plotting backends could scale down the font size, and render the exponent part at a vertically offset location - but most just don't do that (InspectDR does it for the tick labels on log plots, though).

Problem

The problem is that the font you selected does not actually provide "drawings" for the "exponent" unicode characters.

Solution

The easiest solution right now is to select a font that "renders/implements" the exponent numbers.

A quick way to check this would be to copy/paste the unicode "exponents" into a text editor (like LibreOffice), and see whether something shows up when select a desired font.

You should be able to copy/paste the following unicode characters:

⁻⁰¹²³⁴⁵⁶⁷⁸⁹

Of course you will only see the above exponents if your browser font currently "implements" their drawings.

@daschw
Copy link
Member

daschw commented Jul 19, 2019

At least on GR and PyPlot, instead of upscale trick you can also just use dpi since #1561.

plot(cumsum(1:10), xlabel = "x label", ylabel = "x label", title = "title", dpi = 50)

dpi_50

plot(cumsum(1:10), xlabel = "x label", ylabel = "x label", title = "title", dpi = 300)

dpi_300
(This image is actually bigger - it's scaled by github markdown here)

@isentropic
Copy link
Member Author

As for the trouble rendering powers of 10:

Background

It would appear that most backends display the exponential portion of the powers of 10 by using the unicode characters for +, -, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. These are special characters that are already positionned in the superscript position... so that plotting backends just have to build a unicode string & render it using the drawing backend (ex: Cairo).

You can read more about it here:
https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts#Superscripts_and_subscripts_block

(Note that the tables preceed the exponent with an "X" just so you can see that the numbers are indeed superscripts (or subscripts).

Alternative Implementation

Plotting backends could scale down the font size, and render the exponent part at a vertically offset location - but most just don't do that (InspectDR does it for the tick labels on log plots, though).

Problem

The problem is that the font you selected does not actually provide "drawings" for the "exponent" unicode characters.

Solution

The easiest solution right now is to select a font that "renders/implements" the exponent numbers.

A quick way to check this would be to copy/paste the unicode "exponents" into a text editor (like LibreOffice), and see whether something shows up when select a desired font.

You should be able to copy/paste the following unicode characters:

⁻⁰¹²³⁴⁵⁶⁷⁸⁹

Of course you will only see the above exponents if your browser font currently "implements" their drawings.

The problem is that the same config works perfectly fine if done in python via pyplot, or PyPlot package in Julia. PyPlot and python's pyplot in the absence of said fonts would then:

image

I think you merely reformulated the problem in more technical terms, it is not a solution. The package should workaround if ligatures are not available like pyplot does natively.

@ma-laforge
Copy link
Contributor

@daschw: That's good to know about DPI. The behaviour seems to make sense compared to what we had in 2017.

But I don't think this solves the problem: It seems like the issue is that exponent parts (after the 10) don't show up when @isentropic selects the "Latin Modern Math" font. And that's simply because this font does not actually include "drawings" for the exponent "characters".

@ma-laforge
Copy link
Contributor

@isentropic:
I don't really understand why you say pyplot is doing things right in the above plot.

Here, Pyplot is using "E" notation (instead of the more natural x10⁸) on the y-axis of the plot above, and decided to display many decimal places (again instead of the easier to read x10⁻³ notation) on the x-axis.

If you change the range on the x-axis to smaller values (ex: x10⁻¹²), you will likely "force" Pyplot to use scientific notation, and get similar results.

Again, as far as I can see the problem is that the "Latin Modern Math" font is lacking the ability to "draw" exponential "characters"

I'm not saying this just to be technicial: I'm simply hilighting the root of the problem.

I don't think it would be reasonable for a plotting backend to somehow detect that the selected font "did not implement" the exponent portions, and find a way to work around this issue. At best, the user should be aware that her font was missing the exponent portion, and maybe then select a different rendering method for the tick labels.

NOTE: InspectDR does allow one to change the notation used to display tick labels through the capabilities of NumericIO: You can choose:

  • Engineering notation (only display exponents that are powers 3)
  • Scientific notation (Allow exponents that are NOT powers of 3)
  • SI notation (..., m, μ, n, ...)
  • You can also choose to display either "E", or "x10" for the base before the exponent.

That way, you could circumvent the font limitations, if you so choose.

@isentropic
Copy link
Member Author

I just expected to see Plots.jl's pyplot backend provide the same workaroundish "1e-9" like values which are good enough for reproducing the original Pyplot behavior. I just do not understand why Plots.jl does not behave the same way. I assumed it to work the same

@isentropic
Copy link
Member Author

isentropic commented Jul 30, 2019

I've been looking at alternatives, but still could not solve my issue.

Does anyone know any Sans-Serif fonts that would have the said ligatures 10^(-1; -2; -3 ...) (scientific notation)?
The reason behind this choice

fntsm = Plots.font("Latin Modern Math", 10.0*upscale)   # MathJax_Math does not work too
fntlg = Plots.font("Latin Modern Math", 14.0*upscale)

was that I believe that this font supports exponents and various math. symbols

@ma-laforge
Copy link
Contributor

I suppose it depends both on the operating system (Linux, Windows, ...) and the drawing package.

For plotting packages that use Cairo, you can actually select:
"sans"

The font "sans" is supposed to be the default sans-serif font.

VERY IMPORTANT NOTE ON CAIRO

  • "sans" works perfectly well on my Linux system.
  • "sans" is missing the drawings for the exponent values on my Windows system.

Alternative on Windows

On my windows 10 machine, I have to resort to selecting "Calibri" (which appears to be bundled with Windows 10).

I don't know why Cairo cannot pick a "fully populated" sans-serif font in WIndows 10 when you request the "sans" fontname.

@isentropic
Copy link
Member Author

isentropic commented Jul 31, 2019

I have tested this issue for plotlyjs gr and pyplot backends in a jupyter notebook again (I'm running Ubuntu)

plotlyjs()
upscale = 1
my_font = "Latin Modern Math"
fntsm = Plots.font(my_font)

fntlg = Plots.font(my_font)
default(titlefont=fntlg, guidefont=fntlg, tickfont=fntsm, legendfont=fntsm, tickfontfamily=fntsm, xtickfontfamily=fntsm)
default(size=(800*upscale,600*upscale)) #Plot canvas size
default(framestyle=:box)
default(dpi=100) 
# Plots.fontfamily = myfont 
plot([sin,cos], 0, .000002*pi)

image

pyplot()
upscale = 1
my_font = "Latin Modern Math"
fntsm = Plots.font(my_font)

fntlg = Plots.font(my_font)
default(titlefont=fntlg, guidefont=fntlg, tickfont=fntsm, legendfont=fntsm, tickfontfamily=fntsm, xtickfontfamily=fntsm)
default(size=(800*upscale,600*upscale)) #Plot canvas size
default(framestyle=:box)
default(dpi=100) 
# Plots.fontfamily = myfont 
plot([sin,cos], 0, .000002*pi)

image

gr()
upscale = 1
my_font = "Latin Modern Math"
fntsm = Plots.font(my_font)

fntlg = Plots.font(my_font)
default(titlefont=fntlg, guidefont=fntlg, tickfont=fntsm, legendfont=fntsm, tickfontfamily=fntsm, xtickfontfamily=fntsm)
default(size=(800*upscale,600*upscale)) #Plot canvas size
default(framestyle=:box)
default(dpi=100) 
# Plots.fontfamily = myfont 
plot([sin,cos], 0, .000002*pi)

image

I tested it with different fonts, results are the same: Exponents do not render properly. (Even tried powerline monospace fonts that have all the ligatures and more)

I think that is something with the way Plots.jl handles the scientific notation, native Pyplot or Plotly do not do this. Let me know if you'd need more tests to figure out why this happens, I'd gladly attempt to fix this, but I do not know how. I have checked all the Attributes to see if there is "Exponent font" or smth like that, I could not find any other font attributes that I could have changed.

The issue remains with Dejavu Serif, MathJax_Main, STIX, and these fonts provide the exponents.

@ma-laforge
Copy link
Contributor

I'm actually not convinced we are talking about the same thing, but here is what I myself get using the pyplot() variant of the code you submitted above, on Ubuntu 18.04:

When my_font = "Latin Modern Math"

image

Yes, I see clearly that the exponent values are missing.

When my_font = "sans"

image

As you can see by the exponent values circled in red: They are no longer missing when you use a font that includes drawings for the exponent values.

My other confusion

  • Your issue is called "Plotting with Sans-Serif Font, scientific notation"... But the "Latin Modern Math" font you keep trying to use is actually a font that is with Serif (it includes those little pointy strokes that extend beyond where the letters would usually end.
  • Also, you use the word "ligature" which apparently means those special so-called "graphemes" where two letters are merged into one... But none of what I can see is you trying to draw any of these "graphemes" (ex: how "oe" can be smashed into a single grapheme, or "et" gets smashed into the "&" symbol).

In short, I am just a bit confused as to what you are trying to do exactly. Your comments are somewhat unclear & go against what I can decipher from your examples / illustrations.

PS the "oe" "ligature" is œ - I added it here just in case your web browser font can't render it.

@isentropic
Copy link
Member Author

Please pardon my ignorance/incompetence, here and everywhere I mean Serif (pointy strokes) font.

My argument is that the fonts I've used (Latin Modern Math for example) support superscripts, subscripts, ligatures, and Unicode characters. I've used multiple fonts to underline the fact that these fonts indeed support super/subscripts (sci-notation).

All in all, I want to have nice looking fonts (Latin Modern Math for example) display the scientific notation in some way. PyPlot natively handles this by adding an offset like factor (like in this pic)
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants