jupyter notebook 中文乱码问题解决——MAC版本

Posted YZY1996068

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jupyter notebook 中文乱码问题解决——MAC版本相关的知识,希望对你有一定的参考价值。

目录

一、检测图形是否支持中文

二、解决方案

临时方案:每次画图时都带着这几段代码(....挺麻烦)

永久方案:安装simhei.tff 字体

1、下载字体下载地址:https://us-logger1.oss-cn-beijing.aliyuncs.com/SimHei.ttf

2、找到需要放置文件的地址

3、前往地址

4、修改配置文件

三、结束



前言:

Pandas绘图依赖的Matplotlib库在安装初始化时会加载一个配置文件,这个文件包含了将要用到的字体,而中文字体不在这个文件中,所以会造成在绘图过程中图形中的中文显示为方框或乱码的情况。

一、检测图形是否支持中文

import pandas as pd
pd.Series([1,2,5,4],index=['标签1','标签2','标签3','标签4']).plot()

正常显示图片如下图,非正常显示:标签2个字会显示成方块;

1.1正常显示图

二、解决方案

  • 临时方案:每次画图时都带着这几段代码(....挺麻烦)

# jupyter notebooks plt 图表配置
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (15.0, 8.0) # 固定显示大小
plt.rcParams['font.family'] = ['sans-serif'] # 显示中文问题
plt.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文问题
plt.rcParams['axes.unicode_minus'] = False # 显示负号
  • 永久方案:安装simhei.tff 字体

1、下载字体


下载地址:https://us-logger1.oss-cn-beijing.aliyuncs.com/SimHei.ttf

2、找到需要放置文件的地址

# 查找Matplotlib配置文件
import matplotlib
matplotlib.matplotlib_fname()


#地址结果
‘’‘

'/Users/wangyixing/opt/anaconda3/lib/python3.9/site-packages/matplotlib/mpl-data/matplotlibrc'

’‘’

3、前往地址

         访问以上文件,在macOS系统中,在访达(Finder)菜单中的“前往”(Go)选项卡下找到“访问目录…”(Go To Folder…),打开并输入;在Windows系统中,可直接在资源管理器的地址栏输入。可以看到fonts文件夹和matplotlibrc配置文件,fonts文件夹用于存放字体文件,将SimHei.ttf文件复制到其下的ttf文件夹里。

4、修改配置文件

        修改配置文件matplotlibrc。在修改前备份一下这个文件以便于在修改错误时还原。用纯文本编辑器(notepad++、Sublime等,不能用记事本,更不能用Word)打开。

(1)使用查找功能查到font.family: font.sans-serif,去掉前面的注释符#;

         font.family : sans-serif

(2)使用查找功能查到font.sans-serif : ,在DejaVu Sans前添加SimHei(注意:和你下载的字体文件名称大小写保持一致)

        font.sans-serif : SimHei, DejaVu Sans, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde,

(3)最后找到axes.unicode_minus,去掉注释并将值设置为False(这一步我当时没有改,也可以正常显示中文字体)

        sans-serif axes.unicode_minus : False

三、结束

最后重新运行代码,就可以正常显示中文啦!

import pandas as pd
pd.Series([1,2,5,4],index=['标签1','标签2','标签3','标签4']).plot()

原创Java小App解决Jupyter Notebook导出PDF不显示中文

0.ATTENTION!!! 

           JavaFx里是通过Java调用控制台执行的的jupyter和xelatex指令,

           这些个指令需要在本地安装Jupyter和MikTeX之后才能正常在电脑上运行

1.【问题背景】

  1.1 最近写了一个大数据的小练习,感觉那个有点用,就想导出PDF去打印

     然后问题来了:导出的PDF不显示中文!!!(可惜那一块多钱)。

     网上教程差不多就是用juypter和xlatex命令进行转换,但是这样一个一个转感觉有点麻烦,

     然后就想着写一个Java程序看看能不能自己选择文件进行PDF转换

     然后探索的过程就开始了

  1.2 一有问题当然是先问度娘了,找了一波后发现可以通过命令提示符(CMD)以命令的方式创建创建出pdf,这就很灵性了。

     虽然直接在Jupyter Notebook里可以更简单地直接导出PDF,

     但是对于希望在PDF里显示中文的同学来说,能够方便一点导出pdf文件的话,何乐而不为嘞

2.【基本过程】

    2.1 我找的解决方案挺简单的,大概分三步:a): 一条命令通过source.ipynb文件生成source.tex文件 

                         b): 用编辑器打开source.tex,在指定位置添加文本

                         c):一条命令通过source.tex文件生成一系列文件,这里面就包括了source.pdf

                         d):上面的处理方式都是通过Java实现,在控制台运行指令也是通过Java调用的(真好玩)

                         嘿嘿,听起来挺简单的,写着写着你会发现还真的挺简单的,还有一点瓜

3.【操作环境以及相关准备】

  3.1   win10+IDEA+jdk8+anaconda+Jupyter Notebook+MikTeX+Pandoc+JavaFx(SceneBuilder)

  3.2   要通过Jupyter Notebook转PDF的话要用MikTeX和Pandoc,MikTeX需要配置环境

  3.3    MikTeX下载地址:https://miktex.org/download              

        Pandoc下载地址:https://github.com/jgm/pandoc/releases/tag/2.3.1

  3.4    把MikTex添加到系统环境变量里

      


 

4.【Java控制台实现方式】

  4.1 介绍:最初就是写了一个控制台程序,然后为了能够成功导出PDF就一直在堆代码,最后就是成功导出PDF

  4.2 代码:因为一开始就是为了写功能而写代码,所以感觉把这个写死了,因为测试就是针对一个文件来写的,不过问题不大,

        后面我又写了一个JavaFx的,相关注释我都写在里面了

    

  1 import java.io.*;
  2 
  3 public class Main {
  4 
  5     private static String path = "D:\\\\JupyterNotebook";
  6     private static File sourceFile = new File("D:\\\\JupyterNotebook\\\\pandas_test.tex");
  7 
  8     public static void main(String[] args) throws IOException, InterruptedException {
  9         for (int i = 0; i < args.length; i++) {
 10             System.out.println(args[i]);
 11         }
 12         change2Tex();
 13         File bufferFile = createTexFile();  //获取创建的文件对象
 14         delay() ;                           //延时
 15         modifyTex(bufferFile);              //修该Tex文件
 16         change2PDF();                       //将Tex文件转化成PDF文件
 17     }
 18 
 19 
 20     /**
 21      * 延一个时,
 22      * java建文件比命令提示符快
 23      *
 24      * @throws InterruptedException
 25      */
 26     public static void delay() throws InterruptedException {
 27         for (int i = 0; i < 4; i++) {
 28             Thread.sleep(1000);
 29         }
 30     }
 31 
 32     /**
 33      * 通过简单的命令
 34      * 将文件转化为tex文件
 35      * 执行cmd
 36      *
 37      * jupyter nbconvert --to latex yourNotebookName.ipynb
 38      * 将文件里   \\documentclass[11pt]{article}后面加上下面这三行
 39      * \\\\usepackage{fontspec, xunicode, xltxtra}
 40      * \\\\setmainfont{Microsoft YaHei}
 41      * 将latex转化为pdf
 42      * xelatex yourNotebookName.tex
 43      */
 44     public static void change2Tex() throws IOException {
 45 
 46         Runtime runtime = Runtime.getRuntime();
 47         String cmd = "cmd /k start  jupyter nbconvert --to latex " + path + "\\\\pandas_test.ipynb";  //cmd指令,cmd /k start + 指令,运行五玩了指令就关闭cmd
 48         System.out.println(cmd);
 49         System.out.println(path);
 50         runtime.exec(cmd);
 51     }
 52 
 53     /**
 54      * 将tex文件转化成pdf文件
 55      *
 56      * @throws IOException
 57      */
 58     public static void change2PDF() throws IOException {
 59         Runtime runtime = Runtime.getRuntime();
 60         String cmd = "cmd /k start xelatex afterInsertText.tex";
 61         runtime.exec(cmd, null, new File(path));//注意这里:exec里有三个参数,这个方法可以指定在path文件夹打开cmd,然后运行cmd指令
 62     }
 63 
 64     /**
 65      * 创建Tex文件
 66      *
 67      * @return
 68      * @throws IOException
 69      */
 70     public static File createTexFile() throws IOException {
 71 
 72         File tempFile = new File("D:\\\\JupyterNotebook");        //判断这个文件夹在不在
 73         if (!tempFile.exists()) {
 74             tempFile.mkdir();
 75         }
 76 
 77         File bufferTopTex = new File("D:\\\\JupyterNotebook", "afterInsertText.tex");     //判断这个文件在不在
 78         if (!bufferTopTex.exists()) {           //不在的话创建文件,
 79             bufferTopTex.createNewFile();
 80         }
 81         //在后面会把源.tex文件要修改的位置前面的数据写到下面这个文件(虽然下面是个对象,意思应该能懂)里面,
 82         // 然后接着在后面添加文本,最后把源tex剩下的数据写到这个文件里
 83         return bufferTopTex;
 84     }
 85 
 86     /**
 87      * 文件读写,在文件后面添加需要添加的指令
 88      *
 89      * @throws IOException
 90      */
 91     public static void modifyTex(File file) throws IOException {
 92         
 93         RandomAccessFile topTex = new RandomAccessFile(file, "rw");     //在本地创建的afterInsertText.tex文件
 94 
 95         RandomAccessFile raf = new RandomAccessFile(sourceFile, "rw");  //获取源.tex文件
 96 
 97         String line;
 98         
 99         //在下面是对readLine()取到的数据进行转码,这是一个解决乱码的好方式
100         //注意在下面每用一次readLine(),那个指向行号的指针就会向下移动一次,和ResultSet里的rs.next()有点像
101         while ((line = new String(raf.readLine().getBytes("ISO-8859-1"), "utf-8")) != null) {
102             topTex.write(("\\n" + line).getBytes());
103             if (line.equals("\\\\documentclass[11pt]{article}")) {
104                 topTex.write((" \\n\\\\usepackage{fontspec, xunicode, xltxtra}").getBytes());
105                 topTex.write(("\\n\\\\setmainfont{Microsoft YaHei}").getBytes());
106                 topTex.write(("\\n\\\\usepackage{ctex} ").getBytes());
107                 break;
108             }
109         }
110 
111         while (true) {
112             final String temp;
113             if ((temp = raf.readLine()) == null) {
114                 break;
115             } else {
116                 line = new String(temp.getBytes("ISO-8859-1"), "utf-8");
117                 topTex.write(("\\n" + line).getBytes());
118             }
119         }
120     }
121 }
Main.java

 

  4.3 运行结果:emmmmmmm,这个运行完了就自己关掉了,不好截图,看看其他的吧

    

    4.3.1 只有一个.ipynb文件:

        

        然后运行一下程序:

          先是Java程序生成的afterInsertText.tex文件

        

 

          然后接着运行到结束就会生成这些文件,可以看到pdf自动生成了

            

             最后看一眼有没有中文:

          

 

-----------------可以看出,上面的pdf是有中文的,成功-----------------

Tip_1:在这里给出要用到的cmd命令:

  1.jupyter nbconvert --to latex yourNotebookName.ipynb


  2.将文件里 \\documentclass[11pt]{article}后面加上下面这三行
                  \\usepackage{fontspec, xunicode, xltxtra}
            \\setmainfont{Microsoft YaHei}

              \\usepackage{ctex}
  3.latex转化为pdf: xelatex yourNotebookName.tex

Tip_2:

  在Java里输出反斜杠要用两个,英文点号  ......要用  \\\\.


 

5.【JavaFx实现方式】

  5.1 用的是IDEA开发的,所以开发JavaFx程序挺简单的,只要新建一个JavaFx程序就好了,然后就是下载Scenebuilder了,下载完了之后还要配置一下options.xml和other.xml

     路径是这个:other.xml也在这个路径下

     配置:other.xml

        

     配置:options.xml,在45行里的value里面加上E:/SceneBuilder/SceneBuilder.exe;你的SceeBuilder程序的路径

        

    重启IDEA,右键FXML文件可以看到有open in scenebuilder那个选项点击之后不会报错了

 

  5.2 程序总体来说还行,但是打包成jar包之后就会出bug,点击Generate不会正常显示提示框,可是在IDEA里可以正常显示提示框,不知道为啥,所以就没处理这个bug,有兴趣的可以改一改咯

  5.3 Java调用控制台执行的的jupyter和xelatex指令,这些个指令需要在本地安装Jupyter和MikTeX之后才能正常在电脑上运行

  5.4 程序基本骨架

          

 


 

  5.5 程序代码:

    5.5.1 包含main方法的类

 1 package sample;
 2 
 3 import javafx.application.Application;
 4 import javafx.fxml.FXMLLoader;
 5 import javafx.scene.Parent;
 6 import javafx.scene.Scene;
 7 import javafx.stage.Stage;
 8 
 9 public class Main extends Application {
10 
11     static Stage mainStage = null ;
12 
13     public static Stage getMainStage(){
14         return mainStage;
15     }
16     @Override
17     public void start(Stage primaryStage) throws Exception{
18         mainStage = primaryStage;
19         Parent root = FXMLLoader.load(getClass().getResource("view/sample.fxml"));
20         primaryStage.setTitle("ChangeTex2PDF");
21         primaryStage.setScene(new Scene(root));
22         primaryStage.show();
23     }
24 
25 
26     public static void main(String[] args) {
27         launch(args);
28     }
29 }
Main.java

      5.5.2  主页中的控件的控制器

package sample.controller;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import sample.Main;
import sample.Service;

import java.io.File;
import java.io.IOException;

public class Controller {

    InputFileDialogController InputFileDialogController = new InputFileDialogController();

    private String srcFilePath;

    @FXML
    private Label filePath_Label;

    @FXML
    private void importFile() {
        //创建选择文件stage
        Stage chooseFileStage = new Stage();

        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("选择文件");

        //文件过滤
        fileChooser.getExtensionFilters().addAll(
                new FileChooser.ExtensionFilter("ipynb file", "*.ipynb")
        );

        //以对话框的形式显示选择文件
        File file = fileChooser.showOpenDialog(chooseFileStage);
        if (file != null) {
            String absolutePath = file.getAbsolutePath();
            srcFilePath = absolutePath;
            filePath_Label.setText(absolutePath);
            System.out.println("劳资要读文件啦");
        }
    }

    @FXML
    /**
     * 生成按钮点击事件处理
     * srcFilePath:文件的绝对路径
     * fullName:名称+后缀
     * filePkgPath:目标文件的包路径,
     *      比如:C:\\test\\notebook\\test.ipynb。
     *      这里filePkgPath就是C:\\test\\notebook
     * path_arr数组:对文件绝对路径的拆分,按反斜杠 \\ 进行拆分,在java里用\\\\
     * fullName_arr数组:对fullName按英文句号进行拆分,在java里用"\\\\."表示
     * texFileName:构造一个tex文件名,给后面转化pdf时用
     *
     */
    public void generatePDF() throws IOException, InterruptedException {
        if (srcFilePath != null) {                                               //在选择了文件的情况下
            String[] path_arr = srcFilePath.split("\\\\\\\\");
            String fullName = path_arr[path_arr.length - 1];

            StringBuffer filePkgPath = getStringBuffer(path_arr);
            String[] fullName_arr = fullName.split("\\\\.");

            Service.change2Tex(filePkgPath.toString(), fullName_arr[0]);

            File bufferFile = Service.createTexFile(filePkgPath.toString());

            Service.delay();

            String texFileName = fullName_arr[0] + ".tex";
            texFileName = filePkgPath + "\\\\" + texFileName;
            Service.modifyTex(bufferFile, texFileName);
            Service.change2PDF(filePkgPath.toString());
        } else {
            InputFileDialogController.loadDialog().show();            //显示提示框,请先选择所需文件
            Main.getMainStage().close();
        }
    }

    /**
     * 获取目标文件的包路径
     *
     * @param path_arr
     * @return
     */
    private StringBuffer getStringBuffer(String[] path_arr) {
        StringBuffer filePkgPath = new StringBuffer();
        for (int i = 0; i < path_arr.length - 1; i++) {
            if (i < path_arr.length - 2) {                  //除开绝对路径后面的(文件名+后缀)那一项
                filePkgPath.append(path_arr[i]).append("\\\\");
            } else {
                filePkgPath.append(path_arr[i]);
            }
        }
        return filePkgPath;
    }

    /**
     * 退出软件
     *
     * @throws IOException
     */
    @FXML
    public void exit() throws IOException {
        Main.getMainStage().close();
    }
}
Controller.java

         5.5.3  调用控制台,执行jupyter xlatex指令,以及对文件路径进行处理的方法

package sample;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Service {
    /**
     * 延一个时,
     * 娘欸java建文件比命令提示符快
     *
     * @throws InterruptedException
     */
    public static void delay() throws InterruptedException {
        for (int i = 0; i < 4; i++) {
            Thread.sleep(1000);
        }
    }

    /**
     * 通过简单的命令
     * 将文件转化为tex文件
     * *   执行cmd
     * *   jupyter nbconvert --to latex yourNotebookName.ipynb
     *
     * 将文件里   \\documentclass[11pt]{article}后面加上下面这两行
     * *       \\\\usepackage{fontspec, xunicode, xltxtra}
     * *       \\\\setmainfont{Microsoft YaHei}
     *
     * 将latex转化为pdf
     * *        xelatex yourNotebookName.tex
     */
    public static void change2Tex(String filePkgPath, String fileName) throws IOException {

        Runtime runtime = Runtime.getRuntime();
        String cmd = "cmd /k start  jupyter nbconvert --to latex " + filePkgPath + "\\\\" + fileName + ".ipynb";
        runtime.exec(cmd);
    }

    /*************************************这里可以改,改成用户自定义名称*************
     * 将tex文件转化成pdf文件
     *
     * @throws IOException
     */
    public static void change2PDF(String filePkgPath) throws IOException {
        Runtime runtime = Runtime.getRuntime();
        String cmd = "cmd /k start xelatex Result.tex";
        runtime.exec(cmd, null, new File(filePkgPath));
    }

    /**
     * 创建Tex文件
     *
     * @return  获取生成的tex文件
     * @throws IOException
     */
    public static File createTexFile(String filePkgPath) throws IOException {

        File tempFile = new File(filePkgPath);
        if (!tempFile.exists()) {
            tempFile.mkdir();
        }

        File bufferTopTex = new File(filePkgPath, "Result.tex");
        if (!bufferTopTex.exists()) {
            bufferTopTex.createNewFile();
        }

        return bufferTopTex;
    }

    /**
     * 文件读写,在文件后面添加需要添加的指令
     *
     * @throws IOException
     */
    public static void modifyTex(File file, String sourceFile) throws IOException {

        RandomAccessFile topTex = new RandomAccessFile(file, "rw");

        RandomAccessFile raf = new RandomAccessFile(sourceFile, "rw");

        String line;
        while ((line = new String(raf.readLine().getBytes("ISO-8859-1"), "utf-8")) != null) {
            topTex.write(("\\n" + line).getBytes());
            if (line.equals("\\\\documentclass[11pt]{article}")) {
                topTex.write((" \\n\\\\usepackage{fontspec, xunicode, xltxtra}").getBytes());
                topTex.write(("\\n\\\\setmainfont{Microsoft YaHei}").getBytes());
                topTex.write(("\\n\\\\usepackage{ctex} ").getBytes());
                break;
            }
        }

        //接着插入后半部分
        while (true) {
            final String temp;
            if ((temp = raf.readLine()) == null) {
                break;
            } else {
                line = new String(temp.getBytes("ISO-8859-1"), "utf-8");
                topTex.write(("\\n" + line).getBytes());
            }
        }
    }

    //判断是否成功生成,成功生成对应文件弹出成功框

}
Service.java

         5.5.4   控制弹出框动作的控制器

package sample.controller;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import sample.Main;


import java.io.IOException;

public class InputFileDialogController {

    static Stage stage = new Stage();

    public Stage loadDialog() throws IOException {
        Scene dialogScene = new Scene(FXMLLoader.load(getClass().getResource("../view/inputFileDialog.fxml")));
        stage.setScene(dialogScene);
        return stage;
    }

    @FXML
    public void closeDialog(){
        stage.close();
        Main.getMainStage().show();
    }
}
InputFileDialogController.java

         5.5.5   主页的视图

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 <?import javafx.scene.control.Button?>
 4 <?import javafx.scene.control.Label?>
 5 <?import javafx.scene.layout.AnchorPane?>
 6 <?import javafx.scene.layout.ColumnConstraints?>
 7 <?import javafx.scene.layout.GridPane?>
 8 <?import javafx.scene.layout.HBox?>
 9 <?import javafx.scene.layout.RowConstraints?>
10 <?import javafx.scene.text.Font?>
11 
12 <AnchorPane maxHeight="354.0" maxWidth="400.0" minHeight="295.0" minWidth="400.0" prefHeight="338.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.controller.Controller">
13    <children>
14       <GridPane prefHeight="343.0" prefWidth="400.0" style="-fx-background-color: white;" stylesheets="@giveMeCss.css">
15         <columnConstraints>
16           <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /><

以上是关于jupyter notebook 中文乱码问题解决——MAC版本的主要内容,如果未能解决你的问题,请参考以下文章

jupyter-notebook 中matplotlib不支持中文的问题(Linux)

如何解决 jupyter notebook 中的 pandas 问题?

windosws下安装jupyter notebook启动后空白问题的解决方法

关于Jupyter Notebook默认起始目录设置无效的解决方法

jupyter notebook闪退,怎么解决

原创Java小App解决Jupyter Notebook导出PDF不显示中文